diff --git a/Benchmark/Benchmark.csproj b/Benchmark/Benchmark.csproj index d1db396..41dd179 100644 --- a/Benchmark/Benchmark.csproj +++ b/Benchmark/Benchmark.csproj @@ -2,7 +2,7 @@ Exe - net48;net6.0 + net48;net8.0 Latest Debug;Release;Test;Test diff --git a/NLog.Targets.OpenTelemetryProtocol.Test/NLog.Targets.OpenTelemetryProtocol.Test.csproj b/NLog.Targets.OpenTelemetryProtocol.Test/NLog.Targets.OpenTelemetryProtocol.Test.csproj index 05b6672..0fc6206 100644 --- a/NLog.Targets.OpenTelemetryProtocol.Test/NLog.Targets.OpenTelemetryProtocol.Test.csproj +++ b/NLog.Targets.OpenTelemetryProtocol.Test/NLog.Targets.OpenTelemetryProtocol.Test.csproj @@ -1,20 +1,20 @@  - - Exe - net6.0 - Latest - Debug;Release;Test;Test - + + Exe + net8.0 + Latest + Debug;Release;Test + - - - + + + - - - Always - - + + + Always + + diff --git a/NLog.Targets.OpenTelemetryProtocol.Test/Program.cs b/NLog.Targets.OpenTelemetryProtocol.Test/Program.cs index 2ca6825..64b72af 100644 --- a/NLog.Targets.OpenTelemetryProtocol.Test/Program.cs +++ b/NLog.Targets.OpenTelemetryProtocol.Test/Program.cs @@ -11,6 +11,8 @@ public static void Main() var message = "testing"; + using var currentActivity = new System.Diagnostics.Activity("Hello World").Start(); + logger.Fatal("message: {messageField}", message); Thread.Sleep(10000); diff --git a/NLog.Targets.OpenTelemetryProtocol/ActivityExtensions.cs b/NLog.Targets.OpenTelemetryProtocol/ActivityExtensions.cs new file mode 100644 index 0000000..8b3656d --- /dev/null +++ b/NLog.Targets.OpenTelemetryProtocol/ActivityExtensions.cs @@ -0,0 +1,52 @@ +using System.Diagnostics; + +namespace NLog.Targets.OpenTelemetryProtocol +{ + /// + /// Formats elements of for inclusion in log events. Non-W3C-format activities are + /// ignored (Seq does not support the older Microsoft-proprietary hierarchical activity id format). + /// + internal static class ActivityExtensions + { + private static readonly System.Diagnostics.ActivitySpanId EmptySpanId = default(System.Diagnostics.ActivitySpanId); + private static readonly System.Diagnostics.ActivityTraceId EmptyTraceId = default(System.Diagnostics.ActivityTraceId); + + public static string GetSpanId(this Activity activity) + { + return activity.IdFormat == ActivityIdFormat.W3C ? + SpanIdToHexString(activity.SpanId) : + string.Empty; + } + + public static string GetTraceId(this Activity activity) + { + return activity.IdFormat == ActivityIdFormat.W3C ? + TraceIdToHexString(activity.TraceId) : + string.Empty; + } + + private static string SpanIdToHexString(ActivitySpanId spanId) + { + if (EmptySpanId.Equals(spanId)) + return string.Empty; + + var spanHexString = spanId.ToHexString(); + if (ReferenceEquals(spanHexString, EmptySpanId.ToHexString())) + return string.Empty; + + return spanHexString; + } + + private static string TraceIdToHexString(ActivityTraceId traceId) + { + if (EmptyTraceId.Equals(traceId)) + return string.Empty; + + var traceHexString = traceId.ToHexString(); + if (ReferenceEquals(traceHexString, EmptyTraceId.ToHexString())) + return string.Empty; + + return traceHexString; + } + } +} diff --git a/NLog.Targets.OpenTelemetryProtocol/NLog.Targets.OpenTelemetryProtocol.csproj b/NLog.Targets.OpenTelemetryProtocol/NLog.Targets.OpenTelemetryProtocol.csproj index a32699b..1e43fcf 100644 --- a/NLog.Targets.OpenTelemetryProtocol/NLog.Targets.OpenTelemetryProtocol.csproj +++ b/NLog.Targets.OpenTelemetryProtocol/NLog.Targets.OpenTelemetryProtocol.csproj @@ -26,7 +26,7 @@ - + diff --git a/NLog.Targets.OpenTelemetryProtocol/OpenTelemetryEventListener.cs b/NLog.Targets.OpenTelemetryProtocol/OpenTelemetryEventListener.cs index d83dfa9..c745cca 100644 --- a/NLog.Targets.OpenTelemetryProtocol/OpenTelemetryEventListener.cs +++ b/NLog.Targets.OpenTelemetryProtocol/OpenTelemetryEventListener.cs @@ -30,7 +30,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) } } - private void WriteEvent(EventLevel eventLevel, string? eventMessage, IReadOnlyList payload) + private void WriteEvent(EventLevel eventLevel, string eventMessage, IReadOnlyList payload) { switch (eventLevel) { diff --git a/NLog.Targets.OpenTelemetryProtocol/OtlpTarget.cs b/NLog.Targets.OpenTelemetryProtocol/OtlpTarget.cs index d90d99b..1178bd3 100644 --- a/NLog.Targets.OpenTelemetryProtocol/OtlpTarget.cs +++ b/NLog.Targets.OpenTelemetryProtocol/OtlpTarget.cs @@ -49,6 +49,10 @@ public class OtlpTarget : TargetWithContext public Layout ServiceName { get; set; } + public Layout TraceId { get; set; } = Layout.FromMethod(evt => System.Diagnostics.Activity.Current?.GetTraceId()); + + public Layout SpanId { get; set; } = Layout.FromMethod(evt => System.Diagnostics.Activity.Current?.GetSpanId()); + public Layout ScheduledDelayMilliseconds { get; set; } = 5000; public Layout MaxQueueSize { get; set; } = 2048; @@ -246,6 +250,13 @@ protected override void Write(LogEventInfo logEvent) Timestamp = logEvent.TimeStamp, }; + var spanId = RenderLogEvent(SpanId, logEvent); + if (!string.IsNullOrEmpty(spanId)) + data.SpanId = System.Diagnostics.ActivitySpanId.CreateFromString(spanId.AsSpan()); + var traceId = RenderLogEvent(TraceId, logEvent); + if (!string.IsNullOrEmpty(traceId)) + data.TraceId = System.Diagnostics.ActivityTraceId.CreateFromString(traceId.AsSpan()); + if (IncludeFormattedMessage && (logEvent.Parameters?.Length > 0 || logEvent.HasProperties)) { var formattedMessage = RenderLogEvent(Layout, logEvent); @@ -353,7 +364,7 @@ private static LogRecordSeverity ResolveSeverity(LogLevel logLevel) private OpenTelemetry.Logs.Logger GetLogger(string name) { - if (!_loggers.TryGetValue(name, out OpenTelemetry.Logs.Logger? logger)) + if (!_loggers.TryGetValue(name, out OpenTelemetry.Logs.Logger logger)) { lock (_sync) { diff --git a/README.md b/README.md index 365cc44..3d906a0 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ This target can export logs in the format defined in the OpenTelemetry specifica For an explanation of the log data model, see https://opentelemetry.io/docs/specs/otel/logs/data-model/.
For an example, see https://opentelemetry.io/docs/specs/otel/protocol/file-exporter/#examples. -**Note that the OpenTelemetry logging API is still unfinished, which means that it is internal in stable releases and public in prelease versions of the OpenTelemetry package. -This package has a reference to OpenTelemetry version 1.9.0-alpha.1. If your project has a reference to a stable version higher than that, +**Note that the OpenTelemetry logging API is still unfinished, which means that it is internal in stable releases and public in pre-release versions of the OpenTelemetry package. +This package has a reference to pre-release version of the OpenTelemetry-nuget-package. If your project has a reference to a stable version higher than that, you will get a runtime error.** ## Configuration @@ -29,7 +29,7 @@ Example XML config: scheduledDelayMilliseconds="1000" useDefaultResources="false" includeFormattedMessage="true" - onlyIncldueParameters="correlationId,messageId"> + onlyIncludeProperties="correlationId,messageId"> @@ -55,6 +55,8 @@ Example XML config: - **Attribute** : Attributes to be included with each LogEvent (optional) - _Name_ : Name of Attribute. - _Layout_ : Value of Attribute (If value is the same for all LogEvents, then add as resource instead) +- **SpanId** : Capture the SpanId value from System.Diagnostics.Activity.Current. Assign to empty value to skip SpanId. +- **TraceId** : Capture the TraceId value from System.Diagnostics.Activity.Current. Assign to empty value to skip TraceId. - **MaxQueueSize** : The target uses a batch exporter, this defines the max queue size. By default 2048, optional. - **MaxExportBatchSize** : The target uses a batch exporter, this defines the max batch size. By default 512, optional. - **ScheduledDelayMilliseconds** : The target uses a batch exporter, this defines how often it is flushed in milliseconds. By default 5000, optional. diff --git a/TestWebApp/TestWebApp.csproj b/TestWebApp/TestWebApp.csproj index 1e80a78..ad56174 100644 --- a/TestWebApp/TestWebApp.csproj +++ b/TestWebApp/TestWebApp.csproj @@ -7,7 +7,7 @@ - + diff --git a/UnitTests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj b/UnitTests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj index 9d212cf..92bd1d1 100644 --- a/UnitTests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj +++ b/UnitTests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj @@ -1,40 +1,40 @@  - - net6.0 - enable - enable - - false - - True - - debug.snk - - Debug;Release;Test;Test - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - Always - - + + net8.0 + enable + enable + + false + + True + + debug.snk + + Debug;Release;Test + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + Always + +