From efa084b960c983fec38476afb7cbbd920a358a6f Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Tue, 14 Mar 2023 09:37:14 +0300 Subject: [PATCH 1/5] Code cleanup --- .editorconfig | 19 +- Build.ps1 | 4 +- Directory.Build.props | 16 + Directory.Build.targets | 7 + sample/ConsoleDemo/ConsoleDemo.csproj | 4 +- sample/ConsoleDemo/Program.cs | 51 +- sample/SyncWritesDemo/Program.cs | 84 ++- sample/SyncWritesDemo/SyncWritesDemo.csproj | 4 +- serilog-sinks-console.sln | 9 +- .../ConsoleLoggerConfigurationExtensions.cs | 156 +++-- .../Properties/AssemblyInfo.cs | 1 - .../Serilog.Sinks.Console.csproj | 15 +- .../Sinks/SystemConsole/ConsoleSink.cs | 101 ++- .../Formatting/ThemedDisplayValueFormatter.cs | 271 ++++---- .../Formatting/ThemedJsonValueFormatter.cs | 331 +++++---- .../Formatting/ThemedValueFormatter.cs | 37 +- .../Formatting/ThemedValueFormatterState.cs | 15 +- .../Output/EventPropertyTokenRenderer.cs | 71 +- .../Output/ExceptionTokenRenderer.cs | 48 +- .../SystemConsole/Output/LevelOutputFormat.cs | 17 +- .../Output/LevelTokenRenderer.cs | 59 +- .../MessageTemplateOutputTokenRenderer.cs | 71 +- .../Output/NewLineTokenRenderer.cs | 31 +- .../Output/OutputTemplateRenderer.cs | 106 ++- .../Output/OutputTemplateTokenRenderer.cs | 10 +- .../Output/PropertiesTokenRenderer.cs | 98 ++- .../SystemConsole/Output/TextTokenRenderer.cs | 32 +- .../Output/TimestampTokenRenderer.cs | 95 ++- .../SystemConsole/Platform/WindowsConsole.cs | 46 +- .../Rendering/AlignmentExtensions.cs | 11 +- .../Sinks/SystemConsole/Rendering/Casing.cs | 40 +- .../Sinks/SystemConsole/Rendering/Padding.cs | 66 +- .../ThemedMessageTemplateRenderer.cs | 172 +++-- .../SystemConsole/Themes/AnsiConsoleTheme.cs | 102 ++- .../SystemConsole/Themes/AnsiConsoleThemes.cs | 167 +++-- .../Themes/AnsiEscapeSequence.cs | 45 +- .../SystemConsole/Themes/ConsoleTheme.cs | 79 +-- .../SystemConsole/Themes/ConsoleThemeStyle.cs | 188 +++-- .../SystemConsole/Themes/EmptyConsoleTheme.cs | 17 +- .../Sinks/SystemConsole/Themes/StyleReset.cs | 28 +- .../Themes/SystemConsoleTheme.cs | 100 ++- .../Themes/SystemConsoleThemeStyle.cs | 25 +- .../Themes/SystemConsoleThemes.cs | 128 ++-- .../Approval/ApiApprovalTests.cs | 29 +- ...nsoleLoggerConfigurationExtensionsTests.cs | 82 ++- .../ThemedDisplayValueFormatterTests.cs | 28 +- .../ThemedJsonValueFormatterTests.cs | 210 +++--- .../Output/OutputTemplateRendererTests.cs | 654 +++++++++--------- .../ThemedMessageTemplateRendererTests.cs | 388 +++++------ .../Serilog.Sinks.Console.Tests.csproj | 15 +- .../Support/DelegatingSink.cs | 46 +- .../Support/TracingConsoleTheme.cs | 32 +- 52 files changed, 2181 insertions(+), 2280 deletions(-) create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets diff --git a/.editorconfig b/.editorconfig index f76c08a..a853ae9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,22 @@ -root=true +root = true [*] +trim_trailing_whitespace = true +insert_final_newline = true indent_style = space indent_size = 4 +charset = utf-8 + +[*.{csproj,json,config,yml,props}] +indent_size = 2 + +[*.sh] +end_of_line = lf + +[*.{cmd, bat}] +end_of_line = crlf + +# C# formatting settings - Namespace options +csharp_style_namespace_declarations = file_scoped:suggestion + +csharp_style_prefer_switch_expression = true:suggestion diff --git a/Build.ps1 b/Build.ps1 index b0ac93a..394f6fb 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -19,7 +19,7 @@ $commitHash = $(git rev-parse --short HEAD) $buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""] Write-Output "build: Package version suffix is $suffix" -Write-Output "build: Build version suffix is $buildSuffix" +Write-Output "build: Build version suffix is $buildSuffix" foreach ($src in Get-ChildItem src/*) { Push-Location $src @@ -32,7 +32,7 @@ foreach ($src in Get-ChildItem src/*) { } else { & dotnet pack -c Release --include-source -o ..\..\artifacts --no-build } - if($LASTEXITCODE -ne 0) { exit 1 } + if($LASTEXITCODE -ne 0) { exit 1 } Pop-Location } diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..d54992d --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,16 @@ + + + latest + True + true + true + $(MSBuildThisFileDirectory)assets/Serilog.snk + enable + enable + + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..6132714 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/sample/ConsoleDemo/ConsoleDemo.csproj b/sample/ConsoleDemo/ConsoleDemo.csproj index 81b1a1f..82b5926 100644 --- a/sample/ConsoleDemo/ConsoleDemo.csproj +++ b/sample/ConsoleDemo/ConsoleDemo.csproj @@ -1,8 +1,8 @@ - + Exe - netcoreapp2.1;netcoreapp2.2;netcoreapp3.0;netcoreapp3.1;net452;net462;net472;net48;net5.0 + net7.0 diff --git a/sample/ConsoleDemo/Program.cs b/sample/ConsoleDemo/Program.cs index 73d50d8..1a929cf 100644 --- a/sample/ConsoleDemo/Program.cs +++ b/sample/ConsoleDemo/Program.cs @@ -1,40 +1,37 @@ -using Serilog; +using Serilog; using Serilog.Sinks.SystemConsole.Themes; -using System; -using System.Threading; -namespace ConsoleDemo +namespace ConsoleDemo; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Verbose() - .WriteTo.Console(theme: AnsiConsoleTheme.Code) - .CreateLogger(); - - try - { - Log.Debug("Getting started"); + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Console(theme: AnsiConsoleTheme.Code) + .CreateLogger(); - Log.Information("Hello {Name} from thread {ThreadId}", Environment.GetEnvironmentVariable("USERNAME"), Thread.CurrentThread.ManagedThreadId); + try + { + Log.Debug("Getting started"); - Log.Warning("No coins remain at position {@Position}", new { Lat = 25, Long = 134 }); + Log.Information("Hello {Name} from thread {ThreadId}", Environment.GetEnvironmentVariable("USERNAME"), Thread.CurrentThread.ManagedThreadId); - Fail(); - } - catch (Exception e) - { - Log.Error(e, "Something went wrong"); - } + Log.Warning("No coins remain at position {@Position}", new { Lat = 25, Long = 134 }); - Log.CloseAndFlush(); + Fail(); } - - static void Fail() + catch (Exception e) { - throw new DivideByZeroException(); + Log.Error(e, "Something went wrong"); } + + Log.CloseAndFlush(); + } + + static void Fail() + { + throw new DivideByZeroException(); } } diff --git a/sample/SyncWritesDemo/Program.cs b/sample/SyncWritesDemo/Program.cs index 5120393..d7c6d6a 100644 --- a/sample/SyncWritesDemo/Program.cs +++ b/sample/SyncWritesDemo/Program.cs @@ -1,57 +1,53 @@ -using Serilog; +using Serilog; using Serilog.Sinks.SystemConsole.Themes; -using System; -using System.Threading; -using System.Threading.Tasks; -namespace SyncWritesDemo +namespace SyncWritesDemo; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - Console.WriteLine("A sample of how to sync writes to the console sink."); + Console.WriteLine("A sample of how to sync writes to the console sink."); - if (args != null && args.Length == 1) + if (args != null && args.Length == 1) + { + switch (args[0]) { - switch (args[0]) - { - case "--sync-root-default": - SystemConsoleSyncTest(syncRootForLogger1: null, syncRootForLogger2: null); - return; - case "--sync-root-separate": - SystemConsoleSyncTest(syncRootForLogger1: new object(), syncRootForLogger2: new object()); - return; - case "--sync-root-same": - var sameSyncRoot = new object(); - SystemConsoleSyncTest(syncRootForLogger1: sameSyncRoot, syncRootForLogger2: sameSyncRoot); - return; - } + case "--sync-root-default": + SystemConsoleSyncTest(syncRootForLogger1: null, syncRootForLogger2: null); + return; + case "--sync-root-separate": + SystemConsoleSyncTest(syncRootForLogger1: new object(), syncRootForLogger2: new object()); + return; + case "--sync-root-same": + var sameSyncRoot = new object(); + SystemConsoleSyncTest(syncRootForLogger1: sameSyncRoot, syncRootForLogger2: sameSyncRoot); + return; } - - Console.WriteLine("Expecting one of the following arguments:{0}--sync-root-default{0}--sync-root-separate{0}--sync-root-same", Environment.NewLine); } - static void SystemConsoleSyncTest(object syncRootForLogger1, object syncRootForLogger2) - { - var logger1 = new LoggerConfiguration() - .MinimumLevel.Verbose() - .Enrich.WithProperty("Logger", "logger1") - .WriteTo.Console(theme: SystemConsoleTheme.Literate, syncRoot: syncRootForLogger1) - .CreateLogger(); + Console.WriteLine("Expecting one of the following arguments:{0}--sync-root-default{0}--sync-root-separate{0}--sync-root-same", Environment.NewLine); + } - var logger2 = new LoggerConfiguration() - .MinimumLevel.Verbose() - .Enrich.WithProperty("Logger", "logger2") - .WriteTo.Console(theme: SystemConsoleTheme.Literate, syncRoot: syncRootForLogger2) - .CreateLogger(); + static void SystemConsoleSyncTest(object? syncRootForLogger1, object? syncRootForLogger2) + { + var logger1 = new LoggerConfiguration() + .MinimumLevel.Verbose() + .Enrich.WithProperty("Logger", "logger1") + .WriteTo.Console(theme: SystemConsoleTheme.Literate, syncRoot: syncRootForLogger1) + .CreateLogger(); - var options = new ParallelOptions { MaxDegreeOfParallelism = 8 }; - Parallel.For(0, 1000, options, (i, loopState) => - { - var logger = (i % 2 == 0) ? logger1 : logger2; - logger.Information("Event {Iteration} generated by {ThreadId}", i, Thread.CurrentThread.ManagedThreadId); - }); - } + var logger2 = new LoggerConfiguration() + .MinimumLevel.Verbose() + .Enrich.WithProperty("Logger", "logger2") + .WriteTo.Console(theme: SystemConsoleTheme.Literate, syncRoot: syncRootForLogger2) + .CreateLogger(); + + var options = new ParallelOptions { MaxDegreeOfParallelism = 8 }; + Parallel.For(0, 1000, options, (i, loopState) => + { + var logger = (i % 2 == 0) ? logger1 : logger2; + logger.Information("Event {Iteration} generated by {ThreadId}", i, Environment.CurrentManagedThreadId); + }); } } diff --git a/sample/SyncWritesDemo/SyncWritesDemo.csproj b/sample/SyncWritesDemo/SyncWritesDemo.csproj index a72595e..8612d23 100644 --- a/sample/SyncWritesDemo/SyncWritesDemo.csproj +++ b/sample/SyncWritesDemo/SyncWritesDemo.csproj @@ -1,8 +1,8 @@ - + Exe - net5.0 + net7.0 diff --git a/serilog-sinks-console.sln b/serilog-sinks-console.sln index e223156..5c0fcd4 100644 --- a/serilog-sinks-console.sln +++ b/serilog-sinks-console.sln @@ -1,17 +1,20 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.12 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33424.131 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{037440DE-440B-4129-9F7A-09B42D00397E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5E1-DEB9-4A04-8BAB-24EC7240ADAF}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig .gitattributes = .gitattributes .gitignore = .gitignore appveyor.yml = appveyor.yml Build.ps1 = Build.ps1 CHANGES.md = CHANGES.md + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets LICENSE = LICENSE README.md = README.md assets\Serilog.snk = assets\Serilog.snk @@ -27,7 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{CF8176 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleDemo", "sample\ConsoleDemo\ConsoleDemo.csproj", "{DBF4907A-63A2-4895-8DEF-59F90C20380B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyncWritesDemo", "sample\SyncWritesDemo\SyncWritesDemo.csproj", "{633AE0AD-C9D4-440D-874A-C0F4632DB75F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyncWritesDemo", "sample\SyncWritesDemo\SyncWritesDemo.csproj", "{633AE0AD-C9D4-440D-874A-C0F4632DB75F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Serilog.Sinks.Console/ConsoleLoggerConfigurationExtensions.cs b/src/Serilog.Sinks.Console/ConsoleLoggerConfigurationExtensions.cs index e55f7a2..d9c4458 100644 --- a/src/Serilog.Sinks.Console/ConsoleLoggerConfigurationExtensions.cs +++ b/src/Serilog.Sinks.Console/ConsoleLoggerConfigurationExtensions.cs @@ -1,4 +1,4 @@ -// Copyright 2017 Serilog Contributors +// Copyright 2017 Serilog Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,94 +19,92 @@ using Serilog.Sinks.SystemConsole; using Serilog.Sinks.SystemConsole.Output; using Serilog.Sinks.SystemConsole.Themes; -using System; -namespace Serilog +namespace Serilog; + +/// +/// Adds the WriteTo.Console() extension method to . +/// +public static class ConsoleLoggerConfigurationExtensions { + static readonly object DefaultSyncRoot = new(); + const string DefaultConsoleOutputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"; + /// - /// Adds the WriteTo.Console() extension method to . + /// Writes log events to . /// - public static class ConsoleLoggerConfigurationExtensions + /// Logger sink configuration. + /// The minimum level for + /// events passed through the sink. Ignored when is specified. + /// A message template describing the format used to write to the sink. + /// The default is "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}". + /// An object that will be used to `lock` (sync) access to the console output. If you specify this, you + /// will have the ability to lock on this object, and guarantee that the console sink will not be about to output anything while + /// the lock is held. + /// Supplies culture-specific formatting information, or null. + /// A switch allowing the pass-through minimum level + /// to be changed at runtime. + /// Specifies the level at which events will be written to standard error. + /// The theme to apply to the styled output. If not specified, + /// uses . + /// Applies the selected or default theme even when output redirection is detected. + /// Configuration object allowing method chaining. + /// When is null + /// When is null + public static LoggerConfiguration Console( + this LoggerSinkConfiguration sinkConfiguration, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = DefaultConsoleOutputTemplate, + IFormatProvider? formatProvider = null, + LoggingLevelSwitch? levelSwitch = null, + LogEventLevel? standardErrorFromLevel = null, + ConsoleTheme? theme = null, + bool applyThemeToRedirectedOutput = false, + object? syncRoot = null) { - static readonly object DefaultSyncRoot = new object(); - const string DefaultConsoleOutputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"; + if (sinkConfiguration is null) throw new ArgumentNullException(nameof(sinkConfiguration)); + if (outputTemplate is null) throw new ArgumentNullException(nameof(outputTemplate)); - /// - /// Writes log events to . - /// - /// Logger sink configuration. - /// The minimum level for - /// events passed through the sink. Ignored when is specified. - /// A message template describing the format used to write to the sink. - /// The default is "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}". - /// An object that will be used to `lock` (sync) access to the console output. If you specify this, you - /// will have the ability to lock on this object, and guarantee that the console sink will not be about to output anything while - /// the lock is held. - /// Supplies culture-specific formatting information, or null. - /// A switch allowing the pass-through minimum level - /// to be changed at runtime. - /// Specifies the level at which events will be written to standard error. - /// The theme to apply to the styled output. If not specified, - /// uses . - /// Applies the selected or default theme even when output redirection is detected. - /// Configuration object allowing method chaining. - /// When is null - /// When is null - public static LoggerConfiguration Console( - this LoggerSinkConfiguration sinkConfiguration, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - string outputTemplate = DefaultConsoleOutputTemplate, - IFormatProvider? formatProvider = null, - LoggingLevelSwitch? levelSwitch = null, - LogEventLevel? standardErrorFromLevel = null, - ConsoleTheme? theme = null, - bool applyThemeToRedirectedOutput = false, - object? syncRoot = null) - { - if (sinkConfiguration is null) throw new ArgumentNullException(nameof(sinkConfiguration)); - if (outputTemplate is null) throw new ArgumentNullException(nameof(outputTemplate)); + var appliedTheme = !applyThemeToRedirectedOutput && (System.Console.IsOutputRedirected || System.Console.IsErrorRedirected) ? + ConsoleTheme.None : + theme ?? SystemConsoleThemes.Literate; - var appliedTheme = !applyThemeToRedirectedOutput && (System.Console.IsOutputRedirected || System.Console.IsErrorRedirected) ? - ConsoleTheme.None : - theme ?? SystemConsoleThemes.Literate; + syncRoot ??= DefaultSyncRoot; - syncRoot ??= DefaultSyncRoot; - - var formatter = new OutputTemplateRenderer(appliedTheme, outputTemplate, formatProvider); - return sinkConfiguration.Sink(new ConsoleSink(appliedTheme, formatter, standardErrorFromLevel, syncRoot), restrictedToMinimumLevel, levelSwitch); - } + var formatter = new OutputTemplateRenderer(appliedTheme, outputTemplate, formatProvider); + return sinkConfiguration.Sink(new ConsoleSink(appliedTheme, formatter, standardErrorFromLevel, syncRoot), restrictedToMinimumLevel, levelSwitch); + } - /// - /// Writes log events to . - /// - /// Logger sink configuration. - /// Controls the rendering of log events into text, for example to log JSON. To - /// control plain text formatting, use the overload that accepts an output template. - /// An object that will be used to `lock` (sync) access to the console output. If you specify this, you - /// will have the ability to lock on this object, and guarantee that the console sink will not be about to output anything while - /// the lock is held. - /// The minimum level for - /// events passed through the sink. Ignored when is specified. - /// A switch allowing the pass-through minimum level - /// to be changed at runtime. - /// Specifies the level at which events will be written to standard error. - /// Configuration object allowing method chaining. - /// When is null - /// When is null - public static LoggerConfiguration Console( - this LoggerSinkConfiguration sinkConfiguration, - ITextFormatter formatter, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch? levelSwitch = null, - LogEventLevel? standardErrorFromLevel = null, - object? syncRoot = null) - { - if (sinkConfiguration is null) throw new ArgumentNullException(nameof(sinkConfiguration)); - if (formatter is null) throw new ArgumentNullException(nameof(formatter)); + /// + /// Writes log events to . + /// + /// Logger sink configuration. + /// Controls the rendering of log events into text, for example to log JSON. To + /// control plain text formatting, use the overload that accepts an output template. + /// An object that will be used to `lock` (sync) access to the console output. If you specify this, you + /// will have the ability to lock on this object, and guarantee that the console sink will not be about to output anything while + /// the lock is held. + /// The minimum level for + /// events passed through the sink. Ignored when is specified. + /// A switch allowing the pass-through minimum level + /// to be changed at runtime. + /// Specifies the level at which events will be written to standard error. + /// Configuration object allowing method chaining. + /// When is null + /// When is null + public static LoggerConfiguration Console( + this LoggerSinkConfiguration sinkConfiguration, + ITextFormatter formatter, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch? levelSwitch = null, + LogEventLevel? standardErrorFromLevel = null, + object? syncRoot = null) + { + if (sinkConfiguration is null) throw new ArgumentNullException(nameof(sinkConfiguration)); + if (formatter is null) throw new ArgumentNullException(nameof(formatter)); - syncRoot ??= DefaultSyncRoot; + syncRoot ??= DefaultSyncRoot; - return sinkConfiguration.Sink(new ConsoleSink(ConsoleTheme.None, formatter, standardErrorFromLevel, syncRoot), restrictedToMinimumLevel, levelSwitch); - } + return sinkConfiguration.Sink(new ConsoleSink(ConsoleTheme.None, formatter, standardErrorFromLevel, syncRoot), restrictedToMinimumLevel, levelSwitch); } } diff --git a/src/Serilog.Sinks.Console/Properties/AssemblyInfo.cs b/src/Serilog.Sinks.Console/Properties/AssemblyInfo.cs index 34ef2fa..d02dfea 100644 --- a/src/Serilog.Sinks.Console/Properties/AssemblyInfo.cs +++ b/src/Serilog.Sinks.Console/Properties/AssemblyInfo.cs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using System.Runtime.CompilerServices; [assembly: CLSCompliant(true)] diff --git a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj index d48dc58..8764446 100644 --- a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj +++ b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj @@ -5,11 +5,6 @@ 4.1.1 Serilog Contributors net45;netstandard1.3;netstandard2.0;net5.0 - 8.0 - enable - ../../assets/Serilog.snk - true - true serilog;console;terminal icon.png https://github.com/serilog/serilog-sinks-console @@ -17,25 +12,23 @@ https://github.com/serilog/serilog-sinks-console git true - True Serilog - latest $(DefineConstants);RUNTIME_INFORMATION - + $(DefineConstants);FEATURE_SPAN - + - + - + diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/ConsoleSink.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/ConsoleSink.cs index e1c1bea..c940d68 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/ConsoleSink.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/ConsoleSink.cs @@ -17,72 +17,69 @@ using Serilog.Formatting; using Serilog.Sinks.SystemConsole.Platform; using Serilog.Sinks.SystemConsole.Themes; -using System; -using System.IO; using System.Text; -namespace Serilog.Sinks.SystemConsole +namespace Serilog.Sinks.SystemConsole; + +class ConsoleSink : ILogEventSink { - class ConsoleSink : ILogEventSink - { - readonly LogEventLevel? _standardErrorFromLevel; - readonly ConsoleTheme _theme; - readonly ITextFormatter _formatter; - readonly object _syncRoot; + readonly LogEventLevel? _standardErrorFromLevel; + readonly ConsoleTheme _theme; + readonly ITextFormatter _formatter; + readonly object _syncRoot; - const int DefaultWriteBufferCapacity = 256; + const int DefaultWriteBufferCapacity = 256; - static ConsoleSink() - { - WindowsConsole.EnableVirtualTerminalProcessing(); - } + static ConsoleSink() + { + WindowsConsole.EnableVirtualTerminalProcessing(); + } - public ConsoleSink( - ConsoleTheme theme, - ITextFormatter formatter, - LogEventLevel? standardErrorFromLevel, - object syncRoot) - { - _standardErrorFromLevel = standardErrorFromLevel; - _theme = theme ?? throw new ArgumentNullException(nameof(theme)); - _formatter = formatter; - _syncRoot = syncRoot ?? throw new ArgumentNullException(nameof(syncRoot)); - } + public ConsoleSink( + ConsoleTheme theme, + ITextFormatter formatter, + LogEventLevel? standardErrorFromLevel, + object syncRoot) + { + _standardErrorFromLevel = standardErrorFromLevel; + _theme = theme ?? throw new ArgumentNullException(nameof(theme)); + _formatter = formatter; + _syncRoot = syncRoot ?? throw new ArgumentNullException(nameof(syncRoot)); + } - public void Emit(LogEvent logEvent) - { - var output = SelectOutputStream(logEvent.Level); + public void Emit(LogEvent logEvent) + { + var output = SelectOutputStream(logEvent.Level); - // ANSI escape codes can be pre-rendered into a buffer; however, if we're on Windows and - // using its console coloring APIs, the color switches would happen during the off-screen - // buffered write here and have no effect when the line is actually written out. - if (_theme.CanBuffer) + // ANSI escape codes can be pre-rendered into a buffer; however, if we're on Windows and + // using its console coloring APIs, the color switches would happen during the off-screen + // buffered write here and have no effect when the line is actually written out. + if (_theme.CanBuffer) + { + var buffer = new StringWriter(new StringBuilder(DefaultWriteBufferCapacity)); + _formatter.Format(logEvent, buffer); + var formattedLogEventText = buffer.ToString(); + lock (_syncRoot) { - var buffer = new StringWriter(new StringBuilder(DefaultWriteBufferCapacity)); - _formatter.Format(logEvent, buffer); - var formattedLogEventText = buffer.ToString(); - lock (_syncRoot) - { - output.Write(formattedLogEventText); - output.Flush(); - } + output.Write(formattedLogEventText); + output.Flush(); } - else + } + else + { + lock (_syncRoot) { - lock (_syncRoot) - { - _formatter.Format(logEvent, output); - output.Flush(); - } + _formatter.Format(logEvent, output); + output.Flush(); } } + } - TextWriter SelectOutputStream(LogEventLevel logEventLevel) - { - if (_standardErrorFromLevel is null) - return Console.Out; + TextWriter SelectOutputStream(LogEventLevel logEventLevel) + { + if (_standardErrorFromLevel is null) + return Console.Out; - return logEventLevel < _standardErrorFromLevel ? Console.Out : Console.Error; - } + return logEventLevel < _standardErrorFromLevel ? Console.Out : Console.Error; } } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedDisplayValueFormatter.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedDisplayValueFormatter.cs index 3093bd6..6bfd9eb 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedDisplayValueFormatter.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedDisplayValueFormatter.cs @@ -12,203 +12,200 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; using Serilog.Events; using Serilog.Formatting.Json; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Formatting +namespace Serilog.Sinks.SystemConsole.Formatting; + +class ThemedDisplayValueFormatter : ThemedValueFormatter { - class ThemedDisplayValueFormatter : ThemedValueFormatter - { - readonly IFormatProvider? _formatProvider; + readonly IFormatProvider? _formatProvider; - public ThemedDisplayValueFormatter(ConsoleTheme theme, IFormatProvider? formatProvider) - : base(theme) - { - _formatProvider = formatProvider; - } + public ThemedDisplayValueFormatter(ConsoleTheme theme, IFormatProvider? formatProvider) + : base(theme) + { + _formatProvider = formatProvider; + } - public override ThemedValueFormatter SwitchTheme(ConsoleTheme theme) - { - return new ThemedDisplayValueFormatter(theme, _formatProvider); - } + public override ThemedValueFormatter SwitchTheme(ConsoleTheme theme) + { + return new ThemedDisplayValueFormatter(theme, _formatProvider); + } - protected override int VisitScalarValue(ThemedValueFormatterState state, ScalarValue scalar) - { - if (scalar is null) - throw new ArgumentNullException(nameof(scalar)); - return FormatLiteralValue(scalar, state.Output, state.Format); - } + protected override int VisitScalarValue(ThemedValueFormatterState state, ScalarValue scalar) + { + if (scalar is null) + throw new ArgumentNullException(nameof(scalar)); + return FormatLiteralValue(scalar, state.Output, state.Format); + } - protected override int VisitSequenceValue(ThemedValueFormatterState state, SequenceValue sequence) - { - if (sequence is null) - throw new ArgumentNullException(nameof(sequence)); + protected override int VisitSequenceValue(ThemedValueFormatterState state, SequenceValue sequence) + { + if (sequence is null) + throw new ArgumentNullException(nameof(sequence)); - var count = 0; + var count = 0; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('['); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('['); - var delim = string.Empty; - for (var index = 0; index < sequence.Elements.Count; ++index) + var delim = string.Empty; + for (var index = 0; index < sequence.Elements.Count; ++index) + { + if (delim.Length != 0) { - if (delim.Length != 0) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(delim); - } - - delim = ", "; - Visit(state, sequence.Elements[index]); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(delim); } - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(']'); - - return count; + delim = ", "; + Visit(state, sequence.Elements[index]); } - protected override int VisitStructureValue(ThemedValueFormatterState state, StructureValue structure) - { - var count = 0; + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(']'); - if (structure.TypeTag != null) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) - state.Output.Write(structure.TypeTag); + return count; + } - state.Output.Write(' '); - } + protected override int VisitStructureValue(ThemedValueFormatterState state, StructureValue structure) + { + var count = 0; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('{'); + if (structure.TypeTag != null) + { + using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) + state.Output.Write(structure.TypeTag); - var delim = string.Empty; - for (var index = 0; index < structure.Properties.Count; ++index) - { - if (delim.Length != 0) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(delim); - } + state.Output.Write(' '); + } - delim = ", "; + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('{'); - var property = structure.Properties[index]; + var delim = string.Empty; + for (var index = 0; index < structure.Properties.Count; ++index) + { + if (delim.Length != 0) + { + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(delim); + } - using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) - state.Output.Write(property.Name); + delim = ", "; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('='); + var property = structure.Properties[index]; - count += Visit(state.Nest(), property.Value); - } + using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) + state.Output.Write(property.Name); using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('}'); + state.Output.Write('='); - return count; + count += Visit(state.Nest(), property.Value); } - protected override int VisitDictionaryValue(ThemedValueFormatterState state, DictionaryValue dictionary) - { - var count = 0; + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('}'); - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('{'); + return count; + } - var delim = string.Empty; - foreach (var element in dictionary.Elements) - { - if (delim.Length != 0) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(delim); - } + protected override int VisitDictionaryValue(ThemedValueFormatterState state, DictionaryValue dictionary) + { + var count = 0; - delim = ", "; + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('{'); + var delim = string.Empty; + foreach (var element in dictionary.Elements) + { + if (delim.Length != 0) + { using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('['); + state.Output.Write(delim); + } - using (ApplyStyle(state.Output, ConsoleThemeStyle.String, ref count)) - count += Visit(state.Nest(), element.Key); + delim = ", "; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write("]="); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('['); - count += Visit(state.Nest(), element.Value); - } + using (ApplyStyle(state.Output, ConsoleThemeStyle.String, ref count)) + count += Visit(state.Nest(), element.Key); using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('}'); + state.Output.Write("]="); - return count; + count += Visit(state.Nest(), element.Value); } - public int FormatLiteralValue(ScalarValue scalar, TextWriter output, string? format) + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('}'); + + return count; + } + + public int FormatLiteralValue(ScalarValue scalar, TextWriter output, string? format) + { + var value = scalar.Value; + var count = 0; + + if (value is null) { - var value = scalar.Value; - var count = 0; + using (ApplyStyle(output, ConsoleThemeStyle.Null, ref count)) + output.Write("null"); + return count; + } - if (value is null) + if (value is string str) + { + using (ApplyStyle(output, ConsoleThemeStyle.String, ref count)) { - using (ApplyStyle(output, ConsoleThemeStyle.Null, ref count)) - output.Write("null"); - return count; + if (format != "l") + JsonValueFormatter.WriteQuotedJsonString(str, output); + else + output.Write(str); } + return count; + } - if (value is string str) + if (value is ValueType) + { + if (value is int || value is uint || value is long || value is ulong || + value is decimal || value is byte || value is sbyte || value is short || + value is ushort || value is float || value is double) { - using (ApplyStyle(output, ConsoleThemeStyle.String, ref count)) - { - if (format != "l") - JsonValueFormatter.WriteQuotedJsonString(str, output); - else - output.Write(str); - } + using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) + scalar.Render(output, format, _formatProvider); return count; } - if (value is ValueType) + if (value is bool b) { - if (value is int || value is uint || value is long || value is ulong || - value is decimal || value is byte || value is sbyte || value is short || - value is ushort || value is float || value is double) - { - using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) - scalar.Render(output, format, _formatProvider); - return count; - } + using (ApplyStyle(output, ConsoleThemeStyle.Boolean, ref count)) + output.Write(b); - if (value is bool b) - { - using (ApplyStyle(output, ConsoleThemeStyle.Boolean, ref count)) - output.Write(b); - - return count; - } + return count; + } - if (value is char ch) + if (value is char ch) + { + using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) { - using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) - { - output.Write('\''); - output.Write(ch); - output.Write('\''); - } - return count; + output.Write('\''); + output.Write(ch); + output.Write('\''); } + return count; } + } - using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) - scalar.Render(output, format, _formatProvider); + using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) + scalar.Render(output, format, _formatProvider); - return count; - } + return count; } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedJsonValueFormatter.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedJsonValueFormatter.cs index ec6d5d1..2117792 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedJsonValueFormatter.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedJsonValueFormatter.cs @@ -12,245 +12,242 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using System.Globalization; -using System.IO; using Serilog.Events; using Serilog.Formatting.Json; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Formatting +namespace Serilog.Sinks.SystemConsole.Formatting; + +class ThemedJsonValueFormatter : ThemedValueFormatter { - class ThemedJsonValueFormatter : ThemedValueFormatter - { - readonly ThemedDisplayValueFormatter _displayFormatter; - readonly IFormatProvider? _formatProvider; + readonly ThemedDisplayValueFormatter _displayFormatter; + readonly IFormatProvider? _formatProvider; - public ThemedJsonValueFormatter(ConsoleTheme theme, IFormatProvider? formatProvider) - : base(theme) - { - _displayFormatter = new ThemedDisplayValueFormatter(theme, formatProvider); - _formatProvider = formatProvider; - } + public ThemedJsonValueFormatter(ConsoleTheme theme, IFormatProvider? formatProvider) + : base(theme) + { + _displayFormatter = new ThemedDisplayValueFormatter(theme, formatProvider); + _formatProvider = formatProvider; + } - public override ThemedValueFormatter SwitchTheme(ConsoleTheme theme) - { - return new ThemedJsonValueFormatter(theme, _formatProvider); - } + public override ThemedValueFormatter SwitchTheme(ConsoleTheme theme) + { + return new ThemedJsonValueFormatter(theme, _formatProvider); + } - protected override int VisitScalarValue(ThemedValueFormatterState state, ScalarValue scalar) - { - if (scalar is null) - throw new ArgumentNullException(nameof(scalar)); + protected override int VisitScalarValue(ThemedValueFormatterState state, ScalarValue scalar) + { + if (scalar is null) + throw new ArgumentNullException(nameof(scalar)); - // At the top level, for scalar values, use "display" rendering. - if (state.IsTopLevel) - return _displayFormatter.FormatLiteralValue(scalar, state.Output, state.Format); + // At the top level, for scalar values, use "display" rendering. + if (state.IsTopLevel) + return _displayFormatter.FormatLiteralValue(scalar, state.Output, state.Format); - return FormatLiteralValue(scalar, state.Output); - } + return FormatLiteralValue(scalar, state.Output); + } - protected override int VisitSequenceValue(ThemedValueFormatterState state, SequenceValue sequence) - { - if (sequence == null) - throw new ArgumentNullException(nameof(sequence)); + protected override int VisitSequenceValue(ThemedValueFormatterState state, SequenceValue sequence) + { + if (sequence == null) + throw new ArgumentNullException(nameof(sequence)); - var count = 0; + var count = 0; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('['); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('['); - var delim = string.Empty; - for (var index = 0; index < sequence.Elements.Count; ++index) + var delim = string.Empty; + for (var index = 0; index < sequence.Elements.Count; ++index) + { + if (delim.Length != 0) { - if (delim.Length != 0) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(delim); - } - - delim = ", "; - Visit(state.Nest(), sequence.Elements[index]); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(delim); } - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(']'); - - return count; + delim = ", "; + Visit(state.Nest(), sequence.Elements[index]); } - protected override int VisitStructureValue(ThemedValueFormatterState state, StructureValue structure) - { - var count = 0; - - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('{'); - - var delim = string.Empty; - for (var index = 0; index < structure.Properties.Count; ++index) - { - if (delim.Length != 0) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(delim); - } + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(']'); - delim = ", "; - - var property = structure.Properties[index]; - - using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) - JsonValueFormatter.WriteQuotedJsonString(property.Name, state.Output); + return count; + } - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(": "); + protected override int VisitStructureValue(ThemedValueFormatterState state, StructureValue structure) + { + var count = 0; - count += Visit(state.Nest(), property.Value); - } + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('{'); - if (structure.TypeTag != null) + var delim = string.Empty; + for (var index = 0; index < structure.Properties.Count; ++index) + { + if (delim.Length != 0) { using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) state.Output.Write(delim); + } - using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) - JsonValueFormatter.WriteQuotedJsonString("$type", state.Output); + delim = ", "; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(": "); + var property = structure.Properties[index]; - using (ApplyStyle(state.Output, ConsoleThemeStyle.String, ref count)) - JsonValueFormatter.WriteQuotedJsonString(structure.TypeTag, state.Output); - } + using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) + JsonValueFormatter.WriteQuotedJsonString(property.Name, state.Output); using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('}'); + state.Output.Write(": "); - return count; + count += Visit(state.Nest(), property.Value); } - protected override int VisitDictionaryValue(ThemedValueFormatterState state, DictionaryValue dictionary) + if (structure.TypeTag != null) { - var count = 0; + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(delim); + + using (ApplyStyle(state.Output, ConsoleThemeStyle.Name, ref count)) + JsonValueFormatter.WriteQuotedJsonString("$type", state.Output); using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('{'); + state.Output.Write(": "); - var delim = string.Empty; - foreach (var element in dictionary.Elements) - { - if (delim.Length != 0) - { - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(delim); - } + using (ApplyStyle(state.Output, ConsoleThemeStyle.String, ref count)) + JsonValueFormatter.WriteQuotedJsonString(structure.TypeTag, state.Output); + } - delim = ", "; + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('}'); - var style = element.Key.Value == null - ? ConsoleThemeStyle.Null - : element.Key.Value is string - ? ConsoleThemeStyle.String - : ConsoleThemeStyle.Scalar; + return count; + } - using (ApplyStyle(state.Output, style, ref count)) - JsonValueFormatter.WriteQuotedJsonString((element.Key.Value ?? "null").ToString() ?? "", state.Output); + protected override int VisitDictionaryValue(ThemedValueFormatterState state, DictionaryValue dictionary) + { + var count = 0; - using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write(": "); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('{'); - count += Visit(state.Nest(), element.Value); + var delim = string.Empty; + foreach (var element in dictionary.Elements) + { + if (delim.Length != 0) + { + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write(delim); } + delim = ", "; + + var style = element.Key.Value == null + ? ConsoleThemeStyle.Null + : element.Key.Value is string + ? ConsoleThemeStyle.String + : ConsoleThemeStyle.Scalar; + + using (ApplyStyle(state.Output, style, ref count)) + JsonValueFormatter.WriteQuotedJsonString((element.Key.Value ?? "null").ToString() ?? "", state.Output); + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) - state.Output.Write('}'); + state.Output.Write(": "); + count += Visit(state.Nest(), element.Value); + } + + using (ApplyStyle(state.Output, ConsoleThemeStyle.TertiaryText, ref count)) + state.Output.Write('}'); + + return count; + } + + int FormatLiteralValue(ScalarValue scalar, TextWriter output) + { + var value = scalar.Value; + var count = 0; + + if (value == null) + { + using (ApplyStyle(output, ConsoleThemeStyle.Null, ref count)) + output.Write("null"); return count; } - int FormatLiteralValue(ScalarValue scalar, TextWriter output) + if (value is string str) { - var value = scalar.Value; - var count = 0; + using (ApplyStyle(output, ConsoleThemeStyle.String, ref count)) + JsonValueFormatter.WriteQuotedJsonString(str, output); + return count; + } - if (value == null) + if (value is ValueType) + { + if (value is int || value is uint || value is long || value is ulong || value is decimal || value is byte || value is sbyte || value is short || value is ushort) { - using (ApplyStyle(output, ConsoleThemeStyle.Null, ref count)) - output.Write("null"); + using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) + output.Write(((IFormattable)value).ToString(null, CultureInfo.InvariantCulture)); return count; } - if (value is string str) + if (value is double d) { - using (ApplyStyle(output, ConsoleThemeStyle.String, ref count)) - JsonValueFormatter.WriteQuotedJsonString(str, output); + using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) + { + if (double.IsNaN(d) || double.IsInfinity(d)) + JsonValueFormatter.WriteQuotedJsonString(d.ToString(CultureInfo.InvariantCulture), output); + else + output.Write(d.ToString("R", CultureInfo.InvariantCulture)); + } return count; } - if (value is ValueType) + if (value is float f) { - if (value is int || value is uint || value is long || value is ulong || value is decimal || value is byte || value is sbyte || value is short || value is ushort) - { - using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) - output.Write(((IFormattable)value).ToString(null, CultureInfo.InvariantCulture)); - return count; - } - - if (value is double d) - { - using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) - { - if (double.IsNaN(d) || double.IsInfinity(d)) - JsonValueFormatter.WriteQuotedJsonString(d.ToString(CultureInfo.InvariantCulture), output); - else - output.Write(d.ToString("R", CultureInfo.InvariantCulture)); - } - return count; - } - - if (value is float f) + using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) { - using (ApplyStyle(output, ConsoleThemeStyle.Number, ref count)) - { - if (double.IsNaN(f) || double.IsInfinity(f)) - JsonValueFormatter.WriteQuotedJsonString(f.ToString(CultureInfo.InvariantCulture), output); - else - output.Write(f.ToString("R", CultureInfo.InvariantCulture)); - } - return count; + if (double.IsNaN(f) || double.IsInfinity(f)) + JsonValueFormatter.WriteQuotedJsonString(f.ToString(CultureInfo.InvariantCulture), output); + else + output.Write(f.ToString("R", CultureInfo.InvariantCulture)); } + return count; + } - if (value is bool b) - { - using (ApplyStyle(output, ConsoleThemeStyle.Boolean, ref count)) - output.Write(b ? "true" : "false"); + if (value is bool b) + { + using (ApplyStyle(output, ConsoleThemeStyle.Boolean, ref count)) + output.Write(b ? "true" : "false"); - return count; - } + return count; + } - if (value is char ch) - { - using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) - JsonValueFormatter.WriteQuotedJsonString(ch.ToString(), output); - return count; - } + if (value is char ch) + { + using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) + JsonValueFormatter.WriteQuotedJsonString(ch.ToString(), output); + return count; + } - if (value is DateTime || value is DateTimeOffset) + if (value is DateTime || value is DateTimeOffset) + { + using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) { - using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) - { - output.Write('"'); - output.Write(((IFormattable)value).ToString("O", CultureInfo.InvariantCulture)); - output.Write('"'); - } - return count; + output.Write('"'); + output.Write(((IFormattable)value).ToString("O", CultureInfo.InvariantCulture)); + output.Write('"'); } + return count; } + } - using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) - JsonValueFormatter.WriteQuotedJsonString(value.ToString() ?? "", output); + using (ApplyStyle(output, ConsoleThemeStyle.Scalar, ref count)) + JsonValueFormatter.WriteQuotedJsonString(value.ToString() ?? "", output); - return count; - } + return count; } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatter.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatter.cs index 34be339..b492a87 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatter.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatter.cs @@ -12,33 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; using Serilog.Data; using Serilog.Events; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Formatting -{ - abstract class ThemedValueFormatter : LogEventPropertyValueVisitor - { - readonly ConsoleTheme _theme; +namespace Serilog.Sinks.SystemConsole.Formatting; - protected ThemedValueFormatter(ConsoleTheme theme) - { - _theme = theme ?? throw new ArgumentNullException(nameof(theme)); - } +abstract class ThemedValueFormatter : LogEventPropertyValueVisitor +{ + readonly ConsoleTheme _theme; - protected StyleReset ApplyStyle(TextWriter output, ConsoleThemeStyle style, ref int invisibleCharacterCount) - { - return _theme.Apply(output, style, ref invisibleCharacterCount); - } + protected ThemedValueFormatter(ConsoleTheme theme) + { + _theme = theme ?? throw new ArgumentNullException(nameof(theme)); + } - public int Format(LogEventPropertyValue value, TextWriter output, string? format, bool literalTopLevel = false) - { - return Visit(new ThemedValueFormatterState { Output = output, Format = format, IsTopLevel = literalTopLevel }, value); - } + protected StyleReset ApplyStyle(TextWriter output, ConsoleThemeStyle style, ref int invisibleCharacterCount) + { + return _theme.Apply(output, style, ref invisibleCharacterCount); + } - public abstract ThemedValueFormatter SwitchTheme(ConsoleTheme theme); + public int Format(LogEventPropertyValue value, TextWriter output, string? format, bool literalTopLevel = false) + { + return Visit(new ThemedValueFormatterState { Output = output, Format = format, IsTopLevel = literalTopLevel }, value); } + + public abstract ThemedValueFormatter SwitchTheme(ConsoleTheme theme); } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatterState.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatterState.cs index a5f5a86..5d5c110 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatterState.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Formatting/ThemedValueFormatterState.cs @@ -12,16 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; +namespace Serilog.Sinks.SystemConsole.Formatting; -namespace Serilog.Sinks.SystemConsole.Formatting +struct ThemedValueFormatterState { - struct ThemedValueFormatterState - { - public TextWriter Output; - public string? Format; - public bool IsTopLevel; + public TextWriter Output; + public string? Format; + public bool IsTopLevel; - public ThemedValueFormatterState Nest() => new ThemedValueFormatterState { Output = Output }; - } + public ThemedValueFormatterState Nest() => new() { Output = Output }; } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/EventPropertyTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/EventPropertyTokenRenderer.cs index d4fe511..eee88c5 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/EventPropertyTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/EventPropertyTokenRenderer.cs @@ -12,59 +12,56 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Rendering; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class EventPropertyTokenRenderer : OutputTemplateTokenRenderer { - class EventPropertyTokenRenderer : OutputTemplateTokenRenderer + readonly ConsoleTheme _theme; + readonly PropertyToken _token; + readonly IFormatProvider? _formatProvider; + + public EventPropertyTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) { - readonly ConsoleTheme _theme; - readonly PropertyToken _token; - readonly IFormatProvider? _formatProvider; + _theme = theme; + _token = token; + _formatProvider = formatProvider; + } - public EventPropertyTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) + public override void Render(LogEvent logEvent, TextWriter output) + { + // If a property is missing, don't render anything (message templates render the raw token here). + if (!logEvent.Properties.TryGetValue(_token.PropertyName, out var propertyValue)) { - _theme = theme; - _token = token; - _formatProvider = formatProvider; + Padding.Apply(output, string.Empty, _token.Alignment); + return; } - public override void Render(LogEvent logEvent, TextWriter output) + var _ = 0; + using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) { - // If a property is missing, don't render anything (message templates render the raw token here). - if (!logEvent.Properties.TryGetValue(_token.PropertyName, out var propertyValue)) + var writer = _token.Alignment.HasValue ? new StringWriter() : output; + + // If the value is a scalar string, support some additional formats: 'u' for uppercase + // and 'w' for lowercase. + if (propertyValue is ScalarValue sv && sv.Value is string literalString) { - Padding.Apply(output, string.Empty, _token.Alignment); - return; + var cased = Casing.Format(literalString, _token.Format); + writer.Write(cased); } - - var _ = 0; - using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) + else { - var writer = _token.Alignment.HasValue ? new StringWriter() : output; - - // If the value is a scalar string, support some additional formats: 'u' for uppercase - // and 'w' for lowercase. - if (propertyValue is ScalarValue sv && sv.Value is string literalString) - { - var cased = Casing.Format(literalString, _token.Format); - writer.Write(cased); - } - else - { - propertyValue.Render(writer, _token.Format, _formatProvider); - } + propertyValue.Render(writer, _token.Format, _formatProvider); + } - if (_token.Alignment.HasValue) - { - var str = writer.ToString()!; - Padding.Apply(output, str, _token.Alignment); - } + if (_token.Alignment.HasValue) + { + var str = writer.ToString()!; + Padding.Apply(output, str, _token.Alignment); } } } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/ExceptionTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/ExceptionTokenRenderer.cs index a70c161..eef109b 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/ExceptionTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/ExceptionTokenRenderer.cs @@ -12,41 +12,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class ExceptionTokenRenderer : OutputTemplateTokenRenderer { - class ExceptionTokenRenderer : OutputTemplateTokenRenderer + const string StackFrameLinePrefix = " "; + + readonly ConsoleTheme _theme; + + public ExceptionTokenRenderer(ConsoleTheme theme, PropertyToken pt) { - const string StackFrameLinePrefix = " "; + _theme = theme; + } - readonly ConsoleTheme _theme; + public override void Render(LogEvent logEvent, TextWriter output) + { + // Padding is never applied by this renderer. - public ExceptionTokenRenderer(ConsoleTheme theme, PropertyToken pt) - { - _theme = theme; - } + if (logEvent.Exception is null) + return; - public override void Render(LogEvent logEvent, TextWriter output) + var lines = new StringReader(logEvent.Exception.ToString()); + string? nextLine; + while ((nextLine = lines.ReadLine()) != null) { - // Padding is never applied by this renderer. - - if (logEvent.Exception is null) - return; - - var lines = new StringReader(logEvent.Exception.ToString()); - string? nextLine; - while ((nextLine = lines.ReadLine()) != null) - { - var style = nextLine.StartsWith(StackFrameLinePrefix) ? ConsoleThemeStyle.SecondaryText : ConsoleThemeStyle.Text; - var _ = 0; - using (_theme.Apply(output, style, ref _)) - output.Write(nextLine); - output.WriteLine(); - } + var style = nextLine.StartsWith(StackFrameLinePrefix) ? ConsoleThemeStyle.SecondaryText : ConsoleThemeStyle.Text; + var _ = 0; + using (_theme.Apply(output, style, ref _)) + output.Write(nextLine); + output.WriteLine(); } } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs index a0c996f..5979764 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using Serilog.Events; using Serilog.Sinks.SystemConsole.Rendering; @@ -74,17 +73,13 @@ public static string GetLevelMoniker(LogEventLevel value, string? format = null) if (width < 1) return string.Empty; - switch (format[0]) + return format[0] switch { - case 'w': - return GetLevelMoniker(LowerCaseLevelMap, index, width); - case 'u': - return GetLevelMoniker(UpperCaseLevelMap, index, width); - case 't': - return GetLevelMoniker(TitleCaseLevelMap, index, width); - default: - return Casing.Format(GetLevelMoniker(TitleCaseLevelMap, index), format); - } + 'w' => GetLevelMoniker(LowerCaseLevelMap, index, width), + 'u' => GetLevelMoniker(UpperCaseLevelMap, index, width), + 't' => GetLevelMoniker(TitleCaseLevelMap, index, width), + _ => Casing.Format(GetLevelMoniker(TitleCaseLevelMap, index), format), + }; } static string GetLevelMoniker(string[][] caseLevelMap, int index, int width) diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelTokenRenderer.cs index 9cb9ed1..37cbba4 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelTokenRenderer.cs @@ -12,45 +12,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.Collections.Generic; -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Rendering; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class LevelTokenRenderer : OutputTemplateTokenRenderer { - class LevelTokenRenderer : OutputTemplateTokenRenderer - { - readonly ConsoleTheme _theme; - readonly PropertyToken _levelToken; + readonly ConsoleTheme _theme; + readonly PropertyToken _levelToken; - static readonly Dictionary Levels = new Dictionary - { - { LogEventLevel.Verbose, ConsoleThemeStyle.LevelVerbose }, - { LogEventLevel.Debug, ConsoleThemeStyle.LevelDebug }, - { LogEventLevel.Information, ConsoleThemeStyle.LevelInformation }, - { LogEventLevel.Warning, ConsoleThemeStyle.LevelWarning }, - { LogEventLevel.Error, ConsoleThemeStyle.LevelError }, - { LogEventLevel.Fatal, ConsoleThemeStyle.LevelFatal }, - }; + static readonly Dictionary Levels = new() + { + { LogEventLevel.Verbose, ConsoleThemeStyle.LevelVerbose }, + { LogEventLevel.Debug, ConsoleThemeStyle.LevelDebug }, + { LogEventLevel.Information, ConsoleThemeStyle.LevelInformation }, + { LogEventLevel.Warning, ConsoleThemeStyle.LevelWarning }, + { LogEventLevel.Error, ConsoleThemeStyle.LevelError }, + { LogEventLevel.Fatal, ConsoleThemeStyle.LevelFatal }, + }; - public LevelTokenRenderer(ConsoleTheme theme, PropertyToken levelToken) - { - _theme = theme; - _levelToken = levelToken; - } + public LevelTokenRenderer(ConsoleTheme theme, PropertyToken levelToken) + { + _theme = theme; + _levelToken = levelToken; + } - public override void Render(LogEvent logEvent, TextWriter output) - { - var moniker = LevelOutputFormat.GetLevelMoniker(logEvent.Level, _levelToken.Format); - if (!Levels.TryGetValue(logEvent.Level, out var levelStyle)) - levelStyle = ConsoleThemeStyle.Invalid; + public override void Render(LogEvent logEvent, TextWriter output) + { + var moniker = LevelOutputFormat.GetLevelMoniker(logEvent.Level, _levelToken.Format); + if (!Levels.TryGetValue(logEvent.Level, out var levelStyle)) + levelStyle = ConsoleThemeStyle.Invalid; - var _ = 0; - using (_theme.Apply(output, levelStyle, ref _)) - Padding.Apply(output, moniker, _levelToken.Alignment); - } + var _ = 0; + using (_theme.Apply(output, levelStyle, ref _)) + Padding.Apply(output, moniker, _levelToken.Alignment); } -} \ No newline at end of file +} diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/MessageTemplateOutputTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/MessageTemplateOutputTokenRenderer.cs index 9f0997b..c7ee17e 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/MessageTemplateOutputTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/MessageTemplateOutputTokenRenderer.cs @@ -12,59 +12,56 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Rendering; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class MessageTemplateOutputTokenRenderer : OutputTemplateTokenRenderer { - class MessageTemplateOutputTokenRenderer : OutputTemplateTokenRenderer - { - readonly ConsoleTheme _theme; - readonly PropertyToken _token; - readonly ThemedMessageTemplateRenderer _renderer; + readonly ConsoleTheme _theme; + readonly PropertyToken _token; + readonly ThemedMessageTemplateRenderer _renderer; - public MessageTemplateOutputTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) - { - _theme = theme ?? throw new ArgumentNullException(nameof(theme)); - _token = token ?? throw new ArgumentNullException(nameof(token)); + public MessageTemplateOutputTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) + { + _theme = theme ?? throw new ArgumentNullException(nameof(theme)); + _token = token ?? throw new ArgumentNullException(nameof(token)); - bool isLiteral = false, isJson = false; + bool isLiteral = false, isJson = false; - if (token.Format != null) + if (token.Format != null) + { + for (var i = 0; i < token.Format.Length; ++i) { - for (var i = 0; i < token.Format.Length; ++i) - { - if (token.Format[i] == 'l') - isLiteral = true; - else if (token.Format[i] == 'j') - isJson = true; - } + if (token.Format[i] == 'l') + isLiteral = true; + else if (token.Format[i] == 'j') + isJson = true; } + } - var valueFormatter = isJson - ? (ThemedValueFormatter)new ThemedJsonValueFormatter(theme, formatProvider) - : new ThemedDisplayValueFormatter(theme, formatProvider); + var valueFormatter = isJson + ? (ThemedValueFormatter)new ThemedJsonValueFormatter(theme, formatProvider) + : new ThemedDisplayValueFormatter(theme, formatProvider); - _renderer = new ThemedMessageTemplateRenderer(theme, valueFormatter, isLiteral); - } + _renderer = new ThemedMessageTemplateRenderer(theme, valueFormatter, isLiteral); + } - public override void Render(LogEvent logEvent, TextWriter output) + public override void Render(LogEvent logEvent, TextWriter output) + { + if (_token.Alignment is null || !_theme.CanBuffer) { - if (_token.Alignment is null || !_theme.CanBuffer) - { - _renderer.Render(logEvent.MessageTemplate, logEvent.Properties, output); - return; - } - - var buffer = new StringWriter(); - var invisible = _renderer.Render(logEvent.MessageTemplate, logEvent.Properties, buffer); - var value = buffer.ToString(); - Padding.Apply(output, value, _token.Alignment.Value.Widen(invisible)); + _renderer.Render(logEvent.MessageTemplate, logEvent.Properties, output); + return; } + + var buffer = new StringWriter(); + var invisible = _renderer.Render(logEvent.MessageTemplate, logEvent.Properties, buffer); + var value = buffer.ToString(); + Padding.Apply(output, value, _token.Alignment.Value.Widen(invisible)); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/NewLineTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/NewLineTokenRenderer.cs index c7174e8..1e18d58 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/NewLineTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/NewLineTokenRenderer.cs @@ -12,29 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Rendering; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class NewLineTokenRenderer : OutputTemplateTokenRenderer { - class NewLineTokenRenderer : OutputTemplateTokenRenderer - { - readonly Alignment? _alignment; + readonly Alignment? _alignment; - public NewLineTokenRenderer(Alignment? alignment) - { - _alignment = alignment; - } + public NewLineTokenRenderer(Alignment? alignment) + { + _alignment = alignment; + } - public override void Render(LogEvent logEvent, TextWriter output) - { - if (_alignment.HasValue) - Padding.Apply(output, Environment.NewLine, _alignment.Value.Widen(Environment.NewLine.Length)); - else - output.WriteLine(); - } + public override void Render(LogEvent logEvent, TextWriter output) + { + if (_alignment.HasValue) + Padding.Apply(output, Environment.NewLine, _alignment.Value.Widen(Environment.NewLine.Length)); + else + output.WriteLine(); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs index c62ab67..dbd4cd8 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs @@ -12,76 +12,72 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.Collections.Generic; -using System.IO; using Serilog.Events; using Serilog.Formatting; using Serilog.Formatting.Display; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class OutputTemplateRenderer : ITextFormatter { - class OutputTemplateRenderer : ITextFormatter + readonly OutputTemplateTokenRenderer[] _renderers; + + public OutputTemplateRenderer(ConsoleTheme theme, string outputTemplate, IFormatProvider? formatProvider) { - readonly OutputTemplateTokenRenderer[] _renderers; + if (outputTemplate is null) throw new ArgumentNullException(nameof(outputTemplate)); + var template = new MessageTemplateParser().Parse(outputTemplate); - public OutputTemplateRenderer(ConsoleTheme theme, string outputTemplate, IFormatProvider? formatProvider) + var renderers = new List(); + foreach (var token in template.Tokens) { - if (outputTemplate is null) throw new ArgumentNullException(nameof(outputTemplate)); - var template = new MessageTemplateParser().Parse(outputTemplate); - - var renderers = new List(); - foreach (var token in template.Tokens) + if (token is TextToken tt) { - if (token is TextToken tt) - { - renderers.Add(new TextTokenRenderer(theme, tt.Text)); - continue; - } - - var pt = (PropertyToken)token; - if (pt.PropertyName == OutputProperties.LevelPropertyName) - { - renderers.Add(new LevelTokenRenderer(theme, pt)); - } - else if (pt.PropertyName == OutputProperties.NewLinePropertyName) - { - renderers.Add(new NewLineTokenRenderer(pt.Alignment)); - } - else if (pt.PropertyName == OutputProperties.ExceptionPropertyName) - { - renderers.Add(new ExceptionTokenRenderer(theme, pt)); - } - else if (pt.PropertyName == OutputProperties.MessagePropertyName) - { - renderers.Add(new MessageTemplateOutputTokenRenderer(theme, pt, formatProvider)); - } - else if (pt.PropertyName == OutputProperties.TimestampPropertyName) - { - renderers.Add(new TimestampTokenRenderer(theme, pt, formatProvider)); - } - else if (pt.PropertyName == "Properties") - { - renderers.Add(new PropertiesTokenRenderer(theme, pt, template, formatProvider)); - } - else - { - renderers.Add(new EventPropertyTokenRenderer(theme, pt, formatProvider)); - } + renderers.Add(new TextTokenRenderer(theme, tt.Text)); + continue; } - _renderers = renderers.ToArray(); + var pt = (PropertyToken)token; + if (pt.PropertyName == OutputProperties.LevelPropertyName) + { + renderers.Add(new LevelTokenRenderer(theme, pt)); + } + else if (pt.PropertyName == OutputProperties.NewLinePropertyName) + { + renderers.Add(new NewLineTokenRenderer(pt.Alignment)); + } + else if (pt.PropertyName == OutputProperties.ExceptionPropertyName) + { + renderers.Add(new ExceptionTokenRenderer(theme, pt)); + } + else if (pt.PropertyName == OutputProperties.MessagePropertyName) + { + renderers.Add(new MessageTemplateOutputTokenRenderer(theme, pt, formatProvider)); + } + else if (pt.PropertyName == OutputProperties.TimestampPropertyName) + { + renderers.Add(new TimestampTokenRenderer(theme, pt, formatProvider)); + } + else if (pt.PropertyName == "Properties") + { + renderers.Add(new PropertiesTokenRenderer(theme, pt, template, formatProvider)); + } + else + { + renderers.Add(new EventPropertyTokenRenderer(theme, pt, formatProvider)); + } } - public void Format(LogEvent logEvent, TextWriter output) - { - if (logEvent is null) throw new ArgumentNullException(nameof(logEvent)); - if (output is null) throw new ArgumentNullException(nameof(output)); + _renderers = renderers.ToArray(); + } - foreach (var renderer in _renderers) - renderer.Render(logEvent, output); - } + public void Format(LogEvent logEvent, TextWriter output) + { + if (logEvent is null) throw new ArgumentNullException(nameof(logEvent)); + if (output is null) throw new ArgumentNullException(nameof(output)); + + foreach (var renderer in _renderers) + renderer.Render(logEvent, output); } } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateTokenRenderer.cs index 90f3c7e..354bea8 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateTokenRenderer.cs @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; using Serilog.Events; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +abstract class OutputTemplateTokenRenderer { - abstract class OutputTemplateTokenRenderer - { - public abstract void Render(LogEvent logEvent, TextWriter output); - } + public abstract void Render(LogEvent logEvent, TextWriter output); } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/PropertiesTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/PropertiesTokenRenderer.cs index 8e48fd0..a6a1bd1 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/PropertiesTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/PropertiesTokenRenderer.cs @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; -using System.Linq; using System.Text; using Serilog.Events; using Serilog.Parsing; @@ -22,70 +19,69 @@ using Serilog.Sinks.SystemConsole.Rendering; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class PropertiesTokenRenderer : OutputTemplateTokenRenderer { - class PropertiesTokenRenderer : OutputTemplateTokenRenderer - { - readonly MessageTemplate _outputTemplate; - readonly ConsoleTheme _theme; - readonly PropertyToken _token; - readonly ThemedValueFormatter _valueFormatter; + readonly MessageTemplate _outputTemplate; + readonly ConsoleTheme _theme; + readonly PropertyToken _token; + readonly ThemedValueFormatter _valueFormatter; - public PropertiesTokenRenderer(ConsoleTheme theme, PropertyToken token, MessageTemplate outputTemplate, IFormatProvider? formatProvider) - { - _outputTemplate = outputTemplate; - _theme = theme ?? throw new ArgumentNullException(nameof(theme)); - _token = token ?? throw new ArgumentNullException(nameof(token)); + public PropertiesTokenRenderer(ConsoleTheme theme, PropertyToken token, MessageTemplate outputTemplate, IFormatProvider? formatProvider) + { + _outputTemplate = outputTemplate; + _theme = theme ?? throw new ArgumentNullException(nameof(theme)); + _token = token ?? throw new ArgumentNullException(nameof(token)); - var isJson = false; + var isJson = false; - if (token.Format != null) + if (token.Format != null) + { + for (var i = 0; i < token.Format.Length; ++i) { - for (var i = 0; i < token.Format.Length; ++i) - { - if (token.Format[i] == 'j') - isJson = true; - } + if (token.Format[i] == 'j') + isJson = true; } - - _valueFormatter = isJson - ? (ThemedValueFormatter)new ThemedJsonValueFormatter(theme, formatProvider) - : new ThemedDisplayValueFormatter(theme, formatProvider); } - public override void Render(LogEvent logEvent, TextWriter output) - { - var included = logEvent.Properties - .Where(p => !TemplateContainsPropertyName(logEvent.MessageTemplate, p.Key) && - !TemplateContainsPropertyName(_outputTemplate, p.Key)) - .Select(p => new LogEventProperty(p.Key, p.Value)); + _valueFormatter = isJson + ? (ThemedValueFormatter)new ThemedJsonValueFormatter(theme, formatProvider) + : new ThemedDisplayValueFormatter(theme, formatProvider); + } - var value = new StructureValue(included); + public override void Render(LogEvent logEvent, TextWriter output) + { + var included = logEvent.Properties + .Where(p => !TemplateContainsPropertyName(logEvent.MessageTemplate, p.Key) && + !TemplateContainsPropertyName(_outputTemplate, p.Key)) + .Select(p => new LogEventProperty(p.Key, p.Value)); - if (_token.Alignment is null || !_theme.CanBuffer) - { - _valueFormatter.Format(value, output, null); - return; - } + var value = new StructureValue(included); - var buffer = new StringWriter(new StringBuilder(value.Properties.Count * 16)); - var invisible = _valueFormatter.Format(value, buffer, null); - var str = buffer.ToString(); - Padding.Apply(output, str, _token.Alignment.Value.Widen(invisible)); + if (_token.Alignment is null || !_theme.CanBuffer) + { + _valueFormatter.Format(value, output, null); + return; } - static bool TemplateContainsPropertyName(MessageTemplate template, string propertyName) + var buffer = new StringWriter(new StringBuilder(value.Properties.Count * 16)); + var invisible = _valueFormatter.Format(value, buffer, null); + var str = buffer.ToString(); + Padding.Apply(output, str, _token.Alignment.Value.Widen(invisible)); + } + + static bool TemplateContainsPropertyName(MessageTemplate template, string propertyName) + { + foreach (var token in template.Tokens) { - foreach (var token in template.Tokens) + if (token is PropertyToken namedProperty && + namedProperty.PropertyName == propertyName) { - if (token is PropertyToken namedProperty && - namedProperty.PropertyName == propertyName) - { - return true; - } + return true; } - - return false; } + + return false; } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TextTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TextTokenRenderer.cs index 1394964..e638524 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TextTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TextTokenRenderer.cs @@ -12,28 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; using Serilog.Events; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class TextTokenRenderer : OutputTemplateTokenRenderer { - class TextTokenRenderer : OutputTemplateTokenRenderer - { - readonly ConsoleTheme _theme; - readonly string _text; + readonly ConsoleTheme _theme; + readonly string _text; - public TextTokenRenderer(ConsoleTheme theme, string text) - { - _theme = theme; - _text = text; - } + public TextTokenRenderer(ConsoleTheme theme, string text) + { + _theme = theme; + _text = text; + } - public override void Render(LogEvent logEvent, TextWriter output) - { - var _ = 0; - using (_theme.Apply(output, ConsoleThemeStyle.TertiaryText, ref _)) - output.Write(_text); - } + public override void Render(LogEvent logEvent, TextWriter output) + { + var _ = 0; + using (_theme.Apply(output, ConsoleThemeStyle.TertiaryText, ref _)) + output.Write(_text); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs index bc5f000..4dc8bf1 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs @@ -12,78 +12,75 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using System.Globalization; -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Rendering; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Output +namespace Serilog.Sinks.SystemConsole.Output; + +class TimestampTokenRenderer : OutputTemplateTokenRenderer { - class TimestampTokenRenderer : OutputTemplateTokenRenderer + readonly ConsoleTheme _theme; + readonly PropertyToken _token; + readonly IFormatProvider? _formatProvider; + + public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) { - readonly ConsoleTheme _theme; - readonly PropertyToken _token; - readonly IFormatProvider? _formatProvider; + _theme = theme; + _token = token; + _formatProvider = formatProvider; + } - public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) - { - _theme = theme; - _token = token; - _formatProvider = formatProvider; - } + public override void Render(LogEvent logEvent, TextWriter output) + { + var sv = new DateTimeOffsetValue(logEvent.Timestamp); - public override void Render(LogEvent logEvent, TextWriter output) + var _ = 0; + using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) { - var sv = new DateTimeOffsetValue(logEvent.Timestamp); - - var _ = 0; - using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) + if (_token.Alignment is null) { - if (_token.Alignment is null) - { - sv.Render(output, _token.Format, _formatProvider); - } - else - { - var buffer = new StringWriter(); - sv.Render(buffer, _token.Format, _formatProvider); - var str = buffer.ToString(); - Padding.Apply(output, str, _token.Alignment); - } + sv.Render(output, _token.Format, _formatProvider); + } + else + { + var buffer = new StringWriter(); + sv.Render(buffer, _token.Format, _formatProvider); + var str = buffer.ToString(); + Padding.Apply(output, str, _token.Alignment); } } + } - readonly struct DateTimeOffsetValue + readonly struct DateTimeOffsetValue + { + public DateTimeOffsetValue(DateTimeOffset value) { - public DateTimeOffsetValue(DateTimeOffset value) - { - Value = value; - } + Value = value; + } - public DateTimeOffset Value { get; } + public DateTimeOffset Value { get; } - public void Render(TextWriter output, string? format = null, IFormatProvider? formatProvider = null) + public void Render(TextWriter output, string? format = null, IFormatProvider? formatProvider = null) + { + var custom = (ICustomFormatter?)formatProvider?.GetFormat(typeof(ICustomFormatter)); + if (custom != null) { - var custom = (ICustomFormatter?)formatProvider?.GetFormat(typeof(ICustomFormatter)); - if (custom != null) - { - output.Write(custom.Format(format, Value, formatProvider)); - return; - } + output.Write(custom.Format(format, Value, formatProvider)); + return; + } #if FEATURE_SPAN - Span buffer = stackalloc char[32]; - if (Value.TryFormat(buffer, out int written, format, formatProvider ?? CultureInfo.InvariantCulture)) - output.Write(buffer.Slice(0, written)); - else - output.Write(Value.ToString(format, formatProvider ?? CultureInfo.InvariantCulture)); -#else + Span buffer = stackalloc char[32]; + if (Value.TryFormat(buffer, out int written, format, formatProvider ?? CultureInfo.InvariantCulture)) + output.Write(buffer.Slice(0, written)); + else output.Write(Value.ToString(format, formatProvider ?? CultureInfo.InvariantCulture)); +#else + output.Write(Value.ToString(format, formatProvider ?? CultureInfo.InvariantCulture)); #endif - } } } } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Platform/WindowsConsole.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Platform/WindowsConsole.cs index fce3ecf..926cf30 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Platform/WindowsConsole.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Platform/WindowsConsole.cs @@ -12,40 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using System.Runtime.InteropServices; -namespace Serilog.Sinks.SystemConsole.Platform +namespace Serilog.Sinks.SystemConsole.Platform; + +static class WindowsConsole { - static class WindowsConsole + public static void EnableVirtualTerminalProcessing() { - public static void EnableVirtualTerminalProcessing() - { #if RUNTIME_INFORMATION - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return; + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return; #else - if (Environment.OSVersion.Platform != PlatformID.Win32NT) - return; + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + return; #endif - var stdout = GetStdHandle(StandardOutputHandleId); - if (stdout != (IntPtr)InvalidHandleValue && GetConsoleMode(stdout, out var mode)) - { - SetConsoleMode(stdout, mode | EnableVirtualTerminalProcessingMode); - } + var stdout = GetStdHandle(StandardOutputHandleId); + if (stdout != (IntPtr)InvalidHandleValue && GetConsoleMode(stdout, out var mode)) + { + SetConsoleMode(stdout, mode | EnableVirtualTerminalProcessingMode); } + } - const int StandardOutputHandleId = -11; - const uint EnableVirtualTerminalProcessingMode = 4; - const long InvalidHandleValue = -1; + const int StandardOutputHandleId = -11; + const uint EnableVirtualTerminalProcessingMode = 4; + const long InvalidHandleValue = -1; - [DllImport("kernel32.dll", SetLastError = true)] - static extern IntPtr GetStdHandle(int handleId); + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr GetStdHandle(int handleId); - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool GetConsoleMode(IntPtr handle, out uint mode); + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool GetConsoleMode(IntPtr handle, out uint mode); - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool SetConsoleMode(IntPtr handle, uint mode); - } + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool SetConsoleMode(IntPtr handle, uint mode); } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/AlignmentExtensions.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/AlignmentExtensions.cs index 6964274..bb6a70d 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/AlignmentExtensions.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/AlignmentExtensions.cs @@ -14,13 +14,12 @@ using Serilog.Parsing; -namespace Serilog.Sinks.SystemConsole.Rendering +namespace Serilog.Sinks.SystemConsole.Rendering; + +static class AlignmentExtensions { - static class AlignmentExtensions + public static Alignment Widen(this Alignment alignment, int amount) { - public static Alignment Widen(this Alignment alignment, int amount) - { - return new Alignment(alignment.Direction, alignment.Width + amount); - } + return new Alignment(alignment.Direction, alignment.Width + amount); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Casing.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Casing.cs index 66ce179..e44b40d 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Casing.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Casing.cs @@ -1,4 +1,4 @@ -// Copyright 2013-2017 Serilog Contributors +// Copyright 2013-2017 Serilog Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,28 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -namespace Serilog.Sinks.SystemConsole.Rendering +namespace Serilog.Sinks.SystemConsole.Rendering; + +static class Casing { - static class Casing + /// + /// Apply upper or lower casing to when is provided. + /// Returns when no or invalid format provided. + /// + /// Provided string for formatting. + /// Format string. + /// The provided with formatting applied. + public static string Format(string value, string? format = null) { - /// - /// Apply upper or lower casing to when is provided. - /// Returns when no or invalid format provided. - /// - /// Provided string for formatting. - /// Format string. - /// The provided with formatting applied. - public static string Format(string value, string? format = null) + return format switch { - switch (format) - { - case "u": - return value.ToUpperInvariant(); - case "w": - return value.ToLowerInvariant(); - default: - return value; - } - } + "u" => value.ToUpperInvariant(), + "w" => value.ToLowerInvariant(), + _ => value, + }; } -} \ No newline at end of file +} diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Padding.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Padding.cs index 12d2595..d3041e4 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Padding.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/Padding.cs @@ -12,45 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; using Serilog.Parsing; -namespace Serilog.Sinks.SystemConsole.Rendering +namespace Serilog.Sinks.SystemConsole.Rendering; + +static class Padding { - static class Padding + static readonly char[] PaddingChars = new string(' ', 80).ToCharArray(); + + /// + /// Writes the provided value to the output, applying direction-based padding when is provided. + /// + /// Output object to write result. + /// Provided value. + /// The alignment settings to apply when rendering . + public static void Apply(TextWriter output, string value, Alignment? alignment) { - static readonly char[] PaddingChars = new string(' ', 80).ToCharArray(); - - /// - /// Writes the provided value to the output, applying direction-based padding when is provided. - /// - /// Output object to write result. - /// Provided value. - /// The alignment settings to apply when rendering . - public static void Apply(TextWriter output, string value, Alignment? alignment) + if (alignment is null || value.Length >= alignment.Value.Width) + { + output.Write(value); + return; + } + + var pad = alignment.Value.Width - value.Length; + + if (alignment.Value.Direction == AlignmentDirection.Left) + output.Write(value); + + if (pad <= PaddingChars.Length) { - if (alignment is null || value.Length >= alignment.Value.Width) - { - output.Write(value); - return; - } - - var pad = alignment.Value.Width - value.Length; - - if (alignment.Value.Direction == AlignmentDirection.Left) - output.Write(value); - - if (pad <= PaddingChars.Length) - { - output.Write(PaddingChars, 0, pad); - } - else - { - output.Write(new string(' ', pad)); - } - - if (alignment.Value.Direction == AlignmentDirection.Right) - output.Write(value); + output.Write(PaddingChars, 0, pad); } + else + { + output.Write(new string(' ', pad)); + } + + if (alignment.Value.Direction == AlignmentDirection.Right) + output.Write(value); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/ThemedMessageTemplateRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/ThemedMessageTemplateRenderer.cs index a299520..839bf97 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/ThemedMessageTemplateRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Rendering/ThemedMessageTemplateRenderer.cs @@ -12,129 +12,125 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.Collections.Generic; -using System.IO; using Serilog.Events; using Serilog.Parsing; using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Rendering +namespace Serilog.Sinks.SystemConsole.Rendering; + +class ThemedMessageTemplateRenderer { - class ThemedMessageTemplateRenderer - { - readonly ConsoleTheme _theme; - readonly ThemedValueFormatter _valueFormatter; - readonly bool _isLiteral; - static readonly ConsoleTheme NoTheme = new EmptyConsoleTheme(); - readonly ThemedValueFormatter _unthemedValueFormatter; + readonly ConsoleTheme _theme; + readonly ThemedValueFormatter _valueFormatter; + readonly bool _isLiteral; + static readonly ConsoleTheme NoTheme = new EmptyConsoleTheme(); + readonly ThemedValueFormatter _unthemedValueFormatter; - public ThemedMessageTemplateRenderer(ConsoleTheme theme, ThemedValueFormatter valueFormatter, bool isLiteral) - { - _theme = theme ?? throw new ArgumentNullException(nameof(theme)); - _valueFormatter = valueFormatter; - _isLiteral = isLiteral; - _unthemedValueFormatter = valueFormatter.SwitchTheme(NoTheme); - } + public ThemedMessageTemplateRenderer(ConsoleTheme theme, ThemedValueFormatter valueFormatter, bool isLiteral) + { + _theme = theme ?? throw new ArgumentNullException(nameof(theme)); + _valueFormatter = valueFormatter; + _isLiteral = isLiteral; + _unthemedValueFormatter = valueFormatter.SwitchTheme(NoTheme); + } - public int Render(MessageTemplate template, IReadOnlyDictionary properties, TextWriter output) + public int Render(MessageTemplate template, IReadOnlyDictionary properties, TextWriter output) + { + var count = 0; + foreach (var token in template.Tokens) { - var count = 0; - foreach (var token in template.Tokens) + if (token is TextToken tt) { - if (token is TextToken tt) - { - count += RenderTextToken(tt, output); - } - else - { - var pt = (PropertyToken)token; - count += RenderPropertyToken(pt, properties, output); - } + count += RenderTextToken(tt, output); + } + else + { + var pt = (PropertyToken)token; + count += RenderPropertyToken(pt, properties, output); } - return count; } + return count; + } - int RenderTextToken(TextToken tt, TextWriter output) + int RenderTextToken(TextToken tt, TextWriter output) + { + var count = 0; + using (_theme.Apply(output, ConsoleThemeStyle.Text, ref count)) + output.Write(tt.Text); + return count; + } + + int RenderPropertyToken(PropertyToken pt, IReadOnlyDictionary properties, TextWriter output) + { + if (!properties.TryGetValue(pt.PropertyName, out var propertyValue)) { var count = 0; - using (_theme.Apply(output, ConsoleThemeStyle.Text, ref count)) - output.Write(tt.Text); + using (_theme.Apply(output, ConsoleThemeStyle.Invalid, ref count)) + output.Write(pt.ToString()); return count; } - int RenderPropertyToken(PropertyToken pt, IReadOnlyDictionary properties, TextWriter output) + if (!pt.Alignment.HasValue) { - if (!properties.TryGetValue(pt.PropertyName, out var propertyValue)) - { - var count = 0; - using (_theme.Apply(output, ConsoleThemeStyle.Invalid, ref count)) - output.Write(pt.ToString()); - return count; - } - - if (!pt.Alignment.HasValue) - { - return RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); - } - - var valueOutput = new StringWriter(); + return RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); + } - if (!_theme.CanBuffer) - return RenderAlignedPropertyTokenUnbuffered(pt, output, propertyValue); + var valueOutput = new StringWriter(); - var invisibleCount = RenderValue(_theme, _valueFormatter, propertyValue, valueOutput, pt.Format); + if (!_theme.CanBuffer) + return RenderAlignedPropertyTokenUnbuffered(pt, output, propertyValue); - var value = valueOutput.ToString(); + var invisibleCount = RenderValue(_theme, _valueFormatter, propertyValue, valueOutput, pt.Format); - if (value.Length - invisibleCount >= pt.Alignment.Value.Width) - { - output.Write(value); - } - else - { - Padding.Apply(output, value, pt.Alignment.Value.Widen(invisibleCount)); - } + var value = valueOutput.ToString(); - return invisibleCount; + if (value.Length - invisibleCount >= pt.Alignment.Value.Width) + { + output.Write(value); } - - int RenderAlignedPropertyTokenUnbuffered(PropertyToken pt, TextWriter output, LogEventPropertyValue propertyValue) + else { - if (pt.Alignment == null) throw new ArgumentException("The PropertyToken should have a non-null Alignment.", nameof(pt)); + Padding.Apply(output, value, pt.Alignment.Value.Widen(invisibleCount)); + } - var valueOutput = new StringWriter(); - RenderValue(NoTheme, _unthemedValueFormatter, propertyValue, valueOutput, pt.Format); + return invisibleCount; + } - var valueLength = valueOutput.ToString().Length; - if (valueLength >= pt.Alignment.Value.Width) - { - return RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); - } + int RenderAlignedPropertyTokenUnbuffered(PropertyToken pt, TextWriter output, LogEventPropertyValue propertyValue) + { + if (pt.Alignment == null) throw new ArgumentException("The PropertyToken should have a non-null Alignment.", nameof(pt)); - if (pt.Alignment.Value.Direction == AlignmentDirection.Left) - { - var invisible = RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); - Padding.Apply(output, string.Empty, pt.Alignment.Value.Widen(-valueLength)); - return invisible; - } + var valueOutput = new StringWriter(); + RenderValue(NoTheme, _unthemedValueFormatter, propertyValue, valueOutput, pt.Format); - Padding.Apply(output, string.Empty, pt.Alignment.Value.Widen(-valueLength)); + var valueLength = valueOutput.ToString().Length; + if (valueLength >= pt.Alignment.Value.Width) + { return RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); } - int RenderValue(ConsoleTheme theme, ThemedValueFormatter valueFormatter, LogEventPropertyValue propertyValue, TextWriter output, string? format) + if (pt.Alignment.Value.Direction == AlignmentDirection.Left) { - if (_isLiteral && propertyValue is ScalarValue sv && sv.Value is string) - { - var count = 0; - using (theme.Apply(output, ConsoleThemeStyle.String, ref count)) - output.Write(sv.Value); - return count; - } + var invisible = RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); + Padding.Apply(output, string.Empty, pt.Alignment.Value.Widen(-valueLength)); + return invisible; + } - return valueFormatter.Format(propertyValue, output, format, _isLiteral); + Padding.Apply(output, string.Empty, pt.Alignment.Value.Widen(-valueLength)); + return RenderValue(_theme, _valueFormatter, propertyValue, output, pt.Format); + } + + int RenderValue(ConsoleTheme theme, ThemedValueFormatter valueFormatter, LogEventPropertyValue propertyValue, TextWriter output, string? format) + { + if (_isLiteral && propertyValue is ScalarValue sv && sv.Value is string) + { + var count = 0; + using (theme.Apply(output, ConsoleThemeStyle.String, ref count)) + output.Write(sv.Value); + return count; } + + return valueFormatter.Format(propertyValue, output, format, _isLiteral); } } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleTheme.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleTheme.cs index c37942b..c9a676a 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleTheme.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleTheme.cs @@ -12,74 +12,68 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +/// +/// A console theme using the ANSI terminal escape sequences. Recommended +/// for Linux and Windows 10+. +/// +public class AnsiConsoleTheme : ConsoleTheme { /// - /// A console theme using the ANSI terminal escape sequences. Recommended - /// for Linux and Windows 10+. + /// A 256-color theme along the lines of Visual Studio Code. /// - public class AnsiConsoleTheme : ConsoleTheme - { - /// - /// A 256-color theme along the lines of Visual Studio Code. - /// - public static AnsiConsoleTheme Code { get; } = AnsiConsoleThemes.Code; + public static AnsiConsoleTheme Code { get; } = AnsiConsoleThemes.Code; - /// - /// A theme using only gray, black and white. - /// - public static AnsiConsoleTheme Grayscale { get; } = AnsiConsoleThemes.Grayscale; + /// + /// A theme using only gray, black and white. + /// + public static AnsiConsoleTheme Grayscale { get; } = AnsiConsoleThemes.Grayscale; - /// - /// A theme in the style of the original Serilog.Sinks.Literate. - /// - public static AnsiConsoleTheme Literate { get; } = AnsiConsoleThemes.Literate; + /// + /// A theme in the style of the original Serilog.Sinks.Literate. + /// + public static AnsiConsoleTheme Literate { get; } = AnsiConsoleThemes.Literate; - /// - /// A theme in the style of the original Serilog.Sinks.Literate using only standard 16 terminal colors that will work on light backgrounds. - /// - public static AnsiConsoleTheme Sixteen { get; } = AnsiConsoleThemes.Sixteen; + /// + /// A theme in the style of the original Serilog.Sinks.Literate using only standard 16 terminal colors that will work on light backgrounds. + /// + public static AnsiConsoleTheme Sixteen { get; } = AnsiConsoleThemes.Sixteen; - readonly IReadOnlyDictionary _styles; - const string AnsiStyleReset = "\x1b[0m"; + readonly IReadOnlyDictionary _styles; + const string AnsiStyleReset = "\x1b[0m"; - /// - /// Construct a theme given a set of styles. - /// - /// Styles to apply within the theme. - /// When is null - public AnsiConsoleTheme(IReadOnlyDictionary styles) - { - if (styles is null) throw new ArgumentNullException(nameof(styles)); - _styles = styles.ToDictionary(kv => kv.Key, kv => kv.Value); - } + /// + /// Construct a theme given a set of styles. + /// + /// Styles to apply within the theme. + /// When is null + public AnsiConsoleTheme(IReadOnlyDictionary styles) + { + if (styles is null) throw new ArgumentNullException(nameof(styles)); + _styles = styles.ToDictionary(kv => kv.Key, kv => kv.Value); + } - /// - public override bool CanBuffer => true; + /// + public override bool CanBuffer => true; - /// - protected override int ResetCharCount { get; } = AnsiStyleReset.Length; + /// + protected override int ResetCharCount { get; } = AnsiStyleReset.Length; - /// - public override int Set(TextWriter output, ConsoleThemeStyle style) + /// + public override int Set(TextWriter output, ConsoleThemeStyle style) + { + if (_styles.TryGetValue(style, out var ansiStyle)) { - if (_styles.TryGetValue(style, out var ansiStyle)) - { - output.Write(ansiStyle); - return ansiStyle.Length; - } - return 0; + output.Write(ansiStyle); + return ansiStyle.Length; } + return 0; + } - /// - public override void Reset(TextWriter output) - { - output.Write(AnsiStyleReset); - } + /// + public override void Reset(TextWriter output) + { + output.Write(AnsiStyleReset); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleThemes.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleThemes.cs index 1728aa0..0f0d6ea 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleThemes.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiConsoleThemes.cs @@ -12,94 +12,91 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.Collections.Generic; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +static class AnsiConsoleThemes { - static class AnsiConsoleThemes - { - public static AnsiConsoleTheme Literate { get; } = new AnsiConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = "\x1b[38;5;0015m", - [ConsoleThemeStyle.SecondaryText] = "\x1b[38;5;0007m", - [ConsoleThemeStyle.TertiaryText] = "\x1b[38;5;0008m", - [ConsoleThemeStyle.Invalid] = "\x1b[38;5;0011m", - [ConsoleThemeStyle.Null] = "\x1b[38;5;0027m", - [ConsoleThemeStyle.Name] = "\x1b[38;5;0007m", - [ConsoleThemeStyle.String] = "\x1b[38;5;0045m", - [ConsoleThemeStyle.Number] = "\x1b[38;5;0200m", - [ConsoleThemeStyle.Boolean] = "\x1b[38;5;0027m", - [ConsoleThemeStyle.Scalar] = "\x1b[38;5;0085m", - [ConsoleThemeStyle.LevelVerbose] = "\x1b[38;5;0007m", - [ConsoleThemeStyle.LevelDebug] = "\x1b[38;5;0007m", - [ConsoleThemeStyle.LevelInformation] = "\x1b[38;5;0015m", - [ConsoleThemeStyle.LevelWarning] = "\x1b[38;5;0011m", - [ConsoleThemeStyle.LevelError] = "\x1b[38;5;0015m\x1b[48;5;0196m", - [ConsoleThemeStyle.LevelFatal] = "\x1b[38;5;0015m\x1b[48;5;0196m", - }); + public static AnsiConsoleTheme Literate { get; } = new AnsiConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = "\x1b[38;5;0015m", + [ConsoleThemeStyle.SecondaryText] = "\x1b[38;5;0007m", + [ConsoleThemeStyle.TertiaryText] = "\x1b[38;5;0008m", + [ConsoleThemeStyle.Invalid] = "\x1b[38;5;0011m", + [ConsoleThemeStyle.Null] = "\x1b[38;5;0027m", + [ConsoleThemeStyle.Name] = "\x1b[38;5;0007m", + [ConsoleThemeStyle.String] = "\x1b[38;5;0045m", + [ConsoleThemeStyle.Number] = "\x1b[38;5;0200m", + [ConsoleThemeStyle.Boolean] = "\x1b[38;5;0027m", + [ConsoleThemeStyle.Scalar] = "\x1b[38;5;0085m", + [ConsoleThemeStyle.LevelVerbose] = "\x1b[38;5;0007m", + [ConsoleThemeStyle.LevelDebug] = "\x1b[38;5;0007m", + [ConsoleThemeStyle.LevelInformation] = "\x1b[38;5;0015m", + [ConsoleThemeStyle.LevelWarning] = "\x1b[38;5;0011m", + [ConsoleThemeStyle.LevelError] = "\x1b[38;5;0015m\x1b[48;5;0196m", + [ConsoleThemeStyle.LevelFatal] = "\x1b[38;5;0015m\x1b[48;5;0196m", + }); - public static AnsiConsoleTheme Grayscale { get; } = new AnsiConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = "\x1b[37;1m", - [ConsoleThemeStyle.SecondaryText] = "\x1b[37m", - [ConsoleThemeStyle.TertiaryText] = "\x1b[30;1m", - [ConsoleThemeStyle.Invalid] = "\x1b[37;1m\x1b[47m", - [ConsoleThemeStyle.Null] = "\x1b[1m\x1b[37;1m", - [ConsoleThemeStyle.Name] = "\x1b[37m", - [ConsoleThemeStyle.String] = "\x1b[1m\x1b[37;1m", - [ConsoleThemeStyle.Number] = "\x1b[1m\x1b[37;1m", - [ConsoleThemeStyle.Boolean] = "\x1b[1m\x1b[37;1m", - [ConsoleThemeStyle.Scalar] = "\x1b[1m\x1b[37;1m", - [ConsoleThemeStyle.LevelVerbose] = "\x1b[30;1m", - [ConsoleThemeStyle.LevelDebug] = "\x1b[30;1m", - [ConsoleThemeStyle.LevelInformation] = "\x1b[37;1m", - [ConsoleThemeStyle.LevelWarning] = "\x1b[37;1m\x1b[47m", - [ConsoleThemeStyle.LevelError] = "\x1b[30m\x1b[47m", - [ConsoleThemeStyle.LevelFatal] = "\x1b[30m\x1b[47m", - }); + public static AnsiConsoleTheme Grayscale { get; } = new AnsiConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = "\x1b[37;1m", + [ConsoleThemeStyle.SecondaryText] = "\x1b[37m", + [ConsoleThemeStyle.TertiaryText] = "\x1b[30;1m", + [ConsoleThemeStyle.Invalid] = "\x1b[37;1m\x1b[47m", + [ConsoleThemeStyle.Null] = "\x1b[1m\x1b[37;1m", + [ConsoleThemeStyle.Name] = "\x1b[37m", + [ConsoleThemeStyle.String] = "\x1b[1m\x1b[37;1m", + [ConsoleThemeStyle.Number] = "\x1b[1m\x1b[37;1m", + [ConsoleThemeStyle.Boolean] = "\x1b[1m\x1b[37;1m", + [ConsoleThemeStyle.Scalar] = "\x1b[1m\x1b[37;1m", + [ConsoleThemeStyle.LevelVerbose] = "\x1b[30;1m", + [ConsoleThemeStyle.LevelDebug] = "\x1b[30;1m", + [ConsoleThemeStyle.LevelInformation] = "\x1b[37;1m", + [ConsoleThemeStyle.LevelWarning] = "\x1b[37;1m\x1b[47m", + [ConsoleThemeStyle.LevelError] = "\x1b[30m\x1b[47m", + [ConsoleThemeStyle.LevelFatal] = "\x1b[30m\x1b[47m", + }); - public static AnsiConsoleTheme Code { get; } = new AnsiConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = "\x1b[38;5;0253m", - [ConsoleThemeStyle.SecondaryText] = "\x1b[38;5;0246m", - [ConsoleThemeStyle.TertiaryText] = "\x1b[38;5;0242m", - [ConsoleThemeStyle.Invalid] = "\x1b[33;1m", - [ConsoleThemeStyle.Null] = "\x1b[38;5;0038m", - [ConsoleThemeStyle.Name] = "\x1b[38;5;0081m", - [ConsoleThemeStyle.String] = "\x1b[38;5;0216m", - [ConsoleThemeStyle.Number] = "\x1b[38;5;151m", - [ConsoleThemeStyle.Boolean] = "\x1b[38;5;0038m", - [ConsoleThemeStyle.Scalar] = "\x1b[38;5;0079m", - [ConsoleThemeStyle.LevelVerbose] = "\x1b[37m", - [ConsoleThemeStyle.LevelDebug] = "\x1b[37m", - [ConsoleThemeStyle.LevelInformation] = "\x1b[37;1m", - [ConsoleThemeStyle.LevelWarning] = "\x1b[38;5;0229m", - [ConsoleThemeStyle.LevelError] = "\x1b[38;5;0197m\x1b[48;5;0238m", - [ConsoleThemeStyle.LevelFatal] = "\x1b[38;5;0197m\x1b[48;5;0238m", - }); + public static AnsiConsoleTheme Code { get; } = new AnsiConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = "\x1b[38;5;0253m", + [ConsoleThemeStyle.SecondaryText] = "\x1b[38;5;0246m", + [ConsoleThemeStyle.TertiaryText] = "\x1b[38;5;0242m", + [ConsoleThemeStyle.Invalid] = "\x1b[33;1m", + [ConsoleThemeStyle.Null] = "\x1b[38;5;0038m", + [ConsoleThemeStyle.Name] = "\x1b[38;5;0081m", + [ConsoleThemeStyle.String] = "\x1b[38;5;0216m", + [ConsoleThemeStyle.Number] = "\x1b[38;5;151m", + [ConsoleThemeStyle.Boolean] = "\x1b[38;5;0038m", + [ConsoleThemeStyle.Scalar] = "\x1b[38;5;0079m", + [ConsoleThemeStyle.LevelVerbose] = "\x1b[37m", + [ConsoleThemeStyle.LevelDebug] = "\x1b[37m", + [ConsoleThemeStyle.LevelInformation] = "\x1b[37;1m", + [ConsoleThemeStyle.LevelWarning] = "\x1b[38;5;0229m", + [ConsoleThemeStyle.LevelError] = "\x1b[38;5;0197m\x1b[48;5;0238m", + [ConsoleThemeStyle.LevelFatal] = "\x1b[38;5;0197m\x1b[48;5;0238m", + }); - public static AnsiConsoleTheme Sixteen { get; } = new AnsiConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = AnsiEscapeSequence.Unthemed, - [ConsoleThemeStyle.SecondaryText] = AnsiEscapeSequence.Unthemed, - [ConsoleThemeStyle.TertiaryText] = AnsiEscapeSequence.Unthemed, - [ConsoleThemeStyle.Invalid] = AnsiEscapeSequence.Yellow, - [ConsoleThemeStyle.Null] = AnsiEscapeSequence.Blue, - [ConsoleThemeStyle.Name] = AnsiEscapeSequence.Unthemed, - [ConsoleThemeStyle.String] = AnsiEscapeSequence.Cyan, - [ConsoleThemeStyle.Number] = AnsiEscapeSequence.Magenta, - [ConsoleThemeStyle.Boolean] = AnsiEscapeSequence.Blue, - [ConsoleThemeStyle.Scalar] = AnsiEscapeSequence.Green, - [ConsoleThemeStyle.LevelVerbose] = AnsiEscapeSequence.Unthemed, - [ConsoleThemeStyle.LevelDebug] = AnsiEscapeSequence.Bold, - [ConsoleThemeStyle.LevelInformation] = AnsiEscapeSequence.BrightCyan, - [ConsoleThemeStyle.LevelWarning] = AnsiEscapeSequence.BrightYellow, - [ConsoleThemeStyle.LevelError] = AnsiEscapeSequence.BrightRed, - [ConsoleThemeStyle.LevelFatal] = AnsiEscapeSequence.BrightRed, - }); - } + public static AnsiConsoleTheme Sixteen { get; } = new AnsiConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = AnsiEscapeSequence.Unthemed, + [ConsoleThemeStyle.SecondaryText] = AnsiEscapeSequence.Unthemed, + [ConsoleThemeStyle.TertiaryText] = AnsiEscapeSequence.Unthemed, + [ConsoleThemeStyle.Invalid] = AnsiEscapeSequence.Yellow, + [ConsoleThemeStyle.Null] = AnsiEscapeSequence.Blue, + [ConsoleThemeStyle.Name] = AnsiEscapeSequence.Unthemed, + [ConsoleThemeStyle.String] = AnsiEscapeSequence.Cyan, + [ConsoleThemeStyle.Number] = AnsiEscapeSequence.Magenta, + [ConsoleThemeStyle.Boolean] = AnsiEscapeSequence.Blue, + [ConsoleThemeStyle.Scalar] = AnsiEscapeSequence.Green, + [ConsoleThemeStyle.LevelVerbose] = AnsiEscapeSequence.Unthemed, + [ConsoleThemeStyle.LevelDebug] = AnsiEscapeSequence.Bold, + [ConsoleThemeStyle.LevelInformation] = AnsiEscapeSequence.BrightCyan, + [ConsoleThemeStyle.LevelWarning] = AnsiEscapeSequence.BrightYellow, + [ConsoleThemeStyle.LevelError] = AnsiEscapeSequence.BrightRed, + [ConsoleThemeStyle.LevelFatal] = AnsiEscapeSequence.BrightRed, + }); } diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiEscapeSequence.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiEscapeSequence.cs index 2512190..2e29d53 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiEscapeSequence.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/AnsiEscapeSequence.cs @@ -12,30 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -namespace Serilog.Sinks.SystemConsole.Themes +namespace Serilog.Sinks.SystemConsole.Themes; + +static class AnsiEscapeSequence { - static class AnsiEscapeSequence - { - public const string Unthemed = ""; - public const string Reset = "\x1b[0m"; - public const string Bold = "\x1b[1m"; + public const string Unthemed = ""; + public const string Reset = "\x1b[0m"; + public const string Bold = "\x1b[1m"; - public const string Black = "\x1b[30m"; - public const string Red = "\x1b[31m"; - public const string Green = "\x1b[32m"; - public const string Yellow = "\x1b[33m"; - public const string Blue = "\x1b[34m"; - public const string Magenta = "\x1b[35m"; - public const string Cyan = "\x1b[36m"; - public const string White = "\x1b[37m"; + public const string Black = "\x1b[30m"; + public const string Red = "\x1b[31m"; + public const string Green = "\x1b[32m"; + public const string Yellow = "\x1b[33m"; + public const string Blue = "\x1b[34m"; + public const string Magenta = "\x1b[35m"; + public const string Cyan = "\x1b[36m"; + public const string White = "\x1b[37m"; - public const string BrightBlack = "\x1b[30;1m"; - public const string BrightRed = "\x1b[31;1m"; - public const string BrightGreen = "\x1b[32;1m"; - public const string BrightYellow = "\x1b[33;1m"; - public const string BrightBlue = "\x1b[34;1m"; - public const string BrightMagenta = "\x1b[35;1m"; - public const string BrightCyan = "\x1b[36;1m"; - public const string BrightWhite = "\x1b[37;1m"; - } + public const string BrightBlack = "\x1b[30;1m"; + public const string BrightRed = "\x1b[31;1m"; + public const string BrightGreen = "\x1b[32;1m"; + public const string BrightYellow = "\x1b[33;1m"; + public const string BrightBlue = "\x1b[34;1m"; + public const string BrightMagenta = "\x1b[35;1m"; + public const string BrightCyan = "\x1b[36;1m"; + public const string BrightWhite = "\x1b[37;1m"; } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleTheme.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleTheme.cs index b3921bf..520bda3 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleTheme.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleTheme.cs @@ -12,51 +12,48 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +/// +/// The base class for styled terminal output. +/// +public abstract class ConsoleTheme { /// - /// The base class for styled terminal output. + /// No styling applied. /// - public abstract class ConsoleTheme + public static ConsoleTheme None { get; } = new EmptyConsoleTheme(); + + /// + /// True if styling applied by the theme is written into the output, and can thus be + /// buffered and measured. + /// + public abstract bool CanBuffer { get; } + + /// + /// Begin a span of text in the specified . + /// + /// Output destination. + /// Style to apply. + /// The number of characters written to . + public abstract int Set(TextWriter output, ConsoleThemeStyle style); + + /// + /// Reset the output to un-styled colors. + /// + /// Output destination. + public abstract void Reset(TextWriter output); + + /// + /// The number of characters written by the method. + /// + protected abstract int ResetCharCount { get; } + + internal StyleReset Apply(TextWriter output, ConsoleThemeStyle style, ref int invisibleCharacterCount) { - /// - /// No styling applied. - /// - public static ConsoleTheme None { get; } = new EmptyConsoleTheme(); - - /// - /// True if styling applied by the theme is written into the output, and can thus be - /// buffered and measured. - /// - public abstract bool CanBuffer { get; } - - /// - /// Begin a span of text in the specified . - /// - /// Output destination. - /// Style to apply. - /// The number of characters written to . - public abstract int Set(TextWriter output, ConsoleThemeStyle style); - - /// - /// Reset the output to un-styled colors. - /// - /// Output destination. - public abstract void Reset(TextWriter output); - - /// - /// The number of characters written by the method. - /// - protected abstract int ResetCharCount { get; } - - internal StyleReset Apply(TextWriter output, ConsoleThemeStyle style, ref int invisibleCharacterCount) - { - invisibleCharacterCount += Set(output, style); - invisibleCharacterCount += ResetCharCount; - - return new StyleReset(this, output); - } + invisibleCharacterCount += Set(output, style); + invisibleCharacterCount += ResetCharCount; + + return new StyleReset(this, output); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleThemeStyle.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleThemeStyle.cs index 69d231f..39001b5 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleThemeStyle.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/ConsoleThemeStyle.cs @@ -12,103 +12,101 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using System.ComponentModel; -namespace Serilog.Sinks.SystemConsole.Themes +namespace Serilog.Sinks.SystemConsole.Themes; + +/// +/// Elements styled by a console theme. +/// +public enum ConsoleThemeStyle { /// - /// Elements styled by a console theme. - /// - public enum ConsoleThemeStyle - { - /// - /// Prominent text, generally content within an event's message. - /// - Text, - - /// - /// Boilerplate text, for example items specified in an output template. - /// - SecondaryText, - - /// - /// De-emphasized text, for example literal text in output templates and - /// punctuation used when writing structured data. - /// - TertiaryText, - - /// - /// Output demonstrating some kind of configuration issue, e.g. an invalid - /// message template token. - /// - Invalid, - - /// - /// The built-in value. - /// - Null, - - /// - /// Property and type names. - /// - Name, - - /// - /// Strings. - /// - String, - - /// - /// Numbers. - /// - Number, - - /// - /// values. - /// - Boolean, - - /// - /// All other scalar values, e.g. instances. - /// - Scalar, - - /// - /// Unrecognized literal values, e.g. instances. - /// - [Obsolete("Use ConsoleThemeStyle.Scalar instead")] - [EditorBrowsable(EditorBrowsableState.Never)] - Object = Scalar, - - /// - /// Level indicator. - /// - LevelVerbose, - - /// - /// Level indicator. - /// - LevelDebug, - - /// - /// Level indicator. - /// - LevelInformation, - - /// - /// Level indicator. - /// - LevelWarning, - - /// - /// Level indicator. - /// - LevelError, - - /// - /// Level indicator. - /// - LevelFatal, - } + /// Prominent text, generally content within an event's message. + /// + Text, + + /// + /// Boilerplate text, for example items specified in an output template. + /// + SecondaryText, + + /// + /// De-emphasized text, for example literal text in output templates and + /// punctuation used when writing structured data. + /// + TertiaryText, + + /// + /// Output demonstrating some kind of configuration issue, e.g. an invalid + /// message template token. + /// + Invalid, + + /// + /// The built-in value. + /// + Null, + + /// + /// Property and type names. + /// + Name, + + /// + /// Strings. + /// + String, + + /// + /// Numbers. + /// + Number, + + /// + /// values. + /// + Boolean, + + /// + /// All other scalar values, e.g. instances. + /// + Scalar, + + /// + /// Unrecognized literal values, e.g. instances. + /// + [Obsolete("Use ConsoleThemeStyle.Scalar instead")] + [EditorBrowsable(EditorBrowsableState.Never)] + Object = Scalar, + + /// + /// Level indicator. + /// + LevelVerbose, + + /// + /// Level indicator. + /// + LevelDebug, + + /// + /// Level indicator. + /// + LevelInformation, + + /// + /// Level indicator. + /// + LevelWarning, + + /// + /// Level indicator. + /// + LevelError, + + /// + /// Level indicator. + /// + LevelFatal, } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/EmptyConsoleTheme.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/EmptyConsoleTheme.cs index de74f8c..182de60 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/EmptyConsoleTheme.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/EmptyConsoleTheme.cs @@ -12,20 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.IO; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +class EmptyConsoleTheme : ConsoleTheme { - class EmptyConsoleTheme : ConsoleTheme - { - public override bool CanBuffer => true; + public override bool CanBuffer => true; - protected override int ResetCharCount { get; } + protected override int ResetCharCount { get; } - public override int Set(TextWriter output, ConsoleThemeStyle style) => 0; + public override int Set(TextWriter output, ConsoleThemeStyle style) => 0; - public override void Reset(TextWriter output) - { - } + public override void Reset(TextWriter output) + { } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/StyleReset.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/StyleReset.cs index a033161..4bea65b 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/StyleReset.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/StyleReset.cs @@ -12,25 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.IO; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +struct StyleReset : IDisposable { - struct StyleReset : IDisposable - { - readonly ConsoleTheme _theme; - readonly TextWriter _output; + readonly ConsoleTheme _theme; + readonly TextWriter _output; - public StyleReset(ConsoleTheme theme, TextWriter output) - { - _theme = theme; - _output = output; - } + public StyleReset(ConsoleTheme theme, TextWriter output) + { + _theme = theme; + _output = output; + } - public void Dispose() - { - _theme.Reset(_output); - } + public void Dispose() + { + _theme.Reset(_output); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleTheme.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleTheme.cs index a4518c8..c043689 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleTheme.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleTheme.cs @@ -12,72 +12,66 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +/// +/// A console theme using the styling facilities of the class. Recommended +/// for Windows versions prior to Windows 10. +/// +public class SystemConsoleTheme : ConsoleTheme { /// - /// A console theme using the styling facilities of the class. Recommended - /// for Windows versions prior to Windows 10. + /// A theme using only gray, black and white. /// - public class SystemConsoleTheme : ConsoleTheme - { - /// - /// A theme using only gray, black and white. - /// - public static SystemConsoleTheme Grayscale { get; } = SystemConsoleThemes.Grayscale; + public static SystemConsoleTheme Grayscale { get; } = SystemConsoleThemes.Grayscale; - /// - /// A theme in the style of the original Serilog.Sinks.Literate. - /// - public static SystemConsoleTheme Literate { get; } = SystemConsoleThemes.Literate; + /// + /// A theme in the style of the original Serilog.Sinks.Literate. + /// + public static SystemConsoleTheme Literate { get; } = SystemConsoleThemes.Literate; - /// - /// A theme based on the original Serilog "colored console" sink. - /// - public static SystemConsoleTheme Colored { get; } = SystemConsoleThemes.Colored; + /// + /// A theme based on the original Serilog "colored console" sink. + /// + public static SystemConsoleTheme Colored { get; } = SystemConsoleThemes.Colored; - /// - /// Construct a theme given a set of styles. - /// - /// Styles to apply within the theme. - /// When is null - public SystemConsoleTheme(IReadOnlyDictionary styles) - { - if (styles is null) throw new ArgumentNullException(nameof(styles)); - Styles = styles.ToDictionary(kv => kv.Key, kv => kv.Value); - } + /// + /// Construct a theme given a set of styles. + /// + /// Styles to apply within the theme. + /// When is null + public SystemConsoleTheme(IReadOnlyDictionary styles) + { + if (styles is null) throw new ArgumentNullException(nameof(styles)); + Styles = styles.ToDictionary(kv => kv.Key, kv => kv.Value); + } - /// - public IReadOnlyDictionary Styles { get; } + /// + public IReadOnlyDictionary Styles { get; } - /// - public override bool CanBuffer => false; + /// + public override bool CanBuffer => false; - /// - protected override int ResetCharCount { get; } + /// + protected override int ResetCharCount { get; } - /// - public override int Set(TextWriter output, ConsoleThemeStyle style) + /// + public override int Set(TextWriter output, ConsoleThemeStyle style) + { + if (Styles.TryGetValue(style, out var wcts)) { - if (Styles.TryGetValue(style, out var wcts)) - { - if (wcts.Foreground.HasValue) - Console.ForegroundColor = wcts.Foreground.Value; - if (wcts.Background.HasValue) - Console.BackgroundColor = wcts.Background.Value; - } - - return 0; + if (wcts.Foreground.HasValue) + Console.ForegroundColor = wcts.Foreground.Value; + if (wcts.Background.HasValue) + Console.BackgroundColor = wcts.Background.Value; } - /// - public override void Reset(TextWriter output) - { - Console.ResetColor(); - } + return 0; + } + + /// + public override void Reset(TextWriter output) + { + Console.ResetColor(); } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemeStyle.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemeStyle.cs index 9cf64ce..c637af4 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemeStyle.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemeStyle.cs @@ -12,23 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +/// +/// Styling applied using the enumeration. +/// +public struct SystemConsoleThemeStyle { /// - /// Styling applied using the enumeration. + /// The foreground color to apply. /// - public struct SystemConsoleThemeStyle - { - /// - /// The foreground color to apply. - /// - public ConsoleColor? Foreground; + public ConsoleColor? Foreground; - /// - /// The background color to apply. - /// - public ConsoleColor? Background; - } + /// + /// The background color to apply. + /// + public ConsoleColor? Background; } \ No newline at end of file diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemes.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemes.cs index 5e202f9..a34d135 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemes.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Themes/SystemConsoleThemes.cs @@ -12,74 +12,70 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.Collections.Generic; +namespace Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Themes +static class SystemConsoleThemes { - static class SystemConsoleThemes - { - public static SystemConsoleTheme Literate { get; } = new SystemConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.SecondaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.TertiaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.Invalid] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Yellow }, - [ConsoleThemeStyle.Null] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Blue }, - [ConsoleThemeStyle.Name] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.String] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Cyan }, - [ConsoleThemeStyle.Number] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Magenta }, - [ConsoleThemeStyle.Boolean] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Blue }, - [ConsoleThemeStyle.Scalar] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Green }, - [ConsoleThemeStyle.LevelVerbose] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.LevelDebug] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.LevelInformation] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.LevelWarning] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Yellow }, - [ConsoleThemeStyle.LevelError] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, - [ConsoleThemeStyle.LevelFatal] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, - }); + public static SystemConsoleTheme Literate { get; } = new SystemConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.SecondaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.TertiaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.Invalid] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Yellow }, + [ConsoleThemeStyle.Null] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Blue }, + [ConsoleThemeStyle.Name] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.String] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Cyan }, + [ConsoleThemeStyle.Number] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Magenta }, + [ConsoleThemeStyle.Boolean] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Blue }, + [ConsoleThemeStyle.Scalar] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Green }, + [ConsoleThemeStyle.LevelVerbose] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.LevelDebug] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.LevelInformation] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.LevelWarning] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Yellow }, + [ConsoleThemeStyle.LevelError] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, + [ConsoleThemeStyle.LevelFatal] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, + }); - public static SystemConsoleTheme Grayscale { get; } = new SystemConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.SecondaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.TertiaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.Invalid] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.Null] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Name] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.String] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Number] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Boolean] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Scalar] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.LevelVerbose] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.LevelDebug] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.LevelInformation] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.LevelWarning] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.LevelError] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Black, Background = ConsoleColor.White }, - [ConsoleThemeStyle.LevelFatal] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Black, Background = ConsoleColor.White }, - }); + public static SystemConsoleTheme Grayscale { get; } = new SystemConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.SecondaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.TertiaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.Invalid] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.Null] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Name] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.String] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Number] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Boolean] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Scalar] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.LevelVerbose] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.LevelDebug] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.LevelInformation] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.LevelWarning] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.LevelError] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Black, Background = ConsoleColor.White }, + [ConsoleThemeStyle.LevelFatal] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Black, Background = ConsoleColor.White }, + }); - public static SystemConsoleTheme Colored { get; } = new SystemConsoleTheme( - new Dictionary - { - [ConsoleThemeStyle.Text] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, - [ConsoleThemeStyle.SecondaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.TertiaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.Invalid] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Yellow }, - [ConsoleThemeStyle.Null] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Name] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.String] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Number] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Boolean] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.Scalar] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, - [ConsoleThemeStyle.LevelVerbose] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray, Background = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.LevelDebug] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.DarkGray }, - [ConsoleThemeStyle.LevelInformation] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Blue }, - [ConsoleThemeStyle.LevelWarning] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray, Background = ConsoleColor.Yellow }, - [ConsoleThemeStyle.LevelError] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, - [ConsoleThemeStyle.LevelFatal] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, - }); - } + public static SystemConsoleTheme Colored { get; } = new SystemConsoleTheme( + new Dictionary + { + [ConsoleThemeStyle.Text] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray }, + [ConsoleThemeStyle.SecondaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.TertiaryText] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.Invalid] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Yellow }, + [ConsoleThemeStyle.Null] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Name] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.String] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Number] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Boolean] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.Scalar] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White }, + [ConsoleThemeStyle.LevelVerbose] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.Gray, Background = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.LevelDebug] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.DarkGray }, + [ConsoleThemeStyle.LevelInformation] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Blue }, + [ConsoleThemeStyle.LevelWarning] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.DarkGray, Background = ConsoleColor.Yellow }, + [ConsoleThemeStyle.LevelError] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, + [ConsoleThemeStyle.LevelFatal] = new SystemConsoleThemeStyle { Foreground = ConsoleColor.White, Background = ConsoleColor.Red }, + }); } diff --git a/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs b/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs index 46b1c72..1ef07b7 100644 --- a/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs @@ -1,26 +1,25 @@ -#if NET5_0 +#if NET7_0 using PublicApiGenerator; using Shouldly; using Xunit; -namespace Serilog.Sinks.Console.Tests.Approval +namespace Serilog.Sinks.Console.Tests.Approval; + +public class ApiApprovalTests { - public class ApiApprovalTests + [Fact] + public void PublicApi_Should_Not_Change_Unintentionally() { - [Fact] - public void PublicApi_Should_Not_Change_Unintentionally() - { - var assembly = typeof(ConsoleLoggerConfigurationExtensions).Assembly; - var publicApi = assembly.GeneratePublicApi( - new ApiGeneratorOptions() - { - IncludeAssemblyAttributes = false, - ExcludeAttributes = new[] { "System.Diagnostics.DebuggerDisplayAttribute" }, - }); + var assembly = typeof(ConsoleLoggerConfigurationExtensions).Assembly; + var publicApi = assembly.GeneratePublicApi( + new ApiGeneratorOptions() + { + IncludeAssemblyAttributes = false, + ExcludeAttributes = new[] { "System.Diagnostics.DebuggerDisplayAttribute" }, + }); - publicApi.ShouldMatchApproved(options => options.WithFilenameGenerator((_, __, fileType, fileExtension) => $"{assembly.GetName().Name!}.{fileType}.{fileExtension}")); - } + publicApi.ShouldMatchApproved(options => options.WithFilenameGenerator((_, __, fileType, fileExtension) => $"{assembly.GetName().Name!}.{fileType}.{fileExtension}")); } } diff --git a/test/Serilog.Sinks.Console.Tests/Configuration/ConsoleLoggerConfigurationExtensionsTests.cs b/test/Serilog.Sinks.Console.Tests/Configuration/ConsoleLoggerConfigurationExtensionsTests.cs index 74596c5..9ec3fc1 100644 --- a/test/Serilog.Sinks.Console.Tests/Configuration/ConsoleLoggerConfigurationExtensionsTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Configuration/ConsoleLoggerConfigurationExtensionsTests.cs @@ -1,62 +1,58 @@ -using System; -using System.IO; -using System.Linq; -using Xunit; +using Xunit; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.Console.Tests.Configuration +namespace Serilog.Sinks.Console.Tests.Configuration; + +public class ConsoleLoggerConfigurationExtensionsTests { - public class ConsoleLoggerConfigurationExtensionsTests + [Fact] + public void OutputFormattingIsIgnored() { - [Fact] - public void OutputFormattingIsIgnored() + using (var stream = new MemoryStream()) { - using (var stream = new MemoryStream()) - { - var sw = new StreamWriter(stream); + var sw = new StreamWriter(stream); - System.Console.SetOut(sw); - var config = new LoggerConfiguration() - .WriteTo.Console(theme: AnsiConsoleTheme.Literate, - applyThemeToRedirectedOutput: false); + System.Console.SetOut(sw); + var config = new LoggerConfiguration() + .WriteTo.Console(theme: AnsiConsoleTheme.Literate, + applyThemeToRedirectedOutput: false); - var logger = config.CreateLogger(); + var logger = config.CreateLogger(); - logger.Error("test"); - stream.Position = 0; + logger.Error("test"); + stream.Position = 0; - using (var streamReader = new StreamReader(stream)) - { - var result = streamReader.ReadToEnd(); - var controlCharacterCount = result.Count(c => Char.IsControl(c) && !Char.IsWhiteSpace(c)); - Assert.Equal(0, controlCharacterCount); - } + using (var streamReader = new StreamReader(stream)) + { + var result = streamReader.ReadToEnd(); + var controlCharacterCount = result.Count(c => Char.IsControl(c) && !Char.IsWhiteSpace(c)); + Assert.Equal(0, controlCharacterCount); } } - - [Fact] - public void OutputFormattingIsPresent() + } + + [Fact] + public void OutputFormattingIsPresent() + { + using (var stream = new MemoryStream()) { - using (var stream = new MemoryStream()) - { - var sw = new StreamWriter(stream); + var sw = new StreamWriter(stream); - System.Console.SetOut(sw); - var config = new LoggerConfiguration() - .WriteTo.Console(theme: AnsiConsoleTheme.Literate, - applyThemeToRedirectedOutput: true); + System.Console.SetOut(sw); + var config = new LoggerConfiguration() + .WriteTo.Console(theme: AnsiConsoleTheme.Literate, + applyThemeToRedirectedOutput: true); - var logger = config.CreateLogger(); + var logger = config.CreateLogger(); - logger.Error("test"); - stream.Position = 0; + logger.Error("test"); + stream.Position = 0; - using (var streamReader = new StreamReader(stream)) - { - var result = streamReader.ReadToEnd(); - var controlCharacterCount = result.Count(c => Char.IsControl(c) && !Char.IsWhiteSpace(c)); - Assert.NotEqual(0, controlCharacterCount); - } + using (var streamReader = new StreamReader(stream)) + { + var result = streamReader.ReadToEnd(); + var controlCharacterCount = result.Count(c => Char.IsControl(c) && !Char.IsWhiteSpace(c)); + Assert.NotEqual(0, controlCharacterCount); } } } diff --git a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs index 2770069..fe94aa5 100644 --- a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs @@ -1,23 +1,21 @@ -using System.IO; -using Serilog.Events; +using Serilog.Events; using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Themes; using Xunit; -namespace Serilog.Sinks.Console.Tests.Formatting +namespace Serilog.Sinks.Console.Tests.Formatting; + +public class ThemedDisplayValueFormatterTests { - public class ThemedDisplayValueFormatterTests + [Theory] + [InlineData("Hello", null, "\"Hello\"")] + [InlineData("Hello", "l", "Hello")] + public void StringFormattingIsApplied(string value, string format, string expected) { - [Theory] - [InlineData("Hello", null, "\"Hello\"")] - [InlineData("Hello", "l", "Hello")] - public void StringFormattingIsApplied(string value, string format, string expected) - { - var formatter = new ThemedDisplayValueFormatter(ConsoleTheme.None, null); - var sw = new StringWriter(); - formatter.FormatLiteralValue(new ScalarValue(value), sw, format); - var actual = sw.ToString(); - Assert.Equal(expected, actual); - } + var formatter = new ThemedDisplayValueFormatter(ConsoleTheme.None, null); + var sw = new StringWriter(); + formatter.FormatLiteralValue(new ScalarValue(value), sw, format); + var actual = sw.ToString(); + Assert.Equal(expected, actual); } } diff --git a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs index 45a3814..af82fdd 100644 --- a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs @@ -1,135 +1,131 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Serilog.Events; +using Serilog.Events; using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Themes; using Xunit; -namespace Serilog.Sinks.Console.Tests.Formatting +namespace Serilog.Sinks.Console.Tests.Formatting; + +public class ThemedJsonValueFormatterTests { - public class ThemedJsonValueFormatterTests + class TestThemedJsonValueFormatter : ThemedJsonValueFormatter { - class TestThemedJsonValueFormatter : ThemedJsonValueFormatter + public TestThemedJsonValueFormatter() + : base(ConsoleTheme.None, null) { - public TestThemedJsonValueFormatter() - : base(ConsoleTheme.None, null) - { - } - - public string Format(object literal) - { - var output = new StringWriter(); - Format(new SequenceValue(new[] { new ScalarValue(literal) }), output, null); - var o = output.ToString(); - return o.Substring(1, o.Length - 2); - } } - [Theory] - [InlineData(123, "123")] - [InlineData('c', "\"c\"")] - [InlineData("Hello, world!", "\"Hello, world!\"")] - [InlineData(true, "true")] - [InlineData("\\\"\t\r\n\f", "\"\\\\\\\"\\t\\r\\n\\f\"")] - [InlineData("\u0001", "\"\\u0001\"")] - [InlineData("a\nb", "\"a\\nb\"")] - [InlineData(null, "null")] - public void JsonLiteralTypesAreFormatted(object value, string expectedJson) + public string Format(object literal) { - var formatter = new TestThemedJsonValueFormatter(); - Assert.Equal(expectedJson, formatter.Format(value)); + var output = new StringWriter(); + Format(new SequenceValue(new[] { new ScalarValue(literal) }), output, null); + var o = output.ToString(); + return o.Substring(1, o.Length - 2); } + } - [Fact] - public void DateTimesFormatAsIso8601() - { - JsonLiteralTypesAreFormatted(new DateTime(2016, 01, 01, 13, 13, 13, DateTimeKind.Utc), "\"2016-01-01T13:13:13.0000000Z\""); - } + [Theory] + [InlineData(123, "123")] + [InlineData('c', "\"c\"")] + [InlineData("Hello, world!", "\"Hello, world!\"")] + [InlineData(true, "true")] + [InlineData("\\\"\t\r\n\f", "\"\\\\\\\"\\t\\r\\n\\f\"")] + [InlineData("\u0001", "\"\\u0001\"")] + [InlineData("a\nb", "\"a\\nb\"")] + [InlineData(null, "null")] + public void JsonLiteralTypesAreFormatted(object value, string expectedJson) + { + var formatter = new TestThemedJsonValueFormatter(); + Assert.Equal(expectedJson, formatter.Format(value)); + } - [Fact] - public void DoubleFormatsAsNumber() - { - JsonLiteralTypesAreFormatted(123.45, "123.45"); - } + [Fact] + public void DateTimesFormatAsIso8601() + { + JsonLiteralTypesAreFormatted(new DateTime(2016, 01, 01, 13, 13, 13, DateTimeKind.Utc), "\"2016-01-01T13:13:13.0000000Z\""); + } - [Fact] - public void DoubleSpecialsFormatAsString() - { - JsonLiteralTypesAreFormatted(double.NaN, "\"NaN\""); - JsonLiteralTypesAreFormatted(double.PositiveInfinity, "\"Infinity\""); - JsonLiteralTypesAreFormatted(double.NegativeInfinity, "\"-Infinity\""); - } + [Fact] + public void DoubleFormatsAsNumber() + { + JsonLiteralTypesAreFormatted(123.45, "123.45"); + } - [Fact] - public void FloatFormatsAsNumber() - { - JsonLiteralTypesAreFormatted(123.45f, "123.45"); - } + [Fact] + public void DoubleSpecialsFormatAsString() + { + JsonLiteralTypesAreFormatted(double.NaN, "\"NaN\""); + JsonLiteralTypesAreFormatted(double.PositiveInfinity, "\"Infinity\""); + JsonLiteralTypesAreFormatted(double.NegativeInfinity, "\"-Infinity\""); + } - [Fact] - public void FloatSpecialsFormatAsString() - { - JsonLiteralTypesAreFormatted(float.NaN, "\"NaN\""); - JsonLiteralTypesAreFormatted(float.PositiveInfinity, "\"Infinity\""); - JsonLiteralTypesAreFormatted(float.NegativeInfinity, "\"-Infinity\""); - } + [Fact] + public void FloatFormatsAsNumber() + { + JsonLiteralTypesAreFormatted(123.45f, "123.45"); + } - [Fact] - public void DecimalFormatsAsNumber() - { - JsonLiteralTypesAreFormatted(123.45m, "123.45"); - } + [Fact] + public void FloatSpecialsFormatAsString() + { + JsonLiteralTypesAreFormatted(float.NaN, "\"NaN\""); + JsonLiteralTypesAreFormatted(float.PositiveInfinity, "\"Infinity\""); + JsonLiteralTypesAreFormatted(float.NegativeInfinity, "\"-Infinity\""); + } - static string Format(LogEventPropertyValue value) - { - var formatter = new TestThemedJsonValueFormatter(); - var output = new StringWriter(); - formatter.Format(value, output, null); - return output.ToString(); - } + [Fact] + public void DecimalFormatsAsNumber() + { + JsonLiteralTypesAreFormatted(123.45m, "123.45"); + } - [Fact] - public void ScalarPropertiesFormatAsLiteralValues() - { - var f = Format(new ScalarValue(123)); - Assert.Equal("123", f); - } + static string Format(LogEventPropertyValue value) + { + var formatter = new TestThemedJsonValueFormatter(); + var output = new StringWriter(); + formatter.Format(value, output, null); + return output.ToString(); + } - [Fact] - public void SequencePropertiesFormatAsArrayValue() - { - var f = Format(new SequenceValue(new[] { new ScalarValue(123), new ScalarValue(456) })); - Assert.Equal("[123, 456]", f); - } + [Fact] + public void ScalarPropertiesFormatAsLiteralValues() + { + var f = Format(new ScalarValue(123)); + Assert.Equal("123", f); + } - [Fact] - public void StructuresFormatAsAnObject() - { - var structure = new StructureValue(new[] { new LogEventProperty("A", new ScalarValue(123)) }, "T"); - var f = Format(structure); - Assert.Equal("{\"A\": 123, \"$type\": \"T\"}", f); - } + [Fact] + public void SequencePropertiesFormatAsArrayValue() + { + var f = Format(new SequenceValue(new[] { new ScalarValue(123), new ScalarValue(456) })); + Assert.Equal("[123, 456]", f); + } + + [Fact] + public void StructuresFormatAsAnObject() + { + var structure = new StructureValue(new[] { new LogEventProperty("A", new ScalarValue(123)) }, "T"); + var f = Format(structure); + Assert.Equal("{\"A\": 123, \"$type\": \"T\"}", f); + } - [Fact] - public void DictionaryWithScalarKeyFormatsAsAnObject() + [Fact] + public void DictionaryWithScalarKeyFormatsAsAnObject() + { + var dict = new DictionaryValue(new Dictionary { - var dict = new DictionaryValue(new Dictionary - { - { new ScalarValue(12), new ScalarValue(345) }, - }); + { new ScalarValue(12), new ScalarValue(345) }, + }); - var f = Format(dict); - Assert.Equal("{\"12\": 345}", f); - } + var f = Format(dict); + Assert.Equal("{\"12\": 345}", f); + } - [Fact] - public void SequencesOfSequencesAreFormatted() - { - var s = new SequenceValue(new[] { new SequenceValue(new[] { new ScalarValue("Hello") }) }); + [Fact] + public void SequencesOfSequencesAreFormatted() + { + var s = new SequenceValue(new[] { new SequenceValue(new[] { new ScalarValue("Hello") }) }); - var f = Format(s); - Assert.Equal("[[\"Hello\"]]", f); - } + var f = Format(s); + Assert.Equal("[[\"Hello\"]]", f); } } diff --git a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs index 9dd5d5f..7cee5d1 100644 --- a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs @@ -1,378 +1,374 @@ -using System; -using System.Globalization; -using System.IO; -using System.Linq; +using System.Globalization; using Serilog.Events; using Serilog.Sinks.Console.Tests.Support; using Serilog.Sinks.SystemConsole.Output; using Serilog.Sinks.SystemConsole.Themes; using Xunit; -namespace Serilog.Sinks.Console.Tests.Output +namespace Serilog.Sinks.Console.Tests.Output; + +public class OutputTemplateRendererTests { - public class OutputTemplateRendererTests + [Fact] + public void UsesFormatProvider() { - [Fact] - public void UsesFormatProvider() - { - var french = new CultureInfo("fr-FR"); - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message}", french); - var evt = DelegatingSink.GetLogEvent(l => l.Information("{0}", 12.345)); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("12,345", sw.ToString()); - } + var french = new CultureInfo("fr-FR"); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message}", french); + var evt = DelegatingSink.GetLogEvent(l => l.Information("{0}", 12.345)); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("12,345", sw.ToString()); + } - [Fact] - public void MessageTemplatesContainingFormatStringPropertiesRenderCorrectly() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("{Message}", "Hello, world!")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("\"Hello, world!\"", sw.ToString()); - } + [Fact] + public void MessageTemplatesContainingFormatStringPropertiesRenderCorrectly() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("{Message}", "Hello, world!")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("\"Hello, world!\"", sw.ToString()); + } - [Fact] - public void UppercaseFormatSpecifierIsSupportedForStrings() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Name:u}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("{Name}", "Nick")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("NICK", sw.ToString()); - } + [Fact] + public void UppercaseFormatSpecifierIsSupportedForStrings() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Name:u}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("{Name}", "Nick")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("NICK", sw.ToString()); + } - [Fact] - public void LowercaseFormatSpecifierIsSupportedForStrings() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Name:w}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("{Name}", "Nick")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("nick", sw.ToString()); - } + [Fact] + public void LowercaseFormatSpecifierIsSupportedForStrings() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Name:w}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("{Name}", "Nick")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("nick", sw.ToString()); + } - [Theory] - [InlineData(LogEventLevel.Verbose, 1, "V")] - [InlineData(LogEventLevel.Verbose, 2, "Vb")] - [InlineData(LogEventLevel.Verbose, 3, "Vrb")] - [InlineData(LogEventLevel.Verbose, 4, "Verb")] - [InlineData(LogEventLevel.Verbose, 5, "Verbo")] - [InlineData(LogEventLevel.Verbose, 6, "Verbos")] - [InlineData(LogEventLevel.Verbose, 7, "Verbose")] - [InlineData(LogEventLevel.Verbose, 8, "Verbose")] - [InlineData(LogEventLevel.Debug, 1, "D")] - [InlineData(LogEventLevel.Debug, 2, "De")] - [InlineData(LogEventLevel.Debug, 3, "Dbg")] - [InlineData(LogEventLevel.Debug, 4, "Dbug")] - [InlineData(LogEventLevel.Debug, 5, "Debug")] - [InlineData(LogEventLevel.Debug, 6, "Debug")] - [InlineData(LogEventLevel.Information, 1, "I")] - [InlineData(LogEventLevel.Information, 2, "In")] - [InlineData(LogEventLevel.Information, 3, "Inf")] - [InlineData(LogEventLevel.Information, 4, "Info")] - [InlineData(LogEventLevel.Information, 5, "Infor")] - [InlineData(LogEventLevel.Information, 6, "Inform")] - [InlineData(LogEventLevel.Information, 7, "Informa")] - [InlineData(LogEventLevel.Information, 8, "Informat")] - [InlineData(LogEventLevel.Information, 9, "Informati")] - [InlineData(LogEventLevel.Information, 10, "Informatio")] - [InlineData(LogEventLevel.Information, 11, "Information")] - [InlineData(LogEventLevel.Information, 12, "Information")] - [InlineData(LogEventLevel.Error, 1, "E")] - [InlineData(LogEventLevel.Error, 2, "Er")] - [InlineData(LogEventLevel.Error, 3, "Err")] - [InlineData(LogEventLevel.Error, 4, "Eror")] - [InlineData(LogEventLevel.Error, 5, "Error")] - [InlineData(LogEventLevel.Error, 6, "Error")] - [InlineData(LogEventLevel.Fatal, 1, "F")] - [InlineData(LogEventLevel.Fatal, 2, "Fa")] - [InlineData(LogEventLevel.Fatal, 3, "Ftl")] - [InlineData(LogEventLevel.Fatal, 4, "Fatl")] - [InlineData(LogEventLevel.Fatal, 5, "Fatal")] - [InlineData(LogEventLevel.Fatal, 6, "Fatal")] - [InlineData(LogEventLevel.Warning, 1, "W")] - [InlineData(LogEventLevel.Warning, 2, "Wn")] - [InlineData(LogEventLevel.Warning, 3, "Wrn")] - [InlineData(LogEventLevel.Warning, 4, "Warn")] - [InlineData(LogEventLevel.Warning, 5, "Warni")] - [InlineData(LogEventLevel.Warning, 6, "Warnin")] - [InlineData(LogEventLevel.Warning, 7, "Warning")] - [InlineData(LogEventLevel.Warning, 8, "Warning")] - public void FixedLengthLevelIsSupported( - LogEventLevel level, - int width, - string expected) - { - var formatter1 = new OutputTemplateRenderer(ConsoleTheme.None, $"{{Level:t{width}}}", CultureInfo.InvariantCulture); - var evt1 = DelegatingSink.GetLogEvent(l => l.Write(level, "Hello")); - var sw1 = new StringWriter(); - formatter1.Format(evt1, sw1); - Assert.Equal(expected, sw1.ToString()); - - var formatter2 = new OutputTemplateRenderer(ConsoleTheme.None, $"{{Level:u{width}}}", CultureInfo.InvariantCulture); - var evt2 = DelegatingSink.GetLogEvent(l => l.Write(level, "Hello")); - var sw2 = new StringWriter(); - formatter2.Format(evt2, sw2); - Assert.Equal(expected.ToUpper(), sw2.ToString()); - - var formatter3 = new OutputTemplateRenderer(ConsoleTheme.None, $"{{Level:w{width}}}", CultureInfo.InvariantCulture); - var evt3 = DelegatingSink.GetLogEvent(l => l.Write(level, "Hello")); - var sw3 = new StringWriter(); - formatter3.Format(evt3, sw3); - Assert.Equal(expected.ToLower(), sw3.ToString()); - } + [Theory] + [InlineData(LogEventLevel.Verbose, 1, "V")] + [InlineData(LogEventLevel.Verbose, 2, "Vb")] + [InlineData(LogEventLevel.Verbose, 3, "Vrb")] + [InlineData(LogEventLevel.Verbose, 4, "Verb")] + [InlineData(LogEventLevel.Verbose, 5, "Verbo")] + [InlineData(LogEventLevel.Verbose, 6, "Verbos")] + [InlineData(LogEventLevel.Verbose, 7, "Verbose")] + [InlineData(LogEventLevel.Verbose, 8, "Verbose")] + [InlineData(LogEventLevel.Debug, 1, "D")] + [InlineData(LogEventLevel.Debug, 2, "De")] + [InlineData(LogEventLevel.Debug, 3, "Dbg")] + [InlineData(LogEventLevel.Debug, 4, "Dbug")] + [InlineData(LogEventLevel.Debug, 5, "Debug")] + [InlineData(LogEventLevel.Debug, 6, "Debug")] + [InlineData(LogEventLevel.Information, 1, "I")] + [InlineData(LogEventLevel.Information, 2, "In")] + [InlineData(LogEventLevel.Information, 3, "Inf")] + [InlineData(LogEventLevel.Information, 4, "Info")] + [InlineData(LogEventLevel.Information, 5, "Infor")] + [InlineData(LogEventLevel.Information, 6, "Inform")] + [InlineData(LogEventLevel.Information, 7, "Informa")] + [InlineData(LogEventLevel.Information, 8, "Informat")] + [InlineData(LogEventLevel.Information, 9, "Informati")] + [InlineData(LogEventLevel.Information, 10, "Informatio")] + [InlineData(LogEventLevel.Information, 11, "Information")] + [InlineData(LogEventLevel.Information, 12, "Information")] + [InlineData(LogEventLevel.Error, 1, "E")] + [InlineData(LogEventLevel.Error, 2, "Er")] + [InlineData(LogEventLevel.Error, 3, "Err")] + [InlineData(LogEventLevel.Error, 4, "Eror")] + [InlineData(LogEventLevel.Error, 5, "Error")] + [InlineData(LogEventLevel.Error, 6, "Error")] + [InlineData(LogEventLevel.Fatal, 1, "F")] + [InlineData(LogEventLevel.Fatal, 2, "Fa")] + [InlineData(LogEventLevel.Fatal, 3, "Ftl")] + [InlineData(LogEventLevel.Fatal, 4, "Fatl")] + [InlineData(LogEventLevel.Fatal, 5, "Fatal")] + [InlineData(LogEventLevel.Fatal, 6, "Fatal")] + [InlineData(LogEventLevel.Warning, 1, "W")] + [InlineData(LogEventLevel.Warning, 2, "Wn")] + [InlineData(LogEventLevel.Warning, 3, "Wrn")] + [InlineData(LogEventLevel.Warning, 4, "Warn")] + [InlineData(LogEventLevel.Warning, 5, "Warni")] + [InlineData(LogEventLevel.Warning, 6, "Warnin")] + [InlineData(LogEventLevel.Warning, 7, "Warning")] + [InlineData(LogEventLevel.Warning, 8, "Warning")] + public void FixedLengthLevelIsSupported( + LogEventLevel level, + int width, + string expected) + { + var formatter1 = new OutputTemplateRenderer(ConsoleTheme.None, $"{{Level:t{width}}}", CultureInfo.InvariantCulture); + var evt1 = DelegatingSink.GetLogEvent(l => l.Write(level, "Hello")); + var sw1 = new StringWriter(); + formatter1.Format(evt1, sw1); + Assert.Equal(expected, sw1.ToString()); + + var formatter2 = new OutputTemplateRenderer(ConsoleTheme.None, $"{{Level:u{width}}}", CultureInfo.InvariantCulture); + var evt2 = DelegatingSink.GetLogEvent(l => l.Write(level, "Hello")); + var sw2 = new StringWriter(); + formatter2.Format(evt2, sw2); + Assert.Equal(expected.ToUpper(), sw2.ToString()); + + var formatter3 = new OutputTemplateRenderer(ConsoleTheme.None, $"{{Level:w{width}}}", CultureInfo.InvariantCulture); + var evt3 = DelegatingSink.GetLogEvent(l => l.Write(level, "Hello")); + var sw3 = new StringWriter(); + formatter3.Format(evt3, sw3); + Assert.Equal(expected.ToLower(), sw3.ToString()); + } - [Fact] - public void FixedLengthLevelSupportsUpperCasing() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level:u3}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("INF", sw.ToString()); - } + [Fact] + public void FixedLengthLevelSupportsUpperCasing() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level:u3}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("INF", sw.ToString()); + } - [Fact] - public void FixedLengthLevelSupportsLowerCasing() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level:w3}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("inf", sw.ToString()); - } - - [Fact] - public void FixedLengthLevelSupportsCasingForWideNames() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level:w6}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("inform", sw.ToString()); - } + [Fact] + public void FixedLengthLevelSupportsLowerCasing() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level:w3}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("inf", sw.ToString()); + } + + [Fact] + public void FixedLengthLevelSupportsCasingForWideNames() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level:w6}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("inform", sw.ToString()); + } - [Fact] - public void DefaultLevelLengthIsFullText() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("Information", sw.ToString()); - } + [Fact] + public void DefaultLevelLengthIsFullText() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("Information", sw.ToString()); + } + + [Fact] + public void AlignmentAndWidthCanBeCombined() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level,5:w3}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal(" inf", sw.ToString()); + } - [Fact] - public void AlignmentAndWidthCanBeCombined() + enum Size + { + Large + } + + class SizeFormatter : IFormatProvider, ICustomFormatter + { + readonly IFormatProvider _innerFormatProvider; + + public SizeFormatter(IFormatProvider innerFormatProvider) { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Level,5:w3}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal(" inf", sw.ToString()); + _innerFormatProvider = innerFormatProvider; } - enum Size + public object? GetFormat(Type? formatType) { - Large + return formatType == typeof(ICustomFormatter) ? this : _innerFormatProvider.GetFormat(formatType) ?? this; } - class SizeFormatter : IFormatProvider, ICustomFormatter + public string Format(string? format, object? arg, IFormatProvider? formatProvider) { - readonly IFormatProvider _innerFormatProvider; + if (arg is Size size) + return size == Size.Large ? "Huge" : size.ToString(); - public SizeFormatter(IFormatProvider innerFormatProvider) - { - _innerFormatProvider = innerFormatProvider; - } + if (arg is IFormattable formattable) + return formattable.ToString(format, _innerFormatProvider); - public object? GetFormat(Type? formatType) - { - return formatType == typeof(ICustomFormatter) ? this : _innerFormatProvider.GetFormat(formatType) ?? this; - } + return arg?.ToString() ?? ""; + } + } - public string Format(string? format, object? arg, IFormatProvider? formatProvider) - { - if (arg is Size size) - return size == Size.Large ? "Huge" : size.ToString(); + [Fact] + public void AppliesCustomFormatterToEnums() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message}", new SizeFormatter(CultureInfo.InvariantCulture)); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Size {Size}", Size.Large)); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("Size Huge", sw.ToString()); + } - if (arg is IFormattable formattable) - return formattable.ToString(format, _innerFormatProvider); + [Fact] + public void NonMessagePropertiesAreRendered() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).Information("Hello from {Bar}!", "bar")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("{Foo=42}", sw.ToString()); + } - return arg?.ToString() ?? ""; - } - } + [Fact] + public void NonMessagePositionalPropertiesAreRendered() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).Information("Hello from {0}!", "bar")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("{Foo=42}", sw.ToString()); + } - [Fact] - public void AppliesCustomFormatterToEnums() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message}", new SizeFormatter(CultureInfo.InvariantCulture)); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Size {Size}", Size.Large)); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("Size Huge", sw.ToString()); - } + [Fact] + public void DoNotDuplicatePropertiesAlreadyRenderedInOutputTemplate() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Foo} {Properties}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).ForContext("Bar", 42).Information("Hello from bar!")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("42 {Bar=42}", sw.ToString()); + } - [Fact] - public void NonMessagePropertiesAreRendered() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).Information("Hello from {Bar}!", "bar")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("{Foo=42}", sw.ToString()); - } + [Theory] + [InlineData("", "Hello, \"World\"!")] + [InlineData(":j", "Hello, \"World\"!")] + [InlineData(":l", "Hello, World!")] + [InlineData(":lj", "Hello, World!")] + [InlineData(":jl", "Hello, World!")] + public void AppliesLiteralFormattingToMessageStringsWhenSpecified(string format, string expected) + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", null); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello, {Name}!", "World")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal(expected, sw.ToString()); + } - [Fact] - public void NonMessagePositionalPropertiesAreRendered() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).Information("Hello from {0}!", "bar")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("{Foo=42}", sw.ToString()); - } + [Theory] + [InlineData("", "{Name=\"World\"}")] + [InlineData(":j", "{\"Name\": \"World\"}")] + [InlineData(":lj", "{\"Name\": \"World\"}")] + [InlineData(":jl", "{\"Name\": \"World\"}")] + public void AppliesJsonFormattingToMessageStructuresWhenSpecified(string format, string expected) + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", null); + var evt = DelegatingSink.GetLogEvent(l => l.Information("{@Obj}", new { Name = "World" })); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal(expected, sw.ToString()); + } - [Fact] - public void DoNotDuplicatePropertiesAlreadyRenderedInOutputTemplate() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Foo} {Properties}", CultureInfo.InvariantCulture); - var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).ForContext("Bar", 42).Information("Hello from bar!")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal("42 {Bar=42}", sw.ToString()); - } + [Theory] + [InlineData("", "{Name=\"World\"}")] + [InlineData(":j", "{\"Name\": \"World\"}")] + [InlineData(":lj", "{\"Name\": \"World\"}")] + [InlineData(":jl", "{\"Name\": \"World\"}")] + public void AppliesJsonFormattingToPropertiesTokenWhenSpecified(string format, string expected) + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties" + format + "}", null); + var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Name", "World").Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal(expected, sw.ToString()); + } - [Theory] - [InlineData("", "Hello, \"World\"!")] - [InlineData(":j", "Hello, \"World\"!")] - [InlineData(":l", "Hello, World!")] - [InlineData(":lj", "Hello, World!")] - [InlineData(":jl", "Hello, World!")] - public void AppliesLiteralFormattingToMessageStringsWhenSpecified(string format, string expected) - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", null); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello, {Name}!", "World")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal(expected, sw.ToString()); - } + [Fact] + public void AnEmptyPropertiesTokenIsAnEmptyStructureValue() + { + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties}", null); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + + // /!\ different behavior from Serilog Core : https://github.com/serilog/serilog/blob/5c3a7821aa0f654e551dc21e8e19089f6767666b/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs#L268-L278 + // + // var expected = new StructureValue(Enumerable.Empty()).ToString(); + // // expected == "{ }" + // Assert.Equal(expected, sw.ToString()); + // + Assert.Equal("{}", sw.ToString()); + } - [Theory] - [InlineData("", "{Name=\"World\"}")] - [InlineData(":j", "{\"Name\": \"World\"}")] - [InlineData(":lj", "{\"Name\": \"World\"}")] - [InlineData(":jl", "{\"Name\": \"World\"}")] - public void AppliesJsonFormattingToMessageStructuresWhenSpecified(string format, string expected) - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", null); - var evt = DelegatingSink.GetLogEvent(l => l.Information("{@Obj}", new { Name = "World" })); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal(expected, sw.ToString()); - } + [Theory] + [InlineData("", true)] + [InlineData(":lj", true)] + [InlineData(":jl", true)] + [InlineData(":j", false)] + [InlineData(":l", true)] + public void FormatProviderWithScalarProperties(string format, bool shouldUseCustomFormatter) + { + var frenchFormatProvider = new CultureInfo("fr-FR"); + var defaultFormatProvider = CultureInfo.InvariantCulture; - [Theory] - [InlineData("", "{Name=\"World\"}")] - [InlineData(":j", "{\"Name\": \"World\"}")] - [InlineData(":lj", "{\"Name\": \"World\"}")] - [InlineData(":jl", "{\"Name\": \"World\"}")] - public void AppliesJsonFormattingToPropertiesTokenWhenSpecified(string format, string expected) - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties" + format + "}", null); - var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Name", "World").Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - Assert.Equal(expected, sw.ToString()); - } + var date = new DateTime(2018, 01, 01); + var number = 12.345; - [Fact] - public void AnEmptyPropertiesTokenIsAnEmptyStructureValue() - { - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Properties}", null); - var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello")); - var sw = new StringWriter(); - formatter.Format(evt, sw); - - // /!\ different behavior from Serilog Core : https://github.com/serilog/serilog/blob/5c3a7821aa0f654e551dc21e8e19089f6767666b/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs#L268-L278 - // - // var expected = new StructureValue(Enumerable.Empty()).ToString(); - // // expected == "{ }" - // Assert.Equal(expected, sw.ToString()); - // - Assert.Equal("{}", sw.ToString()); - } + var expectedFormattedDate = shouldUseCustomFormatter + ? date.ToString(frenchFormatProvider) + : date.ToString("O", defaultFormatProvider); + var expectedFormattedNumber = shouldUseCustomFormatter + ? number.ToString(frenchFormatProvider) + : number.ToString(defaultFormatProvider); - [Theory] - [InlineData("", true)] - [InlineData(":lj", true)] - [InlineData(":jl", true)] - [InlineData(":j", false)] - [InlineData(":l", true)] - public void FormatProviderWithScalarProperties(string format, bool shouldUseCustomFormatter) + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", frenchFormatProvider); + var evt = DelegatingSink.GetLogEvent(l => { - var frenchFormatProvider = new CultureInfo("fr-FR"); - var defaultFormatProvider = CultureInfo.InvariantCulture; + l.Information("{MyDate}{MyNumber}", date, number); + }); + var sw = new StringWriter(); + formatter.Format(evt, sw); - var date = new DateTime(2018, 01, 01); - var number = 12.345; + Assert.Contains(expectedFormattedDate, sw.ToString()); + Assert.Contains(expectedFormattedNumber, sw.ToString()); + } - var expectedFormattedDate = shouldUseCustomFormatter - ? date.ToString(frenchFormatProvider) - : date.ToString("O", defaultFormatProvider); - var expectedFormattedNumber = shouldUseCustomFormatter - ? number.ToString(frenchFormatProvider) - : number.ToString(defaultFormatProvider); + [Theory] + [InlineData("", true)] + [InlineData(":lj", false)] + [InlineData(":jl", false)] + [InlineData(":j", false)] + [InlineData(":l", true)] + public void FormatProviderWithDestructuredProperties(string format, bool shouldUseCustomFormatter) + { + var frenchFormatProvider = new CultureInfo("fr-FR"); + var defaultFormatProvider = CultureInfo.InvariantCulture; - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", frenchFormatProvider); - var evt = DelegatingSink.GetLogEvent(l => - { - l.Information("{MyDate}{MyNumber}", date, number); - }); - var sw = new StringWriter(); - formatter.Format(evt, sw); + var date = new DateTime(2018, 01, 01); + var number = 12.345; - Assert.Contains(expectedFormattedDate, sw.ToString()); - Assert.Contains(expectedFormattedNumber, sw.ToString()); - } + var expectedFormattedDate = shouldUseCustomFormatter + ? date.ToString(frenchFormatProvider) + : date.ToString("O", defaultFormatProvider); + var expectedFormattedNumber = shouldUseCustomFormatter + ? number.ToString(frenchFormatProvider) + : number.ToString(defaultFormatProvider); - [Theory] - [InlineData("", true)] - [InlineData(":lj", false)] - [InlineData(":jl", false)] - [InlineData(":j", false)] - [InlineData(":l", true)] - public void FormatProviderWithDestructuredProperties(string format, bool shouldUseCustomFormatter) + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", frenchFormatProvider); + var evt = DelegatingSink.GetLogEvent(l => { - var frenchFormatProvider = new CultureInfo("fr-FR"); - var defaultFormatProvider = CultureInfo.InvariantCulture; - - var date = new DateTime(2018, 01, 01); - var number = 12.345; - - var expectedFormattedDate = shouldUseCustomFormatter - ? date.ToString(frenchFormatProvider) - : date.ToString("O", defaultFormatProvider); - var expectedFormattedNumber = shouldUseCustomFormatter - ? number.ToString(frenchFormatProvider) - : number.ToString(defaultFormatProvider); - - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Message" + format + "}", frenchFormatProvider); - var evt = DelegatingSink.GetLogEvent(l => + l.Information("{@Item}", new { - l.Information("{@Item}", new - { - MyDate = date, - MyNumber = number, - }); + MyDate = date, + MyNumber = number, }); - var sw = new StringWriter(); - formatter.Format(evt, sw); + }); + var sw = new StringWriter(); + formatter.Format(evt, sw); - Assert.Contains(expectedFormattedDate, sw.ToString()); - Assert.Contains(expectedFormattedNumber, sw.ToString()); - } + Assert.Contains(expectedFormattedDate, sw.ToString()); + Assert.Contains(expectedFormattedNumber, sw.ToString()); } } diff --git a/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs index 031f118..c822e05 100644 --- a/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs @@ -1,203 +1,199 @@ -using Serilog.Sinks.SystemConsole.Formatting; +using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Rendering; using Serilog.Sinks.SystemConsole.Themes; -using System; using System.Globalization; -using System.IO; -using System.Linq; using System.Text; using Xunit; -namespace Serilog.Sinks.Console.Tests.Rendering +namespace Serilog.Sinks.Console.Tests.Rendering; + +public class ThemedMessageTemplateRendererTests { - public class ThemedMessageTemplateRendererTests - { - class Chair - { - // ReSharper disable UnusedMember.Local - public string Back => "straight"; - - public int[] Legs => new[] { 1, 2, 3, 4 }; - - // ReSharper restore UnusedMember.Local - public override string ToString() => "a chair"; - } - - class Receipt - { - // ReSharper disable UnusedMember.Local - public decimal Sum => 12.345m; - - public DateTime When => new DateTime(2013, 5, 20, 16, 39, 0); - - // ReSharper restore UnusedMember.Local - public override string ToString() => "a receipt"; - } - - [Fact] - public void AnObjectIsRenderedInSimpleNotation() - { - var m = Render("I sat at {@Chair}", new Chair()); - Assert.Equal("I sat at Chair {Back=\"straight\", Legs=[1, 2, 3, 4]}", m); - } - - [Fact] - public void AnObjectIsRenderedInSimpleNotationUsingFormatProvider() - { - var m = Render(new CultureInfo("fr-FR"), "I received {@Receipt}", new Receipt()); - Assert.Equal("I received Receipt {Sum=12,345, When=20/05/2013 16:39:00}", m); - } - - [Fact] - public void AnAnonymousObjectIsRenderedInSimpleNotationWithoutType() - { - var m = Render("I sat at {@Chair}", new { Back = "straight", Legs = new[] { 1, 2, 3, 4 } }); - Assert.Equal("I sat at {Back=\"straight\", Legs=[1, 2, 3, 4]}", m); - } - - [Fact] - public void AnAnonymousObjectIsRenderedInSimpleNotationWithoutTypeUsingFormatProvider() - { - var m = Render(new CultureInfo("fr-FR"), "I received {@Receipt}", new { Sum = 12.345, When = new DateTime(2013, 5, 20, 16, 39, 0) }); - Assert.Equal("I received {Sum=12,345, When=20/05/2013 16:39:00}", m); - } - - [Fact] - public void AnObjectWithDefaultDestructuringIsRenderedAsAStringLiteral() - { - var m = Render("I sat at {Chair}", new Chair()); - Assert.Equal("I sat at \"a chair\"", m); - } - - [Fact] - public void AnObjectWithStringifyDestructuringIsRenderedAsAString() - { - var m = Render("I sat at {$Chair}", new Chair()); - Assert.Equal("I sat at \"a chair\"", m); - } - - [Fact] - public void MultiplePropertiesAreRenderedInOrder() - { - var m = Render("Just biting {Fruit} number {Count}", "Apple", 12); - Assert.Equal("Just biting \"Apple\" number 12", m); - } - - [Fact] - public void MultiplePropertiesUseFormatProvider() - { - var m = Render(new CultureInfo("fr-FR"), "Income was {Income} at {Date:d}", 1234.567, new DateTime(2013, 5, 20)); - Assert.Equal("Income was 1234,567 at 20/05/2013", m); - } - - [Fact] - public void FormatStringsArePropagated() - { - var m = Render("Welcome, customer {CustomerId:0000}", 12); - Assert.Equal("Welcome, customer 0012", m); - } - - [Theory] - [InlineData("Welcome, customer #{CustomerId,-10}, pleasure to see you", "Welcome, customer #1234 , pleasure to see you")] - [InlineData("Welcome, customer #{CustomerId,-10:000000}, pleasure to see you", "Welcome, customer #001234 , pleasure to see you")] - [InlineData("Welcome, customer #{CustomerId,10}, pleasure to see you", "Welcome, customer # 1234, pleasure to see you")] - [InlineData("Welcome, customer #{CustomerId,10:000000}, pleasure to see you", "Welcome, customer # 001234, pleasure to see you")] - [InlineData("Welcome, customer #{CustomerId,10:0,0}, pleasure to see you", "Welcome, customer # 1,234, pleasure to see you")] - [InlineData("Welcome, customer #{CustomerId:0,0}, pleasure to see you", "Welcome, customer #1,234, pleasure to see you")] - public void AlignmentStringsArePropagated(string value, string expected) - { - Assert.Equal(expected, Render(value, 1234)); - } - - [Fact] - public void FormatProviderIsUsed() - { - var m = Render(new CultureInfo("fr-FR"), "Please pay {Sum}", 12.345); - Assert.Equal("Please pay 12,345", m); - } - - static string Render(string messageTemplate, params object[] properties) - { - return Render(null, messageTemplate, properties); - } - - static string Render(IFormatProvider? formatProvider, string messageTemplate, params object[] properties) - { - var binder = new LoggerConfiguration().CreateLogger(); - if (binder.BindMessageTemplate(messageTemplate, properties, out var mt, out var props) == false) - throw new InvalidOperationException(); - - var output = new StringBuilder(); - var writer = new StringWriter(output); - var renderer = new ThemedMessageTemplateRenderer(ConsoleTheme.None, - new ThemedDisplayValueFormatter(ConsoleTheme.None, formatProvider), false); - renderer.Render(mt, props.ToDictionary(p => p.Name, p => p.Value), writer); - writer.Flush(); - return output.ToString(); - } - - [Fact] - public void ATemplateWithOnlyPositionalPropertiesIsAnalyzedAndRenderedPositionally() - { - var m = Render("{1}, {0}", "world", "Hello"); - Assert.Equal("\"Hello\", \"world\"", m); - } - - [Fact] - public void ATemplateWithOnlyPositionalPropertiesUsesFormatProvider() - { - var m = Render(new CultureInfo("fr-FR"), "{1}, {0}", 12.345, "Hello"); - Assert.Equal("\"Hello\", 12,345", m); - } - - // Debatable what the behavior should be, here. - [Fact] - public void ATemplateWithNamesAndPositionalsUsesNamesForAllValues() - { - var m = Render("{1}, {Place}", "world", "Hello"); - Assert.Equal("\"world\", \"Hello\"", m); - } - - [Fact] - public void MissingPositionalParametersRenderAsTextLikeStandardFormats() - { - var m = Render("{1}, {0}", "world"); - Assert.Equal("{1}, \"world\"", m); - } - - [Fact] - public void AnonymousTypeShouldBeRendered() - { - var anonymous = new { Test = 3M }; - var m = Render("Anonymous type {value}", anonymous); - Assert.Equal("Anonymous type \"{ Test = 3 }\"", m); - } - - [Fact] - public void EnumerableOfAnonymousTypeShouldBeRendered() - { - var anonymous = new { Foo = 4M, Bar = "Baz" }; - var enumerable = Enumerable.Repeat("MyKey", 1).Select(v => anonymous); - var m = Render("Enumerable with anonymous type {enumerable}", enumerable); - Assert.Equal("Enumerable with anonymous type [\"{ Foo = 4, Bar = Baz }\"]", m); - } - - [Fact] - public void DictionaryOfAnonymousTypeAsValueShouldBeRendered() - { - var anonymous = new { Test = 5M }; - var dictionary = Enumerable.Repeat("MyKey", 1).ToDictionary(v => v, v => anonymous); - var m = Render("Dictionary with anonymous type value {dictionary}", dictionary); - Assert.Equal("Dictionary with anonymous type value {[\"MyKey\"]=\"{ Test = 5 }\"}", m); - } - - [Fact] - public void DictionaryOfAnonymousTypeAsKeyShouldBeRendered() - { - var anonymous = new { Bar = 6M, Baz = 4M }; - var dictionary = Enumerable.Repeat("MyValue", 1).ToDictionary(v => anonymous, v => v); - var m = Render("Dictionary with anonymous type key {dictionary}", dictionary); - Assert.Equal("Dictionary with anonymous type key [\"[{ Bar = 6, Baz = 4 }, MyValue]\"]", m); - } - } -} \ No newline at end of file + class Chair + { + // ReSharper disable UnusedMember.Local + public string Back => "straight"; + + public int[] Legs => new[] { 1, 2, 3, 4 }; + + // ReSharper restore UnusedMember.Local + public override string ToString() => "a chair"; + } + + class Receipt + { + // ReSharper disable UnusedMember.Local + public decimal Sum => 12.345m; + + public DateTime When => new(2013, 5, 20, 16, 39, 0); + + // ReSharper restore UnusedMember.Local + public override string ToString() => "a receipt"; + } + + [Fact] + public void AnObjectIsRenderedInSimpleNotation() + { + var m = Render("I sat at {@Chair}", new Chair()); + Assert.Equal("I sat at Chair {Back=\"straight\", Legs=[1, 2, 3, 4]}", m); + } + + [Fact] + public void AnObjectIsRenderedInSimpleNotationUsingFormatProvider() + { + var m = Render(new CultureInfo("fr-FR"), "I received {@Receipt}", new Receipt()); + Assert.Equal("I received Receipt {Sum=12,345, When=20/05/2013 16:39:00}", m); + } + + [Fact] + public void AnAnonymousObjectIsRenderedInSimpleNotationWithoutType() + { + var m = Render("I sat at {@Chair}", new { Back = "straight", Legs = new[] { 1, 2, 3, 4 } }); + Assert.Equal("I sat at {Back=\"straight\", Legs=[1, 2, 3, 4]}", m); + } + + [Fact] + public void AnAnonymousObjectIsRenderedInSimpleNotationWithoutTypeUsingFormatProvider() + { + var m = Render(new CultureInfo("fr-FR"), "I received {@Receipt}", new { Sum = 12.345, When = new DateTime(2013, 5, 20, 16, 39, 0) }); + Assert.Equal("I received {Sum=12,345, When=20/05/2013 16:39:00}", m); + } + + [Fact] + public void AnObjectWithDefaultDestructuringIsRenderedAsAStringLiteral() + { + var m = Render("I sat at {Chair}", new Chair()); + Assert.Equal("I sat at \"a chair\"", m); + } + + [Fact] + public void AnObjectWithStringifyDestructuringIsRenderedAsAString() + { + var m = Render("I sat at {$Chair}", new Chair()); + Assert.Equal("I sat at \"a chair\"", m); + } + + [Fact] + public void MultiplePropertiesAreRenderedInOrder() + { + var m = Render("Just biting {Fruit} number {Count}", "Apple", 12); + Assert.Equal("Just biting \"Apple\" number 12", m); + } + + [Fact] + public void MultiplePropertiesUseFormatProvider() + { + var m = Render(new CultureInfo("fr-FR"), "Income was {Income} at {Date:d}", 1234.567, new DateTime(2013, 5, 20)); + Assert.Equal("Income was 1234,567 at 20/05/2013", m); + } + + [Fact] + public void FormatStringsArePropagated() + { + var m = Render("Welcome, customer {CustomerId:0000}", 12); + Assert.Equal("Welcome, customer 0012", m); + } + + [Theory] + [InlineData("Welcome, customer #{CustomerId,-10}, pleasure to see you", "Welcome, customer #1234 , pleasure to see you")] + [InlineData("Welcome, customer #{CustomerId,-10:000000}, pleasure to see you", "Welcome, customer #001234 , pleasure to see you")] + [InlineData("Welcome, customer #{CustomerId,10}, pleasure to see you", "Welcome, customer # 1234, pleasure to see you")] + [InlineData("Welcome, customer #{CustomerId,10:000000}, pleasure to see you", "Welcome, customer # 001234, pleasure to see you")] + [InlineData("Welcome, customer #{CustomerId,10:0,0}, pleasure to see you", "Welcome, customer # 1,234, pleasure to see you")] + [InlineData("Welcome, customer #{CustomerId:0,0}, pleasure to see you", "Welcome, customer #1,234, pleasure to see you")] + public void AlignmentStringsArePropagated(string value, string expected) + { + Assert.Equal(expected, Render(value, 1234)); + } + + [Fact] + public void FormatProviderIsUsed() + { + var m = Render(new CultureInfo("fr-FR"), "Please pay {Sum}", 12.345); + Assert.Equal("Please pay 12,345", m); + } + + static string Render(string messageTemplate, params object[] properties) + { + return Render(null, messageTemplate, properties); + } + + static string Render(IFormatProvider? formatProvider, string messageTemplate, params object[] properties) + { + var binder = new LoggerConfiguration().CreateLogger(); + if (binder.BindMessageTemplate(messageTemplate, properties, out var mt, out var props) == false) + throw new InvalidOperationException(); + + var output = new StringBuilder(); + var writer = new StringWriter(output); + var renderer = new ThemedMessageTemplateRenderer(ConsoleTheme.None, + new ThemedDisplayValueFormatter(ConsoleTheme.None, formatProvider), false); + renderer.Render(mt, props.ToDictionary(p => p.Name, p => p.Value), writer); + writer.Flush(); + return output.ToString(); + } + + [Fact] + public void ATemplateWithOnlyPositionalPropertiesIsAnalyzedAndRenderedPositionally() + { + var m = Render("{1}, {0}", "world", "Hello"); + Assert.Equal("\"Hello\", \"world\"", m); + } + + [Fact] + public void ATemplateWithOnlyPositionalPropertiesUsesFormatProvider() + { + var m = Render(new CultureInfo("fr-FR"), "{1}, {0}", 12.345, "Hello"); + Assert.Equal("\"Hello\", 12,345", m); + } + + // Debatable what the behavior should be, here. + [Fact] + public void ATemplateWithNamesAndPositionalsUsesNamesForAllValues() + { + var m = Render("{1}, {Place}", "world", "Hello"); + Assert.Equal("\"world\", \"Hello\"", m); + } + + [Fact] + public void MissingPositionalParametersRenderAsTextLikeStandardFormats() + { + var m = Render("{1}, {0}", "world"); + Assert.Equal("{1}, \"world\"", m); + } + + [Fact] + public void AnonymousTypeShouldBeRendered() + { + var anonymous = new { Test = 3M }; + var m = Render("Anonymous type {value}", anonymous); + Assert.Equal("Anonymous type \"{ Test = 3 }\"", m); + } + + [Fact] + public void EnumerableOfAnonymousTypeShouldBeRendered() + { + var anonymous = new { Foo = 4M, Bar = "Baz" }; + var enumerable = Enumerable.Repeat("MyKey", 1).Select(v => anonymous); + var m = Render("Enumerable with anonymous type {enumerable}", enumerable); + Assert.Equal("Enumerable with anonymous type [\"{ Foo = 4, Bar = Baz }\"]", m); + } + + [Fact] + public void DictionaryOfAnonymousTypeAsValueShouldBeRendered() + { + var anonymous = new { Test = 5M }; + var dictionary = Enumerable.Repeat("MyKey", 1).ToDictionary(v => v, v => anonymous); + var m = Render("Dictionary with anonymous type value {dictionary}", dictionary); + Assert.Equal("Dictionary with anonymous type value {[\"MyKey\"]=\"{ Test = 5 }\"}", m); + } + + [Fact] + public void DictionaryOfAnonymousTypeAsKeyShouldBeRendered() + { + var anonymous = new { Bar = 6M, Baz = 4M }; + var dictionary = Enumerable.Repeat("MyValue", 1).ToDictionary(v => anonymous, v => v); + var m = Render("Dictionary with anonymous type key {dictionary}", dictionary); + Assert.Equal("Dictionary with anonymous type key [\"[{ Bar = 6, Baz = 4 }, MyValue]\"]", m); + } +} diff --git a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj index 57b8025..8adb7d6 100644 --- a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj +++ b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj @@ -1,13 +1,8 @@ - + - netcoreapp2.1;netcoreapp2.2;netcoreapp3.0;netcoreapp3.1;net452;net462;net472;net48;net5.0 + netcoreapp2.1;netcoreapp2.2;netcoreapp3.0;netcoreapp3.1;net452;net462;net472;net48;net5.0;net7.0 true - ../../assets/Serilog.snk - true - true - 8.0 - enable @@ -15,12 +10,12 @@ - + - + - + diff --git a/test/Serilog.Sinks.Console.Tests/Support/DelegatingSink.cs b/test/Serilog.Sinks.Console.Tests/Support/DelegatingSink.cs index 1863a41..6bcdd34 100644 --- a/test/Serilog.Sinks.Console.Tests/Support/DelegatingSink.cs +++ b/test/Serilog.Sinks.Console.Tests/Support/DelegatingSink.cs @@ -1,33 +1,31 @@ -using System; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; -namespace Serilog.Sinks.Console.Tests.Support +namespace Serilog.Sinks.Console.Tests.Support; + +public class DelegatingSink : ILogEventSink { - public class DelegatingSink : ILogEventSink - { - readonly Action _write; + readonly Action _write; - public DelegatingSink(Action write) - { - _write = write ?? throw new ArgumentNullException(nameof(write)); - } + public DelegatingSink(Action write) + { + _write = write ?? throw new ArgumentNullException(nameof(write)); + } - public void Emit(LogEvent logEvent) - { - _write(logEvent); - } + public void Emit(LogEvent logEvent) + { + _write(logEvent); + } - public static LogEvent GetLogEvent(Action writeAction) - { - LogEvent? result = null; - var logger = new LoggerConfiguration() - .MinimumLevel.Verbose() - .WriteTo.Sink(new DelegatingSink(le => result = le)) - .CreateLogger(); + public static LogEvent GetLogEvent(Action writeAction) + { + LogEvent? result = null; + var logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Sink(new DelegatingSink(le => result = le)) + .CreateLogger(); - writeAction(logger); - return result!; - } + writeAction(logger); + return result!; } } diff --git a/test/Serilog.Sinks.Console.Tests/Support/TracingConsoleTheme.cs b/test/Serilog.Sinks.Console.Tests/Support/TracingConsoleTheme.cs index 901315e..85b930c 100644 --- a/test/Serilog.Sinks.Console.Tests/Support/TracingConsoleTheme.cs +++ b/test/Serilog.Sinks.Console.Tests/Support/TracingConsoleTheme.cs @@ -1,26 +1,24 @@ -using System.IO; using Serilog.Sinks.SystemConsole.Themes; -namespace Serilog.Sinks.SystemConsole.Tests +namespace Serilog.Sinks.SystemConsole.Tests; + +class TracingConsoleTheme : ConsoleTheme { - class TracingConsoleTheme : ConsoleTheme - { - const string End = ""; + const string End = ""; - public override bool CanBuffer => true; + public override bool CanBuffer => true; - protected override int ResetCharCount { get; } = End.Length; + protected override int ResetCharCount { get; } = End.Length; - public override int Set(TextWriter output, ConsoleThemeStyle style) - { - var start = $"<{style.ToString().ToLowerInvariant()}>"; - output.Write(start); - return start.Length; - } + public override int Set(TextWriter output, ConsoleThemeStyle style) + { + var start = $"<{style.ToString().ToLowerInvariant()}>"; + output.Write(start); + return start.Length; + } - public override void Reset(TextWriter output) - { - output.Write(End); - } + public override void Reset(TextWriter output) + { + output.Write(End); } } \ No newline at end of file From eb110d5482ba37f014d01a8038d6f9b8210b3c29 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Tue, 14 Mar 2023 09:46:26 +0300 Subject: [PATCH 2/5] fix CI --- build.sh | 16 ++++------------ serilog-sinks-console.sln | 1 + 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/build.sh b/build.sh index 64d87ea..0f6a946 100755 --- a/build.sh +++ b/build.sh @@ -1,18 +1,10 @@ #!/bin/bash set -e -dotnet --info -dotnet restore -for path in src/**/*.csproj; do - dotnet build -f netstandard2.0 -c Release ${path} -done +echo "🤖 Attempting to build..." -for path in test/*.Tests/*.csproj; do - dotnet test -f netcoreapp2.2 -c Release ${path} -done +dotnet build --configuration Release -for path in sample/ConsoleDemo/*.csproj; do - dotnet build -f netcoreapp2.2 -c Release ${path} - dotnet run -f netcoreapp2.2 --project ${path} -done +echo "🤖 Running tests..." +dotnet test test/Serilog.Sinks.Console.Tests --configuration Release --no-build --no-restore diff --git a/serilog-sinks-console.sln b/serilog-sinks-console.sln index 5c0fcd4..66816c7 100644 --- a/serilog-sinks-console.sln +++ b/serilog-sinks-console.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5 .gitignore = .gitignore appveyor.yml = appveyor.yml Build.ps1 = Build.ps1 + build.sh = build.sh CHANGES.md = CHANGES.md Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets From d76fe3b41860afd3506464ccee09ff2ed36e81cd Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Tue, 14 Mar 2023 10:38:13 +0300 Subject: [PATCH 3/5] fix CI 2 --- Build.ps1 | 47 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/Build.ps1 b/Build.ps1 index 394f6fb..184dffe 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -1,8 +1,5 @@ Write-Output "build: Build started" -& dotnet --info -& dotnet --list-sdks - Push-Location $PSScriptRoot if(Test-Path .\artifacts) { @@ -10,8 +7,6 @@ if(Test-Path .\artifacts) { Remove-Item .\artifacts -Force -Recurse } -& dotnet restore --no-cache - $branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$env:APPVEYOR_REPO_BRANCH -ne $NULL]; $revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:APPVEYOR_BUILD_NUMBER, 10); $false = "local" }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL]; $suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)))-$revision"}[$branch -eq "main" -and $revision -ne "local"] @@ -21,42 +16,20 @@ $buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($c Write-Output "build: Package version suffix is $suffix" Write-Output "build: Build version suffix is $buildSuffix" -foreach ($src in Get-ChildItem src/*) { - Push-Location $src - - Write-Output "build: Packaging project in $src" - - & dotnet build -c Release --version-suffix=$buildSuffix - if ($suffix) { - & dotnet pack -c Release --include-source -o ..\..\artifacts --version-suffix=$suffix --no-build - } else { - & dotnet pack -c Release --include-source -o ..\..\artifacts --no-build - } - if($LASTEXITCODE -ne 0) { exit 1 } - - Pop-Location -} - -foreach ($sample in Get-ChildItem sample/*) { - Push-Location $sample - - Write-Output "build: Testing project in $sample" +& dotnet build --configuration Release --version-suffix=$buildSuffix /p:ContinuousIntegrationBuild=true - & dotnet build -c Release --version-suffix=$buildSuffix - if($LASTEXITCODE -ne 0) { exit 3 } +if($LASTEXITCODE -ne 0) { exit 1 } - Pop-Location +if($suffix) { + & dotnet pack src\Serilog.Sinks.Console --configuration Release --no-build --no-restore -o artifacts --version-suffix=$suffix +} else { + & dotnet pack src\Serilog.Sinks.Console --configuration Release --no-build --no-restore -o artifacts } -foreach ($test in Get-ChildItem test/*.Tests) { - Push-Location $test +if($LASTEXITCODE -ne 0) { exit 2 } - Write-Output "build: Testing project in $test" +Write-Output "build: Testing" - & dotnet test -c Release - if($LASTEXITCODE -ne 0) { exit 3 } - - Pop-Location -} +& dotnet test test\Serilog.Sinks.Console.Tests --configuration Release --no-build --no-restore -Pop-Location +if($LASTEXITCODE -ne 0) { exit 3 } From bb2a3e74d9741ae8bcc82824075cf7c5ffb277c5 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Tue, 14 Mar 2023 10:42:59 +0300 Subject: [PATCH 4/5] revert versions --- .../Serilog.Sinks.Console.Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj index 8adb7d6..f2594ee 100644 --- a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj +++ b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj @@ -10,9 +10,9 @@ - + - + From 7469b215c437e4ee53ba2c899a71c5f5cb97b998 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Sat, 16 Mar 2024 11:05:02 +0300 Subject: [PATCH 5/5] more --- .../SystemConsole/Output/LevelOutputFormat.cs | 48 +++++++++---------- .../Approval/ApiApprovalTests.cs | 15 ++---- .../ThemedDisplayValueFormatterTests.cs | 4 +- .../ThemedJsonValueFormatterTests.cs | 6 +-- .../ThemedMessageTemplateRendererTests.cs | 2 +- .../Serilog.Sinks.Console.Tests.csproj | 10 ++-- 6 files changed, 40 insertions(+), 45 deletions(-) diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs index 5979764..3820273 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/LevelOutputFormat.cs @@ -25,32 +25,32 @@ namespace Serilog.Sinks.SystemConsole.Output; /// static class LevelOutputFormat { - static readonly string[][] TitleCaseLevelMap = { - new []{ "V", "Vb", "Vrb", "Verb", "Verbo", "Verbos", "Verbose" }, - new []{ "D", "De", "Dbg", "Dbug", "Debug" }, - new []{ "I", "In", "Inf", "Info", "Infor", "Inform", "Informa", "Informat", "Informati", "Informatio", "Information" }, - new []{ "W", "Wn", "Wrn", "Warn", "Warni", "Warnin", "Warning" }, - new []{ "E", "Er", "Err", "Eror", "Error" }, - new []{ "F", "Fa", "Ftl", "Fatl", "Fatal" } - }; + static readonly string[][] TitleCaseLevelMap = [ + ["V", "Vb", "Vrb", "Verb", "Verbo", "Verbos", "Verbose"], + ["D", "De", "Dbg", "Dbug", "Debug"], + ["I", "In", "Inf", "Info", "Infor", "Inform", "Informa", "Informat", "Informati", "Informatio", "Information"], + ["W", "Wn", "Wrn", "Warn", "Warni", "Warnin", "Warning"], + ["E", "Er", "Err", "Eror", "Error"], + ["F", "Fa", "Ftl", "Fatl", "Fatal"] + ]; - static readonly string[][] LowerCaseLevelMap = { - new []{ "v", "vb", "vrb", "verb", "verbo", "verbos", "verbose" }, - new []{ "d", "de", "dbg", "dbug", "debug" }, - new []{ "i", "in", "inf", "info", "infor", "inform", "informa", "informat", "informati", "informatio", "information" }, - new []{ "w", "wn", "wrn", "warn", "warni", "warnin", "warning" }, - new []{ "e", "er", "err", "eror", "error" }, - new []{ "f", "fa", "ftl", "fatl", "fatal" } - }; + static readonly string[][] LowerCaseLevelMap = [ + ["v", "vb", "vrb", "verb", "verbo", "verbos", "verbose"], + ["d", "de", "dbg", "dbug", "debug"], + ["i", "in", "inf", "info", "infor", "inform", "informa", "informat", "informati", "informatio", "information"], + ["w", "wn", "wrn", "warn", "warni", "warnin", "warning"], + ["e", "er", "err", "eror", "error"], + ["f", "fa", "ftl", "fatl", "fatal"] + ]; - static readonly string[][] UpperCaseLevelMap = { - new []{ "V", "VB", "VRB", "VERB", "VERBO", "VERBOS", "VERBOSE" }, - new []{ "D", "DE", "DBG", "DBUG", "DEBUG" }, - new []{ "I", "IN", "INF", "INFO", "INFOR", "INFORM", "INFORMA", "INFORMAT", "INFORMATI", "INFORMATIO", "INFORMATION" }, - new []{ "W", "WN", "WRN", "WARN", "WARNI", "WARNIN", "WARNING" }, - new []{ "E", "ER", "ERR", "EROR", "ERROR" }, - new []{ "F", "FA", "FTL", "FATL", "FATAL" } - }; + static readonly string[][] UpperCaseLevelMap = [ + ["V", "VB", "VRB", "VERB", "VERBO", "VERBOS", "VERBOSE"], + ["D", "DE", "DBG", "DBUG", "DEBUG"], + ["I", "IN", "INF", "INFO", "INFOR", "INFORM", "INFORMA", "INFORMAT", "INFORMATI", "INFORMATIO", "INFORMATION"], + ["W", "WN", "WRN", "WARN", "WARNI", "WARNIN", "WARNING"], + ["E", "ER", "ERR", "EROR", "ERROR"], + ["F", "FA", "FTL", "FATL", "FATAL"] + ]; public static string GetLevelMoniker(LogEventLevel value, string? format = null) { diff --git a/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs b/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs index 1ef07b7..4f8b8f0 100644 --- a/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Approval/ApiApprovalTests.cs @@ -1,5 +1,3 @@ -#if NET7_0 - using PublicApiGenerator; using Shouldly; using Xunit; @@ -12,15 +10,12 @@ public class ApiApprovalTests public void PublicApi_Should_Not_Change_Unintentionally() { var assembly = typeof(ConsoleLoggerConfigurationExtensions).Assembly; - var publicApi = assembly.GeneratePublicApi( - new ApiGeneratorOptions() - { - IncludeAssemblyAttributes = false, - ExcludeAttributes = new[] { "System.Diagnostics.DebuggerDisplayAttribute" }, - }); + var publicApi = assembly.GeneratePublicApi(new() + { + IncludeAssemblyAttributes = false, + ExcludeAttributes = ["System.Diagnostics.DebuggerDisplayAttribute"], + }); publicApi.ShouldMatchApproved(options => options.WithFilenameGenerator((_, __, fileType, fileExtension) => $"{assembly.GetName().Name!}.{fileType}.{fileExtension}")); } } - -#endif diff --git a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs index fe94aa5..8df75db 100644 --- a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedDisplayValueFormatterTests.cs @@ -1,4 +1,4 @@ -using Serilog.Events; +using Serilog.Events; using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Themes; using Xunit; @@ -10,7 +10,7 @@ public class ThemedDisplayValueFormatterTests [Theory] [InlineData("Hello", null, "\"Hello\"")] [InlineData("Hello", "l", "Hello")] - public void StringFormattingIsApplied(string value, string format, string expected) + public void StringFormattingIsApplied(string value, string? format, string expected) { var formatter = new ThemedDisplayValueFormatter(ConsoleTheme.None, null); var sw = new StringWriter(); diff --git a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs index af82fdd..bda1240 100644 --- a/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Formatting/ThemedJsonValueFormatterTests.cs @@ -1,4 +1,4 @@ -using Serilog.Events; +using Serilog.Events; using Serilog.Sinks.SystemConsole.Formatting; using Serilog.Sinks.SystemConsole.Themes; using Xunit; @@ -14,7 +14,7 @@ public TestThemedJsonValueFormatter() { } - public string Format(object literal) + public string Format(object? literal) { var output = new StringWriter(); Format(new SequenceValue(new[] { new ScalarValue(literal) }), output, null); @@ -32,7 +32,7 @@ public string Format(object literal) [InlineData("\u0001", "\"\\u0001\"")] [InlineData("a\nb", "\"a\\nb\"")] [InlineData(null, "null")] - public void JsonLiteralTypesAreFormatted(object value, string expectedJson) + public void JsonLiteralTypesAreFormatted(object? value, string expectedJson) { var formatter = new TestThemedJsonValueFormatter(); Assert.Equal(expectedJson, formatter.Format(value)); diff --git a/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs index c822e05..e2ca385 100644 --- a/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Rendering/ThemedMessageTemplateRendererTests.cs @@ -14,7 +14,7 @@ class Chair // ReSharper disable UnusedMember.Local public string Back => "straight"; - public int[] Legs => new[] { 1, 2, 3, 4 }; + public int[] Legs => [1, 2, 3, 4]; // ReSharper restore UnusedMember.Local public override string ToString() => "a chair"; diff --git a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj index 159f49e..9a58ac4 100644 --- a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj +++ b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj @@ -10,12 +10,12 @@ - - - + + + - - + +