diff --git a/CHANGES.md b/CHANGES.md index 72b8da47..0bd08f88 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,6 @@ +# 9.0.2 +* Fixed issue #643: TraceId and SpanId are saved as empty string instead of NULL (thanks to @nanny07) + # 9.0.1 * Fixed issue #642: NuGet package downgrade System.Configuration.ConfigurationManager error * Updated sample apps to .NET 9 diff --git a/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj b/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj index babe262a..8240a56b 100644 --- a/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj +++ b/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj @@ -2,7 +2,7 @@ A Serilog sink that writes events to Microsoft SQL Server and Azure SQL - 9.0.1 + 9.0.2 true 9.0.0 Michiel van Oudheusden;Christian Kadluba;Serilog Contributors diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Output/StandardColumnDataGenerator.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Output/StandardColumnDataGenerator.cs index 2766504b..435dc741 100644 --- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Output/StandardColumnDataGenerator.cs +++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Output/StandardColumnDataGenerator.cs @@ -51,13 +51,16 @@ public KeyValuePair GetStandardColumnNameAndValue(StandardColumn case StandardColumn.Level: return new KeyValuePair(_columnOptions.Level.ColumnName, _columnOptions.Level.StoreAsEnum ? (object)logEvent.Level : logEvent.Level.ToString()); case StandardColumn.TraceId: - return new KeyValuePair(_columnOptions.TraceId.ColumnName, logEvent.TraceId.ToString()); + var useDefaultTraceIdValue = logEvent.TraceId is null && !_columnOptions.TraceId.AllowNull; + return new KeyValuePair(_columnOptions.TraceId.ColumnName, useDefaultTraceIdValue ? _columnOptions.TraceId.AsDataColumn().DefaultValue.ToString() : logEvent.TraceId?.ToString()); case StandardColumn.SpanId: - return new KeyValuePair(_columnOptions.SpanId.ColumnName, logEvent.SpanId.ToString()); + var useDefaultSpanIdValue = logEvent.SpanId is null && !_columnOptions.SpanId.AllowNull; + return new KeyValuePair(_columnOptions.SpanId.ColumnName, useDefaultSpanIdValue ? _columnOptions.SpanId.AsDataColumn().DefaultValue.ToString() : logEvent.SpanId?.ToString()); case StandardColumn.TimeStamp: return GetTimeStampStandardColumnNameAndValue(logEvent); case StandardColumn.Exception: - return new KeyValuePair(_columnOptions.Exception.ColumnName, logEvent.Exception?.ToString().TruncateOutput(_columnOptions.Exception.DataLength)); + var useDefaultExceptionValue = logEvent.Exception is null && !_columnOptions.Exception.AllowNull; + return new KeyValuePair(_columnOptions.Exception.ColumnName, useDefaultExceptionValue ? _columnOptions.Exception.AsDataColumn().DefaultValue.ToString() : logEvent.Exception?.ToString().TruncateOutput(_columnOptions.Exception.DataLength)); case StandardColumn.Properties: return new KeyValuePair(_columnOptions.Properties.ColumnName, ConvertPropertiesToXmlStructure(logEvent.Properties)); case StandardColumn.LogEvent: diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/Output/StandardColumnDataGeneratorTests.cs b/test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/Output/StandardColumnDataGeneratorTests.cs index a14b7302..9c0b3265 100644 --- a/test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/Output/StandardColumnDataGeneratorTests.cs +++ b/test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/Output/StandardColumnDataGeneratorTests.cs @@ -282,6 +282,46 @@ public void GetStandardColumnNameAndValueForTraceIdReturnsLogLevelKeyValue() Assert.Equal("34898a9020e0390190b0982370034f00", result.Value); } + [Fact] + public void GetStandardColumnNameAndNullValueForTraceIdReturnsLogLevelKeyValue() + { + // Arrange + var traceId = default(ActivityTraceId); + var logEvent = new LogEvent( + new DateTimeOffset(2020, 1, 1, 0, 0, 0, 0, TimeSpan.Zero), + LogEventLevel.Debug, null, new MessageTemplate(new List() { new TextToken("Test message") }), + new List(), traceId, ActivitySpanId.CreateRandom()); + SetupSut(new MSSqlServer.ColumnOptions(), CultureInfo.InvariantCulture); + + // Act + var result = _sut.GetStandardColumnNameAndValue(StandardColumn.TraceId, logEvent); + + // Assert + Assert.Equal("TraceId", result.Key); + Assert.Null(result.Value); + } + + [Fact] + public void GetStandardColumnNameAndNullValueForTraceIdWithoutAllowNullReturnsLogLevelKeyValueEmpty() + { + // Arrange + var traceId = default(ActivityTraceId); + var logEvent = new LogEvent( + new DateTimeOffset(2020, 1, 1, 0, 0, 0, 0, TimeSpan.Zero), + LogEventLevel.Debug, null, new MessageTemplate(new List() { new TextToken("Test message") }), + new List(), traceId, ActivitySpanId.CreateRandom()); + var columnOptions = new MSSqlServer.ColumnOptions(); + columnOptions.TraceId.AllowNull = false; + SetupSut(columnOptions, CultureInfo.InvariantCulture); + + // Act + var result = _sut.GetStandardColumnNameAndValue(StandardColumn.TraceId, logEvent); + + // Assert + Assert.Equal("TraceId", result.Key); + Assert.Equal(string.Empty, result.Value); + } + [Fact] public void GetStandardColumnNameAndValueForSpanIdReturnsLogLevelKeyValue() { @@ -301,6 +341,46 @@ public void GetStandardColumnNameAndValueForSpanIdReturnsLogLevelKeyValue() Assert.Equal("0390190b09823700", result.Value); } + [Fact] + public void GetStandardColumnNameAndNullValueForSpanIdReturnsLogLevelKeyValue() + { + // Arrange + var spanId = default(ActivitySpanId); + var logEvent = new LogEvent( + new DateTimeOffset(2020, 1, 1, 0, 0, 0, 0, TimeSpan.Zero), + LogEventLevel.Debug, null, new MessageTemplate(new List() { new TextToken("Test message") }), + new List(), ActivityTraceId.CreateRandom(), spanId); + SetupSut(new MSSqlServer.ColumnOptions(), CultureInfo.InvariantCulture); + + // Act + var result = _sut.GetStandardColumnNameAndValue(StandardColumn.SpanId, logEvent); + + // Assert + Assert.Equal("SpanId", result.Key); + Assert.Null(result.Value); + } + + [Fact] + public void GetStandardColumnNameAndNullValueForSpanIdWithoutAllowNullReturnsLogLevelKeyValueEmpty() + { + // Arrange + var spanId = default(ActivitySpanId); + var logEvent = new LogEvent( + new DateTimeOffset(2020, 1, 1, 0, 0, 0, 0, TimeSpan.Zero), + LogEventLevel.Debug, null, new MessageTemplate(new List() { new TextToken("Test message") }), + new List(), ActivityTraceId.CreateRandom(), spanId); + var columnOptions = new MSSqlServer.ColumnOptions(); + columnOptions.SpanId.AllowNull = false; + SetupSut(columnOptions, CultureInfo.InvariantCulture); + + // Act + var result = _sut.GetStandardColumnNameAndValue(StandardColumn.SpanId, logEvent); + + // Assert + Assert.Equal("SpanId", result.Key); + Assert.Equal(string.Empty, result.Value); + } + [Fact] public void GetStandardColumnNameAndValueForLogLevelReturnsLogLevelKeyValueAsEnum() { @@ -449,6 +529,27 @@ public void GetStandardColumnNameAndValueForExceptionWhenCalledWithoutExceptionR Assert.Null(result.Value); } + [Fact] + public void GetStandardColumnNameAndValueForExceptionWhenCalledWithoutExceptionAndNotAllowedNullReturnsEmptyValue() + { + // Arrange + var logEvent = new LogEvent( + new DateTimeOffset(2020, 1, 1, 0, 0, 0, 0, TimeSpan.Zero), + LogEventLevel.Debug, null, new MessageTemplate(new List() { new TextToken("Test message") }), + new List()); + var columnOptions = new Serilog.Sinks.MSSqlServer.ColumnOptions(); + columnOptions.Level.StoreAsEnum = true; + columnOptions.Exception.AllowNull = false; + SetupSut(columnOptions, CultureInfo.InvariantCulture); + + // Act + var result = _sut.GetStandardColumnNameAndValue(StandardColumn.Exception, logEvent); + + // Assert + Assert.Equal("Exception", result.Key); + Assert.Equal(string.Empty, result.Value); + } + [Fact] public void GetStandardColumnNameAndValueForPropertiesUsesRootElementName() {