diff --git a/src/SeqCli/Output/NativeFormatter.cs b/src/SeqCli/Output/NativeFormatter.cs index 79017ce5..9fe30f8d 100644 --- a/src/SeqCli/Output/NativeFormatter.cs +++ b/src/SeqCli/Output/NativeFormatter.cs @@ -74,7 +74,8 @@ public static void WriteEvent(TextWriter output, EventEntity evt) ("@Elapsed", evt.Elapsed ?? UndefinedValue), ("@TraceId", evt.TraceId ?? UndefinedValue), ("@SpanId", evt.SpanId ?? UndefinedValue), - ("@SpanKind", evt.SpanKind ?? UndefinedValue), + // This temporarily works around an events API bug; non-span events should not carry span kinds. + ("@SpanKind", evt.Start != null ? evt.SpanKind ?? UndefinedValue : UndefinedValue), ("@Start", evt.Start != null ? DateTimeOffset.Parse(evt.Start).UtcDateTime : UndefinedValue), ("@ParentId", evt.ParentId ?? UndefinedValue), ("@Properties", evt.Properties?.Count > 0 ? new Action(w => WritePropertiesObject(w, evt.Properties)) : UndefinedValue), diff --git a/src/SeqCli/Output/OutputFormat.cs b/src/SeqCli/Output/OutputFormat.cs index affa48ef..b1c88c6e 100644 --- a/src/SeqCli/Output/OutputFormat.cs +++ b/src/SeqCli/Output/OutputFormat.cs @@ -256,7 +256,8 @@ public static LogEvent ToSerilogEvent(EventEntity evt) if (!string.IsNullOrWhiteSpace(evt.Start)) serilogEvent.AddOrUpdateProperty(new("@st", new ScalarValue(evt.Start))); - if (!string.IsNullOrWhiteSpace(evt.SpanKind)) + // This temporarily works around an events API bug; non-span events should not carry span kinds. + if (!string.IsNullOrWhiteSpace(evt.Start) && !string.IsNullOrWhiteSpace(evt.SpanKind)) serilogEvent.AddOrUpdateProperty(new("@sk", new ScalarValue(evt.SpanKind))); return serilogEvent; diff --git a/test/SeqCli.Tests/Output/NativeFormatterTests.cs b/test/SeqCli.Tests/Output/NativeFormatterTests.cs index 82251913..ae2c1c90 100644 --- a/test/SeqCli.Tests/Output/NativeFormatterTests.cs +++ b/test/SeqCli.Tests/Output/NativeFormatterTests.cs @@ -51,7 +51,14 @@ public static IEnumerable EventPropertyCases() => [Some.MakeEvent(e => e.Elapsed = TimeSpan.FromSeconds(13)), "@Elapsed: 13s"], [Some.MakeEvent(e => e.TraceId = "abc123"), "@TraceId: 'abc123'"], [Some.MakeEvent(e => e.SpanId = "def456"), "@SpanId: 'def456'"], - [Some.MakeEvent(e => e.SpanKind = "server"), "@SpanKind: 'server'"], + [ + Some.MakeEvent(e => + { + e.Start = "2024-01-01T00:00:00.0000000Z"; + e.SpanKind = "server"; + }), + "@SpanKind: 'server'" + ], [Some.MakeEvent(e => e.Start = "2024-01-01T00:00:00.0000000Z"), "@Start: DateTime('2024-01-01T00:00:00.0000000Z')"], [Some.MakeEvent(e => e.ParentId = "p1"), "@ParentId: 'p1'"], [Some.MakeEvent(e => e.Properties = Some.MakeProperties(("UserId", 42))), "@Properties: {UserId: 42}"], @@ -118,6 +125,13 @@ public void OptionalPropertiesAreOmittedWhenAbsent(string token) Assert.DoesNotContain(token, Render(Some.MakeEvent())); } + [Fact] + public void SpanKindIsOmittedFromEventsThatAreNotSpans() + { + // The events API reports a span kind for every event, defaulting to `Internal`. + Assert.DoesNotContain("@SpanKind", Render(Some.MakeEvent(e => e.SpanKind = "Internal"))); + } + [Fact] public void EmptyPropertyCollectionIsOmitted() { diff --git a/test/SeqCli.Tests/Output/OutputFormatTests.cs b/test/SeqCli.Tests/Output/OutputFormatTests.cs new file mode 100644 index 00000000..4d75b771 --- /dev/null +++ b/test/SeqCli.Tests/Output/OutputFormatTests.cs @@ -0,0 +1,36 @@ +#nullable enable +using SeqCli.Tests.Support; +using Serilog.Events; +using Xunit; +using OutputFormat = SeqCli.Output.OutputFormat; + +namespace SeqCli.Tests.Output; + +public class OutputFormatTests +{ + [Fact] + public void SpanKindIsMappedFromSpans() + { + var evt = OutputFormat.ToSerilogEvent(Some.MakeEvent(e => + { + e.Properties = []; + e.Start = "2024-01-01T00:00:00.0000000Z"; + e.SpanKind = "Server"; + })); + + Assert.Equal("Server", Assert.IsType(evt.Properties["@sk"]).Value); + } + + [Fact] + public void SpanKindIsOmittedFromEventsThatAreNotSpans() + { + // The events API reports a span kind for every event, defaulting to `Internal`. + var evt = OutputFormat.ToSerilogEvent(Some.MakeEvent(e => + { + e.Properties = []; + e.SpanKind = "Internal"; + })); + + Assert.DoesNotContain("@sk", evt.Properties.Keys); + } +}