diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..f92aa1f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/HoneycombSerilogSink.sln b/HoneycombSerilogSink.sln index 12b6491..9194bf6 100644 --- a/HoneycombSerilogSink.sln +++ b/HoneycombSerilogSink.sln @@ -24,6 +24,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{87AFA633-E EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Honeycomb.Serilog.Sink.Tests", "test\Honeycomb.Serilog.Sink.Tests\Honeycomb.Serilog.Sink.Tests.csproj", "{3153A916-94B4-418D-84BD-EB1649449CFF}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ci", "ci", "{F33664C2-6205-4DB6-B00F-0C18887E8272}" +ProjectSection(SolutionItems) = preProject + ci\templates\build-and-package.yml = ci\templates\build-and-package.yml +EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/src/Honeycomb.Serilog.Sink/Formatters/RawJsonFormatter.cs b/src/Honeycomb.Serilog.Sink/Formatters/RawJsonFormatter.cs index 19f6c8d..f7a354f 100644 --- a/src/Honeycomb.Serilog.Sink/Formatters/RawJsonFormatter.cs +++ b/src/Honeycomb.Serilog.Sink/Formatters/RawJsonFormatter.cs @@ -33,6 +33,7 @@ public static void FormatContent(LogEvent logEvent, TextWriter output) output.Write($"{{\"time\":\"{logEvent.Timestamp:O}\","); output.Write("\"data\":{"); output.Write($"\"level\":\"{logEvent.Level}\""); + output.Write(",\"meta.annotation_type\":\"span_event\""); output.Write(",\"messageTemplate\":"); JsonValueFormatter.WriteQuotedJsonString(logEvent.MessageTemplate.Text, output); if (logEvent.Exception != null) @@ -63,12 +64,30 @@ private static void WriteProperties(IReadOnlyDictionary - /// The name of the team to submit the events to + /// The name of the dataset where to send the events to /// The API key given in the Honeycomb ui /// The maximum number of events to include in a single batch. /// The time to wait between checking for event batches. + /// See the official Honeycomb documentation for more details. public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration loggerConfiguration, - string teamId, + string dataset, string apiKey, int batchSizeLimit, TimeSpan period) @@ -25,7 +26,7 @@ public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration log Period = period }; - return loggerConfiguration.HoneycombSink(teamId, apiKey, batchingOptions); + return loggerConfiguration.HoneycombSink(dataset, apiKey, batchingOptions); } public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration loggerConfiguration, diff --git a/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs b/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs index e83d7d5..8dfee28 100644 --- a/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs +++ b/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs @@ -224,6 +224,80 @@ public async Task Emit_GivenAMessageWithEmptyPropertyValue_SkipsSendingProperty( } } + [Fact] + public async Task Emit_GivenAMessageWithTraceId_WritesItAsOTELStandard() + { + const string dataset = nameof(dataset); + const string apiKey = nameof(apiKey); + + HttpClientStub clientStub = A.HttpClient(); + + var sut = CreateSut(dataset, apiKey, clientStub); + + var level = LogEventLevel.Information; + + var property = 1; + const string spanId = nameof(spanId); + + var messageTemplateString = $"Testing message property {{{nameof(property)}}} {{TraceId}}"; + + var eventToSend = Some.LogEvent(level, messageTemplateString, property, spanId); + + + await sut.EmitTestable(eventToSend); + + var requestContent = clientStub.RequestContent; + using (var document = JsonDocument.Parse(requestContent)) + using (new AssertionScope()) + { + document.RootElement.ValueKind.Should().Be(JsonValueKind.Array); + document.RootElement.GetArrayLength().Should().Be(1); + JsonElement sentEvent = document.RootElement.EnumerateArray().Single(); + + sentEvent.GetProperty("time").GetDateTimeOffset().Should().Be(eventToSend.Timestamp); + sentEvent.GetProperty("data").ValueKind.Should().Be(JsonValueKind.Object); + sentEvent.GetProperty("data").GetProperty("trace.trace_id").ValueKind.Should().Be(JsonValueKind.String); + sentEvent.GetProperty("data").GetProperty("trace.trace_id").GetString().Should().Be(spanId); + } + } + + [Fact] + public async Task Emit_GivenAMessageWithParentId_WritesItAsOTELStandard() + { + const string dataset = nameof(dataset); + const string apiKey = nameof(apiKey); + + HttpClientStub clientStub = A.HttpClient(); + + var sut = CreateSut(dataset, apiKey, clientStub); + + var level = LogEventLevel.Information; + + var property = 1; + const string parentId = nameof(parentId); + + var messageTemplateString = $"Testing message property {{{nameof(property)}}} {{ParentId}}"; + + var eventToSend = Some.LogEvent(level, messageTemplateString, property, parentId); + + + await sut.EmitTestable(eventToSend); + + var requestContent = clientStub.RequestContent; + using (var document = JsonDocument.Parse(requestContent)) + using (new AssertionScope()) + { + document.RootElement.ValueKind.Should().Be(JsonValueKind.Array); + document.RootElement.GetArrayLength().Should().Be(1); + JsonElement sentEvent = document.RootElement.EnumerateArray().Single(); + + sentEvent.GetProperty("time").GetDateTimeOffset().Should().Be(eventToSend.Timestamp); + sentEvent.GetProperty("data").ValueKind.Should().Be(JsonValueKind.Object); + sentEvent.GetProperty("data").GetProperty("trace.parent_id").ValueKind.Should().Be(JsonValueKind.String); + sentEvent.GetProperty("data").GetProperty("trace.parent_id").GetString().Should().Be(parentId); + } + } + private HoneycombSerilogSinkStub CreateSut(string dataset, string apiKey, HttpClient client = null) { return new HoneycombSerilogSinkStub(client, dataset, apiKey);