Skip to content

Commit cc11781

Browse files
committed
feat: Add support for optionally including operation ID, parent span ID, operation name, and version properties in telemetry converters
1 parent 2dd05c3 commit cc11781

17 files changed

Lines changed: 327 additions & 42 deletions

src/Serilog.Sinks.ApplicationInsights/Sinks/ApplicationInsights/TelemetryConverters/EventTelemetryConverter.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,34 @@ namespace Serilog.Sinks.ApplicationInsights.TelemetryConverters;
1010

1111
public class EventTelemetryConverter : TelemetryConverterBase
1212
{
13+
/// <inheritdoc cref="EventTelemetryConverter(bool, bool, bool, bool)"/>
14+
public EventTelemetryConverter()
15+
: this(false, false, false, false)
16+
{
17+
}
18+
19+
/// <inheritdoc cref="TelemetryConverterBase(bool, bool, bool, bool)"/>
20+
public EventTelemetryConverter(
21+
bool includeOperationIdPropertyAsTelemetryProperty,
22+
bool includeParentSpanIdPropertyAsTelemetryProperty,
23+
bool includeOperationNamePropertyAsTelemetryProperty,
24+
bool includeVersionPropertyAsTelemetryProperty)
25+
: base(
26+
includeOperationIdPropertyAsTelemetryProperty,
27+
includeParentSpanIdPropertyAsTelemetryProperty,
28+
includeOperationNamePropertyAsTelemetryProperty,
29+
includeVersionPropertyAsTelemetryProperty)
30+
{
31+
}
32+
1333
public override IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvider formatProvider)
1434
{
1535
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
1636

1737
if (logEvent.Exception == null)
1838
{
19-
var telemetry = new EventTelemetry(logEvent.MessageTemplate.Text) {
39+
var telemetry = new EventTelemetry(logEvent.MessageTemplate.Text)
40+
{
2041
Timestamp = logEvent.Timestamp
2142
};
2243

@@ -39,4 +60,4 @@ public override void ForwardPropertiesToTelemetryProperties(LogEvent logEvent,
3960
includeRenderedMessage: true,
4061
includeMessageTemplate: false);
4162
}
42-
}
63+
}

src/Serilog.Sinks.ApplicationInsights/Sinks/ApplicationInsights/TelemetryConverters/TelemetryConverterBase.cs

Lines changed: 87 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,52 @@ public abstract class TelemetryConverterBase : ITelemetryConverter
5757

5858
static readonly MessageTemplateTextFormatter MessageTemplateTextFormatter = new("{Message:lj}");
5959

60+
private readonly bool _includeOperationIdPropertyAsTelemetryProperty;
61+
private readonly bool _includeParentSpanIdPropertyAsTelemetryProperty;
62+
private readonly bool _includeOperationNamePropertyAsTelemetryProperty;
63+
private readonly bool _includeVersionPropertyAsTelemetryProperty;
64+
6065
/// <summary>
6166
/// Creates an instance of <see cref="TelemetryConverterBase" /> using default value formatter (
6267
/// <see cref="ApplicationInsightsJsonValueFormatter" />).
6368
/// </summary>
6469
public TelemetryConverterBase()
70+
: this(false, false, false, false)
71+
{
72+
}
73+
74+
/// <summary>
75+
/// Creates an instance of <see cref="TelemetryConverterBase" /> using default value formatter (
76+
/// <see cref="ApplicationInsightsJsonValueFormatter" />).
77+
/// </summary>
78+
/// <param name="includeOperationIdPropertyAsTelemetryProperty">
79+
/// if set to <c>true</c> the <see cref="OperationIdProperty" /> is added to the
80+
/// telemetry properties. Otherwise it is only set as <c>ITelemetry.Context.Operation.Id</c>.
81+
/// </param>
82+
/// <param name="includeParentSpanIdPropertyAsTelemetryProperty">
83+
/// if set to <c>true</c> the <see cref="ParentSpanIdProperty" /> is added to the
84+
/// telemetry properties. Otherwise it is only set as <c>ITelemetry.Context.Operation.ParentId</c>.
85+
/// </param>
86+
/// <param name="includeOperationNamePropertyAsTelemetryProperty">
87+
/// if set to <c>true</c> the <see cref="OperationNameProperty" /> is added to the
88+
/// telemetry properties. Otherwise it is only set as <c>ITelemetry.Context.Operation.Name</c>.
89+
/// </param>
90+
/// <param name="includeVersionPropertyAsTelemetryProperty">
91+
/// if set to <c>true</c> the <see cref="VersionProperty" /> is added to the
92+
/// telemetry properties. Otherwise it is only set as <c>ITelemetry.Context.Component.Version</c>.
93+
/// </param>
94+
public TelemetryConverterBase(
95+
bool includeOperationIdPropertyAsTelemetryProperty,
96+
bool includeParentSpanIdPropertyAsTelemetryProperty,
97+
bool includeOperationNamePropertyAsTelemetryProperty,
98+
bool includeVersionPropertyAsTelemetryProperty)
6599
{
66100
ValueFormatter = new ApplicationInsightsJsonValueFormatter();
101+
102+
_includeOperationIdPropertyAsTelemetryProperty = includeOperationIdPropertyAsTelemetryProperty;
103+
_includeParentSpanIdPropertyAsTelemetryProperty = includeParentSpanIdPropertyAsTelemetryProperty;
104+
_includeOperationNamePropertyAsTelemetryProperty = includeOperationNamePropertyAsTelemetryProperty;
105+
_includeVersionPropertyAsTelemetryProperty = includeVersionPropertyAsTelemetryProperty;
67106
}
68107

69108
#pragma warning disable CS1591
@@ -155,42 +194,41 @@ public void ForwardPropertiesToTelemetryProperties(LogEvent logEvent,
155194

156195
if (telemetryProperties is ITelemetry telemetry)
157196
{
158-
// Operation.Id (TraceId)
159-
if (logEvent.Properties.TryGetValue(OperationIdProperty, out var operationIdProp))
160-
telemetry.Context.Operation.Id = operationIdProp.ToString().Trim('"');
161-
else if (logEvent.TraceId is ActivityTraceId traceId)
162-
telemetry.Context.Operation.Id = traceId.ToHexString();
163-
164-
// Operation.ParentId (ParentSpanId)
165-
if (logEvent.Properties.TryGetValue(ParentSpanIdProperty, out var parentSpanIdProp))
166-
telemetry.Context.Operation.ParentId = parentSpanIdProp.ToString().Trim('"');
167-
168-
// Operation.Name (OperationName)
169-
if (logEvent.Properties.TryGetValue(OperationNameProperty, out var operationNameProp))
170-
telemetry.Context.Operation.Name = operationNameProp.ToString().Trim('"');
171-
172-
// Set Id for RequestTelemetry and DependencyTelemetry
173-
if (logEvent.SpanId is ActivitySpanId spanId)
174-
{
175-
if (telemetry is RequestTelemetry req)
176-
req.Id = spanId.ToHexString();
177-
else if (telemetry is DependencyTelemetry dep)
178-
dep.Id = spanId.ToHexString();
179-
}
197+
PopulateTelemetryFromLogEvent(logEvent, telemetry);
180198

181199
if (telemetry.Context?.Component != null
182200
&& logEvent.Properties.TryGetValue(VersionProperty, out var version))
183201
telemetry.Context.Component.Version = version.ToString().Trim('\"');
184202
}
185203

186204
var baggageWasForwarded = ForwardActivityBaggage(logEvent, telemetryProperties, formatProvider);
205+
ForwardSimpleProperties(logEvent, telemetryProperties, baggageWasForwarded);
206+
}
187207

188-
var filteredProperties = logEvent.Properties.Where(property =>
189-
property.Value != null
190-
&& !(baggageWasForwarded && BaggageProperty.Equals(property.Key, StringComparison.Ordinal))
191-
&& !telemetryProperties.Properties.ContainsKey(property.Key));
192-
foreach (var property in filteredProperties)
193-
ValueFormatter.Format(property.Key, property.Value, telemetryProperties.Properties);
208+
private static void PopulateTelemetryFromLogEvent(LogEvent logEvent, ITelemetry telemetry)
209+
{
210+
// Operation.Id (TraceId)
211+
if (logEvent.Properties.TryGetValue(OperationIdProperty, out var operationIdProp))
212+
telemetry.Context.Operation.Id = operationIdProp.ToString().Trim('"');
213+
else if (logEvent.TraceId is ActivityTraceId traceId)
214+
telemetry.Context.Operation.Id = traceId.ToHexString();
215+
216+
// Operation.ParentId (ParentSpanId)
217+
if (logEvent.Properties.TryGetValue(ParentSpanIdProperty, out var parentSpanIdProp))
218+
telemetry.Context.Operation.ParentId = parentSpanIdProp.ToString().Trim('"');
219+
220+
// Operation.Name (OperationName)
221+
if (logEvent.Properties.TryGetValue(OperationNameProperty, out var operationNameProp))
222+
telemetry.Context.Operation.Name = operationNameProp.ToString().Trim('"');
223+
224+
// Set Id for RequestTelemetry and DependencyTelemetry
225+
if (logEvent.SpanId is ActivitySpanId spanId)
226+
{
227+
if (telemetry is RequestTelemetry req)
228+
req.Id = spanId.ToHexString();
229+
else if (telemetry is DependencyTelemetry dep)
230+
dep.Id = spanId.ToHexString();
231+
}
194232
}
195233

196234
private static bool ForwardActivityBaggage(LogEvent logEvent, ISupportProperties telemetryProperties, IFormatProvider formatProvider)
@@ -216,6 +254,27 @@ private static bool ForwardActivityBaggage(LogEvent logEvent, ISupportProperties
216254
return true;
217255
}
218256

257+
private void ForwardSimpleProperties(LogEvent logEvent, ISupportProperties telemetryProperties, bool skipBaggage)
258+
{
259+
var skipOperationId = !_includeOperationIdPropertyAsTelemetryProperty;
260+
var skipParentSpanId = !_includeParentSpanIdPropertyAsTelemetryProperty;
261+
var skipOperationName = !_includeOperationNamePropertyAsTelemetryProperty;
262+
var skipVersion = !_includeVersionPropertyAsTelemetryProperty;
263+
264+
foreach (var property in logEvent.Properties)
265+
{
266+
if (property.Value is null) continue;
267+
if (skipOperationId && OperationIdProperty.Equals(property.Key, StringComparison.Ordinal)) continue;
268+
if (skipParentSpanId && ParentSpanIdProperty.Equals(property.Key, StringComparison.Ordinal)) continue;
269+
if (skipOperationName && OperationNameProperty.Equals(property.Key, StringComparison.Ordinal)) continue;
270+
if (skipVersion && VersionProperty.Equals(property.Key, StringComparison.Ordinal)) continue;
271+
if (skipBaggage && BaggageProperty.Equals(property.Key, StringComparison.Ordinal)) continue;
272+
if (telemetryProperties.Properties.ContainsKey(property.Key)) continue;
273+
274+
ValueFormatter.Format(property.Key, property.Value, telemetryProperties.Properties);
275+
}
276+
}
277+
219278
/// <summary>
220279
/// To the severity level.
221280
/// </summary>

src/Serilog.Sinks.ApplicationInsights/Sinks/ApplicationInsights/TelemetryConverters/TraceTelemetryConverter.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ public class TraceTelemetryConverter : TelemetryConverterBase
1414
{
1515
static readonly MessageTemplateTextFormatter MessageTemplateTextFormatter = new("{Message:lj}");
1616

17+
/// <inheritdoc cref="EventTelemetryConverter(bool, bool, bool, bool)"/>
18+
public TraceTelemetryConverter()
19+
: this(false, false, false, false)
20+
{
21+
}
22+
23+
/// <inheritdoc cref="TelemetryConverterBase(bool, bool, bool, bool)"/>
24+
public TraceTelemetryConverter(
25+
bool includeOperationIdPropertyAsTelemetryProperty,
26+
bool includeParentSpanIdPropertyAsTelemetryProperty,
27+
bool includeOperationNamePropertyAsTelemetryProperty,
28+
bool includeVersionPropertyAsTelemetryProperty)
29+
: base(
30+
includeOperationIdPropertyAsTelemetryProperty,
31+
includeParentSpanIdPropertyAsTelemetryProperty,
32+
includeOperationNamePropertyAsTelemetryProperty,
33+
includeVersionPropertyAsTelemetryProperty)
34+
{
35+
}
36+
1737
public override IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvider formatProvider)
1838
{
1939
if (logEvent == null)
@@ -24,7 +44,8 @@ public override IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvid
2444
var sw = new StringWriter();
2545
MessageTemplateTextFormatter.Format(logEvent, sw);
2646

27-
var telemetry = new TraceTelemetry(sw.ToString()) {
47+
var telemetry = new TraceTelemetry(sw.ToString())
48+
{
2849
Timestamp = logEvent.Timestamp,
2950
SeverityLevel = ToSeverityLevel(logEvent.Level)
3051
};
@@ -39,4 +60,4 @@ public override IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvid
3960
yield return ToExceptionTelemetry(logEvent, formatProvider);
4061
}
4162
}
42-
}
63+
}

test/Serilog.Sinks.ApplicationInsights.Tests/CustomTelemetryConversionTest.cs renamed to test/Serilog.Sinks.ApplicationInsights.Tests/TelemetryConverters/CustomTelemetryConversionTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
88
using Xunit;
99

10-
namespace Serilog.Sinks.ApplicationInsights.Tests;
10+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters;
1111

1212
public class CustomTelemetryConversionTest : ApplicationInsightsTest
1313
{
@@ -55,4 +55,4 @@ public override IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvid
5555
}
5656
}
5757
}
58-
}
58+
}

test/Serilog.Sinks.ApplicationInsights.Tests/DottedOutFormattingTest.cs renamed to test/Serilog.Sinks.ApplicationInsights.Tests/TelemetryConverters/DottedOutFormattingTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
33
using Xunit;
44

5-
namespace Serilog.Sinks.ApplicationInsights.Tests;
5+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters;
66

77
public class DottedOutFormattingTest : ApplicationInsightsTest
88
{
@@ -33,4 +33,4 @@ class DottedOutTrace : TraceTelemetryConverter
3333
{
3434
public override IValueFormatter ValueFormatter => new ApplicationInsightsDottedValueFormatter();
3535
}
36-
}
36+
}

test/Serilog.Sinks.ApplicationInsights.Tests/CustomiseEventTelemetryConverterTest.cs renamed to test/Serilog.Sinks.ApplicationInsights.Tests/TelemetryConverters/Event/CustomiseEventTelemetryConverterTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using Serilog.Events;
44
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
55

6-
namespace Serilog.Sinks.ApplicationInsights.Tests;
6+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters.Event;
77

88
public class CustomiseEventTelemetryConverterTest : ApplicationInsightsTest
99
{
@@ -18,4 +18,4 @@ public override void ForwardPropertiesToTelemetryProperties(LogEvent logEvent,
1818
includeMessageTemplate: false);
1919
}
2020
}
21-
}
21+
}

test/Serilog.Sinks.ApplicationInsights.Tests/EventTelemetryConverterTest.cs renamed to test/Serilog.Sinks.ApplicationInsights.Tests/TelemetryConverters/Event/EventTelemetryConverterTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
33
using Xunit;
44

5-
namespace Serilog.Sinks.ApplicationInsights.Tests;
5+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters.Event;
66

77
public class EventTelemetryConverterTest : ApplicationInsightsTest
88
{
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
2+
using Xunit;
3+
4+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters.Event;
5+
6+
public class IncludeOperationIdTest : ApplicationInsightsTest
7+
{
8+
public IncludeOperationIdTest()
9+
: base(new EventTelemetryConverter(true, false, false, false), true, true)
10+
{
11+
}
12+
13+
[Fact]
14+
public void OperationIdIsSetAsTraceProperty()
15+
{
16+
using var activity = new System.Diagnostics.Activity("TestActivity");
17+
activity.Start();
18+
19+
Logger.Information("Hello, {operationId}!", "foo-operation-id");
20+
21+
Assert.Equal("foo-operation-id", LastSubmittedEventTelemetry.Properties["operationId"]);
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
2+
using Xunit;
3+
4+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters.Event;
5+
6+
public class IncludeOperationNameTest : ApplicationInsightsTest
7+
{
8+
public IncludeOperationNameTest()
9+
: base(new EventTelemetryConverter(false, false, true, false), true, true)
10+
{
11+
}
12+
13+
[Fact]
14+
public void OperationIdIsSetAsTraceProperty()
15+
{
16+
using var activity = new System.Diagnostics.Activity("TestActivity");
17+
activity.Start();
18+
19+
Logger.Information("Hello, {OperationName}!", "foo-operation-name");
20+
21+
Assert.Equal("foo-operation-name", LastSubmittedEventTelemetry.Properties["OperationName"]);
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
2+
using Xunit;
3+
4+
namespace Serilog.Sinks.ApplicationInsights.Tests.TelemetryConverters.Event;
5+
6+
public class IncludeSpanIdTest : ApplicationInsightsTest
7+
{
8+
public IncludeSpanIdTest()
9+
: base(new EventTelemetryConverter(false, true, false, false), true, true)
10+
{
11+
}
12+
13+
[Fact]
14+
public void OperationIdIsSetAsTraceProperty()
15+
{
16+
using var activity = new System.Diagnostics.Activity("TestActivity");
17+
activity.Start();
18+
19+
Logger.Information("Hello, {ParentSpanId}!", "foo-parent-span-id");
20+
21+
Assert.Equal("foo-parent-span-id", LastSubmittedEventTelemetry.Properties["ParentSpanId"]);
22+
}
23+
}

0 commit comments

Comments
 (0)