From 828e6d5a13b61aa6c8d0b92aeb0a8c120a7faa31 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 10 Jun 2024 08:10:05 +1000 Subject: [PATCH 01/15] Dev version bump [skip ci] --- src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj index 38a3d4f..f57adf9 100644 --- a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj +++ b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj @@ -1,7 +1,7 @@ A Serilog sink that writes log events to the console/terminal. - 6.0.0 + 6.0.1 Serilog Contributors net462;net471 $(TargetFrameworks);netstandard2.0;net6.0;net8.0 From cbcd22bc92f82daafb24a87256ac6f59ce64c1df Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Tue, 3 Dec 2024 09:59:10 +0100 Subject: [PATCH 02/15] Add unit tests for OutputTemplateRenderer for new UtcTimestamp token (TDD) Addresses #164 --- .../Output/OutputTemplateRendererTests.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs index 8e5f731..1a07ac0 100644 --- a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs @@ -400,4 +400,28 @@ public void TraceAndSpanAreIncludedWhenPresent() formatter.Format(evt, sw); Assert.Equal($"{traceId}/{spanId}", sw.ToString()); } + + [Fact] + public void TimestampTokenRendersLocalTime() + { + var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Timestamp:yyyy-MM-dd HH:mm:ss}", CultureInfo.InvariantCulture); + var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Information, null, MessageTemplate.Empty, Array.Empty()); + var sw = new StringWriter(); + formatter.Format(evt, sw); + // expect time in local time, unchanged from the input, the +02:00 offset should not affect the output + Assert.Equal("2024-09-03 14:15:16", sw.ToString()); + } + + [Fact] + public void UtcTimestampTokenRendersUtcTime() + { + var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{UtcTimestamp:yyyy-MM-dd HH:mm:ss}", CultureInfo.InvariantCulture); + var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Information, null, MessageTemplate.Empty, Array.Empty()); + var sw = new StringWriter(); + formatter.Format(evt, sw); + // expect time in UTC, the +02:00 offset must be applied to adjust the hour + Assert.Equal("2024-09-03 12:15:16", sw.ToString()); + } } \ No newline at end of file From 2c127720d421f8abeb03ce2e50582873659b5b7d Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Tue, 3 Dec 2024 10:02:13 +0100 Subject: [PATCH 03/15] Add support for Serilog 4.0 built-in UtcTimestamp token in output template (OutputTemplateRenderer) Implements #164 --- .../SystemConsole/Output/OutputTemplateRenderer.cs | 6 +++++- .../SystemConsole/Output/TimestampTokenRenderer.cs | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs index 2f8c743..6e4f561 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/OutputTemplateRenderer.cs @@ -68,7 +68,11 @@ public OutputTemplateRenderer(ConsoleTheme theme, string outputTemplate, IFormat } else if (pt.PropertyName == OutputProperties.TimestampPropertyName) { - renderers.Add(new TimestampTokenRenderer(theme, pt, formatProvider)); + renderers.Add(new TimestampTokenRenderer(theme, pt, formatProvider, convertToUtc: false)); + } + else if (pt.PropertyName == OutputProperties.UtcTimestampPropertyName) + { + renderers.Add(new TimestampTokenRenderer(theme, pt, formatProvider, convertToUtc: true)); } else if (pt.PropertyName == OutputProperties.PropertiesPropertyName) { diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs index 7c4de83..390a337 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs @@ -27,17 +27,22 @@ class TimestampTokenRenderer : OutputTemplateTokenRenderer readonly ConsoleTheme _theme; readonly PropertyToken _token; readonly IFormatProvider? _formatProvider; + readonly bool _convertToUtc; - public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider) + public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider, bool convertToUtc) { _theme = theme; _token = token; _formatProvider = formatProvider; - } + _convertToUtc = convertToUtc; + } public override void Render(LogEvent logEvent, TextWriter output) { - var sv = new DateTimeOffsetValue(logEvent.Timestamp); + var timestamp = _convertToUtc + ? logEvent.Timestamp.ToUniversalTime() + : logEvent.Timestamp; + var sv = new DateTimeOffsetValue(timestamp); var _ = 0; using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) From 5a730233d1963441c522c2ff196b2fee799dad33 Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Wed, 4 Dec 2024 22:23:39 +0100 Subject: [PATCH 04/15] Unit test setup streamlined with earlier existing similar test setup --- .../Output/OutputTemplateRendererTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs index 1a07ac0..86cead5 100644 --- a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs @@ -406,7 +406,8 @@ public void TimestampTokenRendersLocalTime() { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Timestamp:yyyy-MM-dd HH:mm:ss}", CultureInfo.InvariantCulture); - var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Information, null, MessageTemplate.Empty, Array.Empty()); + var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, + new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in local time, unchanged from the input, the +02:00 offset should not affect the output @@ -418,7 +419,8 @@ public void UtcTimestampTokenRendersUtcTime() { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{UtcTimestamp:yyyy-MM-dd HH:mm:ss}", CultureInfo.InvariantCulture); - var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Information, null, MessageTemplate.Empty, Array.Empty()); + var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, + new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in UTC, the +02:00 offset must be applied to adjust the hour From 513456038880ee5f863ad4916192feb7f2d2ebdd Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Thu, 5 Dec 2024 00:06:14 +0100 Subject: [PATCH 05/15] Unit tests for OutputTemplateRenderer for UtcTimestamp token enhanced - assert that UtcTimestamp in default format (no custom format string) renders without the +00:00 time-zone suffix. Relates to #164 --- .../Output/OutputTemplateRendererTests.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs index 86cead5..3297787 100644 --- a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs @@ -405,25 +405,29 @@ public void TraceAndSpanAreIncludedWhenPresent() public void TimestampTokenRendersLocalTime() { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{Timestamp:yyyy-MM-dd HH:mm:ss}", CultureInfo.InvariantCulture); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, + "Default Format: {Timestamp} / Custom Format String: {Timestamp:yyyy-MM-dd HH:mm:ss}", + CultureInfo.InvariantCulture); var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in local time, unchanged from the input, the +02:00 offset should not affect the output - Assert.Equal("2024-09-03 14:15:16", sw.ToString()); + Assert.Equal("Default Format: 09/03/2024 14:15:16 +02:00 / Custom Format String: 2024-09-03 14:15:16", sw.ToString()); } [Fact] public void UtcTimestampTokenRendersUtcTime() { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, "{UtcTimestamp:yyyy-MM-dd HH:mm:ss}", CultureInfo.InvariantCulture); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, + "Default Format: {UtcTimestamp} / Custom Format String: {UtcTimestamp:yyyy-MM-dd HH:mm:ss}", + CultureInfo.InvariantCulture); var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in UTC, the +02:00 offset must be applied to adjust the hour - Assert.Equal("2024-09-03 12:15:16", sw.ToString()); + Assert.Equal("Default Format: 09/03/2024 12:15:16 / Custom Format String: 2024-09-03 12:15:16", sw.ToString()); } } \ No newline at end of file From 4c0dc6f66ca50ba491b8cb5e5c5d044284f0acc0 Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Wed, 4 Dec 2024 23:21:05 +0100 Subject: [PATCH 06/15] TimestampTokenRenderer indentation fixed --- .../Output/TimestampTokenRenderer.cs | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs index 390a337..599e868 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs @@ -31,10 +31,10 @@ class TimestampTokenRenderer : OutputTemplateTokenRenderer public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider, bool convertToUtc) { - _theme = theme; - _token = token; - _formatProvider = formatProvider; - _convertToUtc = convertToUtc; + _theme = theme; + _token = token; + _formatProvider = formatProvider; + _convertToUtc = convertToUtc; } public override void Render(LogEvent logEvent, TextWriter output) @@ -44,29 +44,29 @@ public override void Render(LogEvent logEvent, TextWriter output) : logEvent.Timestamp; var sv = new DateTimeOffsetValue(timestamp); - var _ = 0; - using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) + var _ = 0; + using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) + { + if (_token.Alignment is null) + { + sv.Render(output, _token.Format, _formatProvider); + } + else { - 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); - } + var buffer = new StringWriter(); + sv.Render(buffer, _token.Format, _formatProvider); + var str = buffer.ToString(); + Padding.Apply(output, str, _token.Alignment); } } + } readonly struct DateTimeOffsetValue { public DateTimeOffsetValue(DateTimeOffset value) { - Value = value; - } + Value = value; + } public DateTimeOffset Value { get; } @@ -80,11 +80,11 @@ public void Render(TextWriter output, string? format = null, IFormatProvider? fo } #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)); + 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 From e9c53a775b814ba4552e0b772b8448dca564f00b Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Thu, 5 Dec 2024 00:04:09 +0100 Subject: [PATCH 07/15] TimestampTokenRenderer simplified and UtcTimestamp support fixed for standard formating - keep render performance in mind / i.e. keep optimizations from #134 - ensure UtcTimestamp without format string is rendered without " +00:00" suffix by rendering as DateTime (same behavior as Serilog's MessageTemplateTextFormatter) Relates to #164 --- .../Output/TimestampTokenRenderer.cs | 69 ++++++++++++------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs index 599e868..66bdf4d 100644 --- a/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs +++ b/src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs @@ -26,6 +26,7 @@ class TimestampTokenRenderer : OutputTemplateTokenRenderer { readonly ConsoleTheme _theme; readonly PropertyToken _token; + readonly string? _format; readonly IFormatProvider? _formatProvider; readonly bool _convertToUtc; @@ -33,61 +34,77 @@ public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatPr { _theme = theme; _token = token; + _format = token.Format; _formatProvider = formatProvider; _convertToUtc = convertToUtc; } public override void Render(LogEvent logEvent, TextWriter output) { - var timestamp = _convertToUtc - ? logEvent.Timestamp.ToUniversalTime() - : logEvent.Timestamp; - var sv = new DateTimeOffsetValue(timestamp); - var _ = 0; using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _)) { if (_token.Alignment is null) { - sv.Render(output, _token.Format, _formatProvider); + Render(output, logEvent.Timestamp); } else { var buffer = new StringWriter(); - sv.Render(buffer, _token.Format, _formatProvider); + Render(buffer, logEvent.Timestamp); var str = buffer.ToString(); Padding.Apply(output, str, _token.Alignment); } } } - readonly struct DateTimeOffsetValue + private void Render(TextWriter output, DateTimeOffset timestamp) { - public DateTimeOffsetValue(DateTimeOffset value) + // When a DateTimeOffset is converted to a string, the default format automatically adds the "+00:00" explicit offset to the output string. + // As the TimestampTokenRenderer is also used for rendering the UtcTimestamp which is always in UTC by definition, the +00:00 suffix should be avoided. + // This is done using the same approach as Serilog's MessageTemplateTextFormatter. In case output should be converted to UTC, in order to avoid a zone specifier, + // the DateTimeOffset is converted to a DateTime which then renders as expected. + + var custom = (ICustomFormatter?)_formatProvider?.GetFormat(typeof(ICustomFormatter)); + if (custom != null) { - Value = value; + output.Write(custom.Format(_format, _convertToUtc ? timestamp.UtcDateTime : timestamp, _formatProvider)); + return; } - public DateTimeOffset Value { get; } - - public void Render(TextWriter output, string? format = null, IFormatProvider? formatProvider = null) + if (_convertToUtc) { - var custom = (ICustomFormatter?)formatProvider?.GetFormat(typeof(ICustomFormatter)); - if (custom != null) - { - output.Write(custom.Format(format, Value, formatProvider)); - return; - } + RenderDateTime(output, timestamp.UtcDateTime); + } + else + { + RenderDateTimeOffset(output, timestamp); + } + } + private void RenderDateTimeOffset(TextWriter output, DateTimeOffset timestamp) + { #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)); + Span buffer = stackalloc char[32]; + if (timestamp.TryFormat(buffer, out int written, _format, _formatProvider ?? CultureInfo.InvariantCulture)) + output.Write(buffer.Slice(0, written)); + else + output.Write(timestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture)); #else - output.Write(Value.ToString(format, formatProvider ?? CultureInfo.InvariantCulture)); + output.Write(timestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture)); +#endif + } + + private void RenderDateTime(TextWriter output, DateTime utcTimestamp) + { +#if FEATURE_SPAN + Span buffer = stackalloc char[32]; + if (utcTimestamp.TryFormat(buffer, out int written, _format, _formatProvider ?? CultureInfo.InvariantCulture)) + output.Write(buffer.Slice(0, written)); + else + output.Write(utcTimestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture)); +#else + output.Write(utcTimestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture)); #endif - } } } \ No newline at end of file From 88762fc6ee87cee70a1e8d92465b1b2c2229fc54 Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Mon, 17 Feb 2025 23:09:46 +0100 Subject: [PATCH 08/15] Unit tests for OutputTemplateRenderer for UtcTimestamp/Timestamp token enhanced - round-trip standard format string added to tests - for Timestamp the +00:00 format is expected, for UtcTimestamp the Z suffix is expected Relates to #164 --- .../Output/OutputTemplateRendererTests.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs index 3297787..0e097fe 100644 --- a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs @@ -406,14 +406,22 @@ public void TimestampTokenRendersLocalTime() { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); var formatter = new OutputTemplateRenderer(ConsoleTheme.None, - "Default Format: {Timestamp} / Custom Format String: {Timestamp:yyyy-MM-dd HH:mm:ss}", + """ + Default Format: {Timestamp} + Round-trip Standard Format String: {Timestamp:o} + Custom Format String: {Timestamp:yyyy-MM-dd HH:mm:ss} + """, CultureInfo.InvariantCulture); var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in local time, unchanged from the input, the +02:00 offset should not affect the output - Assert.Equal("Default Format: 09/03/2024 14:15:16 +02:00 / Custom Format String: 2024-09-03 14:15:16", sw.ToString()); + Assert.Equal(""" + Default Format: 09/03/2024 14:15:16 +02:00 + Round-trip Standard Format String: 2024-09-03T14:15:16.0790000+02:00 + Custom Format String: 2024-09-03 14:15:16 + """, sw.ToString()); } [Fact] @@ -421,13 +429,21 @@ public void UtcTimestampTokenRendersUtcTime() { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); var formatter = new OutputTemplateRenderer(ConsoleTheme.None, - "Default Format: {UtcTimestamp} / Custom Format String: {UtcTimestamp:yyyy-MM-dd HH:mm:ss}", + """ + Default Format: {UtcTimestamp} + Round-trip Standard Format String: {UtcTimestamp:o} + Custom Format String: {UtcTimestamp:yyyy-MM-dd HH:mm:ss} + """, CultureInfo.InvariantCulture); var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in UTC, the +02:00 offset must be applied to adjust the hour - Assert.Equal("Default Format: 09/03/2024 12:15:16 / Custom Format String: 2024-09-03 12:15:16", sw.ToString()); + Assert.Equal(""" + Default Format: 09/03/2024 12:15:16 + Round-trip Standard Format String: 2024-09-03T12:15:16.0790000Z + Custom Format String: 2024-09-03 12:15:16 + """, sw.ToString()); } } \ No newline at end of file From 8b58251fca62380b9105d8c35e8418989bb2dfbf Mon Sep 17 00:00:00 2001 From: Manuel Rinnhofer Date: Mon, 17 Feb 2025 23:14:57 +0100 Subject: [PATCH 09/15] Unit tests for rendering UtcTimestamp/Timestamp switched from Fact to Theory to improve maintainability For better maintainability the multi-line strings with several tokens and formats of Fact unit tests are replaced by Theory with InlineData for better maintainability/readability. Relates to #164 --- .../Output/OutputTemplateRendererTests.cs | 42 +++++++------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs index 0e097fe..7e6b799 100644 --- a/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs +++ b/test/Serilog.Sinks.Console.Tests/Output/OutputTemplateRendererTests.cs @@ -401,49 +401,35 @@ public void TraceAndSpanAreIncludedWhenPresent() Assert.Equal($"{traceId}/{spanId}", sw.ToString()); } - [Fact] - public void TimestampTokenRendersLocalTime() + [Theory] + [InlineData("{Timestamp}", "09/03/2024 14:15:16 +02:00")] // Default Format + [InlineData("{Timestamp:o}", "2024-09-03T14:15:16.0790000+02:00")] // Round-trip Standard Format String + [InlineData("{Timestamp:yyyy-MM-dd HH:mm:ss}", "2024-09-03 14:15:16")] // Custom Format String + public void TimestampTokenRendersLocalTime(string actualToken, string expectedOutput) { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, - """ - Default Format: {Timestamp} - Round-trip Standard Format String: {Timestamp:o} - Custom Format String: {Timestamp:yyyy-MM-dd HH:mm:ss} - """, - CultureInfo.InvariantCulture); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, actualToken, CultureInfo.InvariantCulture); var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in local time, unchanged from the input, the +02:00 offset should not affect the output - Assert.Equal(""" - Default Format: 09/03/2024 14:15:16 +02:00 - Round-trip Standard Format String: 2024-09-03T14:15:16.0790000+02:00 - Custom Format String: 2024-09-03 14:15:16 - """, sw.ToString()); + Assert.Equal(expectedOutput, sw.ToString()); } - [Fact] - public void UtcTimestampTokenRendersUtcTime() + [Theory] + [InlineData("{UtcTimestamp}", "09/03/2024 12:15:16")] // Default Format + [InlineData("{UtcTimestamp:o}", "2024-09-03T12:15:16.0790000Z")] // Round-trip Standard Format String + [InlineData("{UtcTimestamp:yyyy-MM-dd HH:mm:ss}", "2024-09-03 12:15:16")] // Custom Format String + public void UtcTimestampTokenRendersUtcTime(string actualToken, string expectedOutput) { var logTimestampWithTimeZoneOffset = DateTimeOffset.Parse("2024-09-03T14:15:16.079+02:00", CultureInfo.InvariantCulture); - var formatter = new OutputTemplateRenderer(ConsoleTheme.None, - """ - Default Format: {UtcTimestamp} - Round-trip Standard Format String: {UtcTimestamp:o} - Custom Format String: {UtcTimestamp:yyyy-MM-dd HH:mm:ss} - """, - CultureInfo.InvariantCulture); + var formatter = new OutputTemplateRenderer(ConsoleTheme.None, actualToken, CultureInfo.InvariantCulture); var evt = new LogEvent(logTimestampWithTimeZoneOffset, LogEventLevel.Debug, null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); var sw = new StringWriter(); formatter.Format(evt, sw); // expect time in UTC, the +02:00 offset must be applied to adjust the hour - Assert.Equal(""" - Default Format: 09/03/2024 12:15:16 - Round-trip Standard Format String: 2024-09-03T12:15:16.0790000Z - Custom Format String: 2024-09-03 12:15:16 - """, sw.ToString()); + Assert.Equal(expectedOutput, sw.ToString()); } } \ No newline at end of file From 5839480c0a1b87188c670ffb99e24b64a0a02073 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Fri, 5 Sep 2025 08:58:55 +1000 Subject: [PATCH 10/15] Minor version bump, UtcTimestamp token support was added --- src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj index f57adf9..824dd05 100644 --- a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj +++ b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj @@ -1,7 +1,7 @@ A Serilog sink that writes log events to the console/terminal. - 6.0.1 + 6.1.0 Serilog Contributors net462;net471 $(TargetFrameworks);netstandard2.0;net6.0;net8.0 From 8556d610244dfbc02d443423d4518f15623290b7 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 2 Nov 2025 14:33:38 +1000 Subject: [PATCH 11/15] Switch build to Actions --- .github/.DS_Store | Bin 0 -> 8196 bytes .github/workflows/ci.yml | 41 +++++++++++++++++ .gitignore | 2 + Build.ps1 | 93 +++++++++++++++++++++++++------------- Directory.Build.props | 25 ++++++++++ Directory.Version.props | 5 ++ appveyor.yml | 22 --------- build.sh | 18 -------- serilog-sinks-console.sln | 15 +++++- 9 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 .github/.DS_Store create mode 100644 .github/workflows/ci.yml create mode 100644 Directory.Build.props create mode 100644 Directory.Version.props delete mode 100644 appveyor.yml delete mode 100755 build.sh diff --git a/.github/.DS_Store b/.github/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..39056af1449efe4ddb9dca58ec1f3c2361c3d376 GIT binary patch literal 8196 zcmeHMU2GIp6u#fIzziMe07Vw;goQ$oW`QnLTmH=UPx&vfE#0=jvb!_Tf!Ud5XSXes z#>T`K5R6Y6|9R4AP#~C+#ml)vgqz}91BxAlD;gY*EaCZiOXZRHgyxqw! z?3pvfxD47L13?DHXTYV6L>0Tu^6bdy`rXN;O*>86i|L$cIEA{pZy}VGPnkMRoF-O? z`{I4}K)jGD6rJW&zSkXf*tVH2^;79RhCYx~s#QKnP9}T13`?^In(d;c zIi7EvD?~|@l1gZ3C>o7~qigDiBjKTF{S&Jr;l^m)@USG#ty#5xck+mtwd|8T82BFq zHe*b1rzVcfJQR&*>}+n7^#t*oPJauJzbsyg|GQHB()0>>hT4_r?&+12%Itm$v^`fa zY|GiB=N*zsrP85H;(HxSLtN(wrTFP z9m8FwJ5kUF3$AXQD$(QE`9h1gSi+$7xs_6M^xZlwYV_-^w6s$-Dm=Ff>DgqQfBW>y(Rw}E{ zLPV0TRfgs-c(htoCo@eH)5g)FQ8=d5h@!Vgc#$ga)##bF+nT$Jrd$wd9ol{AB312m zH7$9aTFrM@UaQI-4h65Ie8ZKiWVz!AK}K=hM}7VAooAo3%j_HWJ^O{-Vt)Xb3JKFu zfhsJ(5=8Jg8qkQfXhu7BVK?H~i#`}Q3C;1Xu9|zQotKi68JIe!?yMiNA11m?F#*Lc)Auu@Dhf2rGpKp;1^TtQU3&?LtCG z35Nw+7~}y6C2H>D<5DXequ#`%^FKPmxrs?v{q&~ITekjtNOyfEr`g;`=7pEmuBva` z*mM_;9KR*VjwXVK{(Cs%q2EKt8022#e3TcKxH^`YokSabP;}X=Oykyz<;05Cgvc7WvC;RKZ#A)K{$6&-iiH4B84;BCA^sDBUd6Xrj{MSP4;@fj}TijV#qg#BM}dkmhp zmypaQexDf6S-Z8>KSagbwKs6G_e#@bmfC$<=KAjE`09`6Ez`CR(QYLU@<+X=E#sq* zTmQFB{`>zuKEWW!K#+m|Rt8Ys8gFf;m?ryHxV3he?gMnYmuok|rRPG8SB{hP%5jo+ n|6xe|FqyhOF<*{wNi%dk@E-ym> $GITHUB_ENV + - name: Build and Publish + env: + DOTNET_CLI_TELEMETRY_OPTOUT: true + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: pwsh + run: | + ./Build.ps1 diff --git a/.gitignore b/.gitignore index 94420dc..4f6c9b2 100644 --- a/.gitignore +++ b/.gitignore @@ -234,3 +234,5 @@ _Pvt_Extensions # FAKE - F# Make .fake/ + +.DS_Store/ diff --git a/Build.ps1 b/Build.ps1 index ba41ab1..e798284 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -1,48 +1,79 @@ -echo "build: Build started" +Write-Output "build: Tool versions follow" + +dotnet --version +dotnet --list-sdks + +Write-Output "build: Build started" Push-Location $PSScriptRoot +try { + if(Test-Path .\artifacts) { + Write-Output "build: Cleaning ./artifacts" + Remove-Item ./artifacts -Force -Recurse + } -if(Test-Path .\artifacts) { - echo "build: Cleaning .\artifacts" - Remove-Item .\artifacts -Force -Recurse -} + & dotnet restore --no-cache -& dotnet restore --no-cache + $dbp = [Xml] (Get-Content .\Directory.Version.props) + $versionPrefix = $dbp.Project.PropertyGroup.VersionPrefix -$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"] -$commitHash = $(git rev-parse --short HEAD) -$buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""] + Write-Output "build: Package version prefix is $versionPrefix" -echo "build: Package version suffix is $suffix" -echo "build: Build version suffix is $buildSuffix" + $branch = @{ $true = $env:CI_TARGET_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$NULL -ne $env:CI_TARGET_BRANCH]; + $revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:CI_BUILD_NUMBER, 10); $false = "local" }[$NULL -ne $env:CI_BUILD_NUMBER]; + $suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)) -replace '([^a-zA-Z0-9\-]*)', '')-$revision"}[$branch -eq "main" -and $revision -ne "local"] + $commitHash = $(git rev-parse --short HEAD) + $buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""] -foreach ($src in ls src/*) { - Push-Location $src + Write-Output "build: Package version suffix is $suffix" + Write-Output "build: Build version suffix is $buildSuffix" - echo "build: Packaging project in $src" + & dotnet build -c Release --version-suffix=$buildSuffix /p:ContinuousIntegrationBuild=true + if($LASTEXITCODE -ne 0) { throw "Build failed" } - & dotnet build -c Release --version-suffix=$buildSuffix -p:EnableSourceLink=true - if ($suffix) { - & dotnet pack -c Release -o ..\..\artifacts --version-suffix=$suffix --no-build - } else { - & dotnet pack -c Release -o ..\..\artifacts --no-build + foreach ($src in Get-ChildItem src/*) { + Push-Location $src + + Write-Output "build: Packaging project in $src" + + if ($suffix) { + & dotnet pack -c Release --no-build --no-restore -o ../../artifacts --version-suffix=$suffix + } else { + & dotnet pack -c Release --no-build --no-restore -o ../../artifacts + } + if($LASTEXITCODE -ne 0) { throw "Packaging failed" } + + Pop-Location } - if($LASTEXITCODE -ne 0) { throw "build failed" } - Pop-Location -} + foreach ($test in Get-ChildItem test/*.Tests) { + Push-Location $test + + Write-Output "build: Testing project in $test" + + & dotnet test -c Release --no-build --no-restore + if($LASTEXITCODE -ne 0) { throw "Testing failed" } + + Pop-Location + } + + if ($env:NUGET_API_KEY) { + # GitHub Actions will only supply this to branch builds and not PRs. We publish + # builds from any branch this action targets (i.e. main and dev). -foreach ($test in ls test/*.Tests) { - Push-Location $test + Write-Output "build: Publishing NuGet packages" - echo "build: Testing project in $test" + foreach ($nupkg in Get-ChildItem artifacts/*.nupkg) { + & dotnet nuget push -k $env:NUGET_API_KEY -s https://api.nuget.org/v3/index.json "$nupkg" + if($LASTEXITCODE -ne 0) { throw "Publishing failed" } + } - & dotnet test -c Release - if($LASTEXITCODE -ne 0) { throw "tests failed" } + if (!($suffix)) { + Write-Output "build: Creating release for version $versionPrefix" + iex "gh release create v$versionPrefix --title v$versionPrefix --generate-notes $(get-item ./artifacts/*.nupkg) $(get-item ./artifacts/*.snupkg)" + } + } +} finally { Pop-Location } - -Pop-Location \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..c114992 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,25 @@ + + + + + latest + True + + true + $(MSBuildThisFileDirectory)assets/Serilog.snk + false + enable + enable + true + true + true + true + snupkg + + + + + + + diff --git a/Directory.Version.props b/Directory.Version.props new file mode 100644 index 0000000..e37c3ef --- /dev/null +++ b/Directory.Version.props @@ -0,0 +1,5 @@ + + + 6.1.0 + + diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 0a0eb08..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: '{build}' -skip_tags: true -image: Visual Studio 2022 -test: off -build_script: -- pwsh: ./Build.ps1 -artifacts: -- path: artifacts/Serilog.*.nupkg -deploy: -- provider: NuGet - api_key: - secure: ZpUO4ECx4c/V0Ecj04cfV1UGd+ZABeEG9DDW2fjG8vITjNYhmbiiJH0qNOnRy2G3 - skip_symbols: true - on: - branch: /^(main|dev)$/ -- provider: GitHub - auth_token: - secure: p4LpVhBKxGS5WqucHxFQ5c7C8cP74kbNB0Z8k9Oxx/PMaDQ1+ibmoexNqVU5ZlmX - artifact: /Serilog.*\.nupkg/ - tag: v$(appveyor_build_version) - on: - branch: main diff --git a/build.sh b/build.sh deleted file mode 100755 index 64d87ea..0000000 --- a/build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -e -dotnet --info -dotnet restore - -for path in src/**/*.csproj; do - dotnet build -f netstandard2.0 -c Release ${path} -done - -for path in test/*.Tests/*.csproj; do - dotnet test -f netcoreapp2.2 -c Release ${path} -done - -for path in sample/ConsoleDemo/*.csproj; do - dotnet build -f netcoreapp2.2 -c Release ${path} - dotnet run -f netcoreapp2.2 --project ${path} -done diff --git a/serilog-sinks-console.sln b/serilog-sinks-console.sln index e223156..9e93a9c 100644 --- a/serilog-sinks-console.sln +++ b/serilog-sinks-console.sln @@ -5,11 +5,10 @@ VisualStudioVersion = 15.0.26430.12 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}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sln", "sln", "{E9D1B5E1-DEB9-4A04-8BAB-24EC7240ADAF}" ProjectSection(SolutionItems) = preProject .gitattributes = .gitattributes .gitignore = .gitignore - appveyor.yml = appveyor.yml Build.ps1 = Build.ps1 CHANGES.md = CHANGES.md LICENSE = LICENSE @@ -29,6 +28,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleDemo", "sample\Conso EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyncWritesDemo", "sample\SyncWritesDemo\SyncWritesDemo.csproj", "{633AE0AD-C9D4-440D-874A-C0F4632DB75F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{91B268E6-3BCF-49B4-A04D-8467AE23410A}" + ProjectSection(SolutionItems) = preProject + .github\ISSUE_TEMPLATE.md = .github\ISSUE_TEMPLATE.md + .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{F4C015DE-80BA-4D63-9D3D-D687999B4960}" + ProjectSection(SolutionItems) = preProject + .github\workflows\ci.yml = .github\workflows\ci.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,6 +70,7 @@ Global {1D56534C-4009-42C2-A573-789CAE6B8AA9} = {7D0692CD-F95D-4BF9-8C63-B4A1C078DF23} {DBF4907A-63A2-4895-8DEF-59F90C20380B} = {CF817664-4CEC-4B6A-9C57-A0D687757D82} {633AE0AD-C9D4-440D-874A-C0F4632DB75F} = {CF817664-4CEC-4B6A-9C57-A0D687757D82} + {F4C015DE-80BA-4D63-9D3D-D687999B4960} = {91B268E6-3BCF-49B4-A04D-8467AE23410A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {43C32ED4-D39A-4E27-AE99-7BB8C883833C} From 95e0cc6f60749bbd16d82b3b1880fc17c78ec15b Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 2 Nov 2025 14:42:55 +1000 Subject: [PATCH 12/15] Tidy up CSPROJ --- src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj | 10 ---------- .../Serilog.Sinks.Console.Tests.csproj | 6 +----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj index 824dd05..f3fd276 100644 --- a/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj +++ b/src/Serilog.Sinks.Console/Serilog.Sinks.Console.csproj @@ -1,24 +1,14 @@ A Serilog sink that writes log events to the console/terminal. - 6.1.0 Serilog Contributors net462;net471 $(TargetFrameworks);netstandard2.0;net6.0;net8.0 - enable - ../../assets/Serilog.snk - true - true serilog;console;terminal icon.png https://github.com/serilog/serilog-sinks-console Apache-2.0 - https://github.com/serilog/serilog-sinks-console - git - true - True Serilog - latest README.md 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 472965f..2a72fac 100644 --- a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj +++ b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj @@ -1,12 +1,8 @@  - net7.0 + net6.0;net8.0;net9.0 true - ../../assets/Serilog.snk - true - true - enable From 78309d3b4c1381674d01072e2289468f24d33e96 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 2 Nov 2025 15:01:11 +1000 Subject: [PATCH 13/15] Update README.md --- README.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 397b2e5..a708a9c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Serilog.Sinks.Console [![Build status](https://ci.appveyor.com/api/projects/status/w1w3m1wyk3in1c96/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog-sinks-console/branch/master) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Sinks.Console.svg?style=flat)](https://www.nuget.org/packages/Serilog.Sinks.Console/) [![Documentation](https://img.shields.io/badge/docs-wiki-yellow.svg)](https://github.com/serilog/serilog/wiki) [![Help](https://img.shields.io/badge/stackoverflow-serilog-orange.svg)](http://stackoverflow.com/questions/tagged/serilog) +# Serilog.Sinks.Console [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Sinks.Console.svg?style=flat)](https://www.nuget.org/packages/Serilog.Sinks.Console/) [![Documentation](https://img.shields.io/badge/docs-wiki-yellow.svg)](https://github.com/serilog/serilog/wiki) [![Help](https://img.shields.io/badge/stackoverflow-serilog-orange.svg)](http://stackoverflow.com/questions/tagged/serilog) -A Serilog sink that writes log events to the Windows Console or an ANSI terminal via standard output. Coloring and custom themes are supported, including ANSI 256-color themes on macOS, Linux and Windows 10. The default output is plain text; JSON formatting can be plugged in using a package such as [_Serilog.Formatting.Compact_](https://github.com/serilog/serilog-formatting-compact). +A Serilog sink that writes log events to the Windows Console or an ANSI terminal via standard output. Coloring and custom themes are supported, including ANSI 256-color themes on macOS, Linux and Windows 10+. The default output is plain text; JSON formatting can be plugged in using [_Serilog.Formatting.Compact_](https://github.com/serilog/serilog-formatting-compact) or the [fully-customizable](https://nblumhardt.com/2021/06/customize-serilog-json-output/) [_Serilog.Expressions_](https://github.com/serilog/serilog-expressions). ### Getting started @@ -16,7 +16,7 @@ Then enable the sink using `WriteTo.Console()`: Log.Logger = new LoggerConfiguration() .WriteTo.Console() .CreateLogger(); - + Log.Information("Hello, world!"); ``` @@ -171,17 +171,8 @@ Log.Logger = new LoggerConfiguration() ### Contributing -Would you like to help make the Serilog console sink even better? We keep a list of issues that are approachable for newcomers under the [up-for-grabs](https://github.com/serilog/serilog-sinks-console/issues?labels=up-for-grabs&state=open) label. Before starting work on a pull request, we suggest commenting on, or raising, an issue on the issue tracker so that we can help and coordinate efforts. For more details check out our [contributing guide](CONTRIBUTING.md). +Would you like to help make the Serilog console sink even better? We keep a list of issues that are approachable for newcomers under the [up-for-grabs](https://github.com/serilog/serilog-sinks-console/issues?labels=up-for-grabs&state=open) label. Before starting work on a pull request, we suggest commenting on, or raising, an issue on the issue tracker so that we can help and coordinate efforts. For more details check out our [contributing guide](CONTRIBUTING.md). When contributing please keep in mind our [Code of Conduct](CODE_OF_CONDUCT.md). - -### Detailed build status - -Branch | AppVeyor | Travis -------------- | ------------- |------------- -dev | [![Build status](https://ci.appveyor.com/api/projects/status/w1w3m1wyk3in1c96/branch/dev?svg=true)](https://ci.appveyor.com/project/serilog/serilog-sinks-console/branch/dev) | [![Build Status](https://travis-ci.org/serilog/serilog-sinks-console.svg?branch=dev)](https://travis-ci.org/serilog/serilog-sinks-console) -main | [![Build status](https://ci.appveyor.com/api/projects/status/w1w3m1wyk3in1c96/branch/main?svg=true)](https://ci.appveyor.com/project/serilog/serilog-sinks-console/branch/main) | [![Build Status](https://travis-ci.org/serilog/serilog-sinks-console.svg?branch=main)](https://travis-ci.org/serilog/serilog-sinks-console) - - _Copyright © Serilog Contributors - Provided under the [Apache License, Version 2.0](http://apache.org/licenses/LICENSE-2.0.html)._ From 52d1579788d9235f35c087103be7d4678d929e0a Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 2 Nov 2025 15:13:54 +1000 Subject: [PATCH 14/15] Don't enable XDOC for tests --- Directory.Build.props | 2 +- sample/SyncWritesDemo/Program.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c114992..95d7522 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,7 +11,7 @@ false enable enable - true + true true true true diff --git a/sample/SyncWritesDemo/Program.cs b/sample/SyncWritesDemo/Program.cs index f1015a1..139f1f1 100644 --- a/sample/SyncWritesDemo/Program.cs +++ b/sample/SyncWritesDemo/Program.cs @@ -24,7 +24,7 @@ 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) +static void SystemConsoleSyncTest(object? syncRootForLogger1, object? syncRootForLogger2) { var logger1 = new LoggerConfiguration() .MinimumLevel.Verbose() From 1c91172ede716dbd9075f99036238f14788e0e48 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 2 Nov 2025 15:20:18 +1000 Subject: [PATCH 15/15] Remove net6.0 target from tests --- .../Serilog.Sinks.Console.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2a72fac..b165f21 100644 --- a/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj +++ b/test/Serilog.Sinks.Console.Tests/Serilog.Sinks.Console.Tests.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net9.0 + net8.0;net9.0 true