Skip to content

Commit 7d9cb11

Browse files
aradalvandmtmk
andauthored
Add support for Filter and Enrich for OpenTelemetry activities (#859)
* Add support for `Filter` and `Enrich` for OpenTelemetry activities * Make `internal` methods in `internal Telemetry` `public` * Fix package versions and whatnot * Remove `TracerProviderBuilderExtensions` * Include `Deserialize` in the receive activity * Revert back accidental change * Add `ParentContext` to `NatsInstrumentationContext` * Make `GetActivityContext` public to provide the ability to get context activity context * Make preprocessor directive more accurate * Revert .csproj formatting * Move public artifacts out of the `Internal` namespace/folder * Fix build script --------- Co-authored-by: Ziya Suzen <[email protected]>
1 parent 61136b6 commit 7d9cb11

File tree

9 files changed

+183
-105
lines changed

9 files changed

+183
-105
lines changed

.github/workflows/signoffs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
if: github.event_name == 'pull_request'
1717
run: |
1818
for commit in $(git rev-list "origin/${{ github.base_ref }}".."${{ github.event.pull_request.head.sha }}"); do
19-
if ! git verify-commit --raw $commit 2>&1 | grep -q SIG; then
19+
if ! git verify-commit --raw $commit 2>&1 | grep -iq SIG; then
2020
echo "--------------------------------------------------------------"
2121
echo "Error: Commit $commit is not signed using GPG, SSH, or S/MIME"
2222
echo "https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits"

src/NATS.Client.Core/Internal/Telemetry.cs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ namespace NATS.Client.Core.Internal;
66
// https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/#messaging-attributes
77
internal static class Telemetry
88
{
9-
internal static readonly ActivitySource NatsActivities = new(name: NatsActivitySource);
10-
11-
private const string NatsActivitySource = "NATS.Net";
9+
public const string NatsActivitySource = "NATS.Net";
10+
public static readonly ActivitySource NatsActivities = new(name: NatsActivitySource);
1211
private static readonly object BoxedTrue = true;
1312

14-
internal static bool HasListeners() => NatsActivities.HasListeners();
13+
public static bool HasListeners() => NatsActivities.HasListeners();
1514

16-
internal static Activity? StartSendActivity(
15+
public static Activity? StartSendActivity(
1716
string name,
1817
INatsConnection? connection,
1918
string subject,
@@ -23,6 +22,19 @@ internal static class Telemetry
2322
if (!NatsActivities.HasListeners())
2423
return null;
2524

25+
var instrumentationContext = new NatsInstrumentationContext(
26+
Subject: subject,
27+
Headers: null,
28+
ReplyTo: replyTo,
29+
QueueGroup: null,
30+
BodySize: null,
31+
Size: null,
32+
Connection: connection,
33+
ParentContext: parentContext);
34+
35+
if (NatsInstrumentationOptions.Default.Filter is { } filter && !filter(instrumentationContext))
36+
return null;
37+
2638
KeyValuePair<string, object?>[] tags;
2739
if (connection is NatsConnection { ServerInfo: not null } conn)
2840
{
@@ -63,14 +75,19 @@ internal static class Telemetry
6375
tags[3] = new KeyValuePair<string, object?>(Constants.ReplyTo, replyTo);
6476
}
6577

66-
return NatsActivities.StartActivity(
78+
var activity = NatsActivities.StartActivity(
6779
name,
6880
kind: ActivityKind.Producer,
6981
parentContext: parentContext ?? default,
7082
tags: tags);
83+
84+
if (activity is not null)
85+
NatsInstrumentationOptions.Default.Enrich?.Invoke(activity, instrumentationContext);
86+
87+
return activity;
7188
}
7289

73-
internal static void AddTraceContextHeaders(Activity? activity, ref NatsHeaders? headers)
90+
public static void AddTraceContextHeaders(Activity? activity, ref NatsHeaders? headers)
7491
{
7592
if (activity is null)
7693
return;
@@ -87,15 +104,15 @@ internal static void AddTraceContextHeaders(Activity? activity, ref NatsHeaders?
87104
return;
88105
}
89106

90-
// There are cases where headers reused internally (e.g. JetStream publish retry)
107+
// There are cases where headers reused publicly (e.g. JetStream publish retry)
91108
// there may also be cases where application can reuse the same header
92109
// in which case we should still be able to overwrite headers with telemetry fields
93110
// even though headers would be set to readonly before being passed down in publish methods.
94111
headers.SetOverrideReadOnly(fieldName, fieldValue);
95112
});
96113
}
97114

98-
internal static Activity? StartReceiveActivity(
115+
public static Activity? StartReceiveActivity(
99116
INatsConnection? connection,
100117
string name,
101118
string subscriptionSubject,
@@ -109,6 +126,22 @@ internal static void AddTraceContextHeaders(Activity? activity, ref NatsHeaders?
109126
if (!NatsActivities.HasListeners())
110127
return null;
111128

129+
if (headers is null || !TryParseTraceContext(headers, out var context))
130+
context = default;
131+
132+
var instrumentationContext = new NatsInstrumentationContext(
133+
Subject: subject,
134+
Headers: headers,
135+
ReplyTo: replyTo,
136+
QueueGroup: queueGroup,
137+
BodySize: bodySize,
138+
Size: size,
139+
Connection: connection,
140+
ParentContext: context);
141+
142+
if (NatsInstrumentationOptions.Default.Filter is { } filter && !filter(instrumentationContext))
143+
return null;
144+
112145
KeyValuePair<string, object?>[] tags;
113146
if (connection is NatsConnection { ServerInfo: not null } conn)
114147
{
@@ -162,17 +195,19 @@ internal static void AddTraceContextHeaders(Activity? activity, ref NatsHeaders?
162195
tags[9] = new KeyValuePair<string, object?>(Constants.ReplyTo, replyTo);
163196
}
164197

165-
if (headers is null || !TryParseTraceContext(headers, out var context))
166-
context = default;
167-
168-
return NatsActivities.StartActivity(
198+
var activity = NatsActivities.StartActivity(
169199
name,
170200
kind: ActivityKind.Consumer,
171201
parentContext: context,
172202
tags: tags);
203+
204+
if (activity is not null)
205+
NatsInstrumentationOptions.Default.Enrich?.Invoke(activity, instrumentationContext);
206+
207+
return activity;
173208
}
174209

175-
internal static void SetException(Activity? activity, Exception exception)
210+
public static void SetException(Activity? activity, Exception exception)
176211
{
177212
if (activity is null)
178213
return;
@@ -251,11 +286,14 @@ private static bool TryParseTraceContext(NatsHeaders headers, out ActivityContex
251286
},
252287
out var traceParent,
253288
out var traceState);
254-
289+
#if NETSTANDARD2_0_OR_GREATER || NET7_0_OR_GREATER
290+
return ActivityContext.TryParse(traceParent, traceState, isRemote: true, out context);
291+
#else
255292
return ActivityContext.TryParse(traceParent, traceState, out context);
293+
#endif
256294
}
257295

258-
internal class Constants
296+
public class Constants
259297
{
260298
public const string True = "true";
261299
public const string False = "false";

0 commit comments

Comments
 (0)