Skip to content

Commit f41442f

Browse files
committed
update
1 parent 5ff061e commit f41442f

File tree

1 file changed

+86
-25
lines changed

1 file changed

+86
-25
lines changed

_posts/2024-12-27-trace-baggage-context-propagation-open-telementry.md

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,49 @@ layout: single
33
title: "Trace & Baggage Context Propagation in .NET with OpenTelemetry"
44
---
55

6-
Context Propagation is an essential concept of distributed tracing. As the name suggests, it propagates the `trace` and `baggage` context over a network to other services.
6+
Context propagation is a key part of distributed tracing. It enables transmitting both `trace` and `baggage` context across network boundaries so that different services in your system can participate in the same `trace`.
77

88

9-
[Trace Context](https://www.w3.org/TR/trace-context/) and [Baggage Context](https://www.w3.org/TR/baggage/) are defined by the W3C standard. The propagation is by HTTP headers.
9+
The W3C provides standards for propagation:
10+
11+
* [Trace Context](https://www.w3.org/TR/trace-context/)
12+
* [Baggage Context](https://www.w3.org/TR/baggage/)
13+
14+
These contexts are transferred in HTTP headers (or other protocols), typically as traceparent for trace context and baggage for baggage context. Below, we will explore how this works in .NET with OpenTelemetry.
1015

1116
## TraceContext
1217

13-
The `traceparent` header represents incomming information about previous trace context.
18+
The `traceparent` header contains information about the current trace.
1419

15-
`traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01`
20+
```csharp
21+
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
22+
```
1623

1724
Format
18-
* version
19-
* trace-id
20-
* parent-id
21-
* trace-flags
25+
* Version (00)
26+
* Trace-Id (0af7651916cd43dd8448eb211c80319c)
27+
* Parent-Id (b7ad6b7169203331)
28+
* Trace-Flags (01)
29+
30+
n .NET, a trace (or span) is represented by an Activity object. Each Activity instance corresponds to one span in the trace.
2231

2332
## BaggageContext
2433

25-
The `baggage` header represents incomming baggage context. Its `key=value` representation.
34+
The `baggage` header holds additional context in the form of `key=value` pairs.
35+
```csharp
36+
baggage: key1=value1
37+
```
38+
2639

27-
`baggage: key1=value1`
40+
In .NET with OpenTelemetry, do not use `Activity.Baggage` to read or modify baggage. Instead, use `Baggage.Current` from the `OpenTelemetry.Api` package.
2841

29-
The information is transferred in plaintext. Be aware of personally sensitive information.
42+
This ensures that baggage context is managed consistently with the OpenTelemetry specifications.
43+
44+
> Tmportant: This header values are transferred in plaintext. Avoid placing sensitive or personally identifiable information in baggage context.
3045

3146
# .NET Usage
3247

33-
Tracing configuration registers `TraceContextPropagator` and `BaggageContextPropagator` out of the box.
48+
Tracing configuration registers `TraceContextPropagator` and `BaggageContextPropagator` out of the box.
3449

3550

3651
```csharp
@@ -42,33 +57,79 @@ builder.Services.AddOpenTelemetry()
4257
});
4358
```
4459

45-
You can use your own propagators (zipking,...)
60+
These propagators enable extracting `traceparent` and `baggage` headers format from incoming requests and injecting them into outgoing requests.
61+
62+
## Custom Propagators
63+
If you need support for alternative or custom propagators (e.g., Zipkin headers), you can set them explicitly using a CompositeTextMapPropagator
64+
4665
```csharp
4766
Sdk.SetDefaultTextMapPropagator(new CompositeTextMapPropagator(
4867
new List<TextMapPropagator>() {
4968
new MyCustomPropagator()
5069
}));
5170
```
5271

53-
To enable propagation (trace & baggege) over HTTP register
54-
`AddAspNetCoreInstrumentation` and
55-
`AddHttpClientInstrumentation` to do it by default.
72+
## HTTP Propagation
73+
74+
By adding the following instrumentation, OpenTelemetry will automatically handle context propagation for incoming and outgoing HTTP requests.
75+
76+
* **AddAspNetCoreInstrumentation** extracts traceparent and baggage from incoming HTTP requests.
77+
* **AddHttpClientInstrumentation** injects traceparent and baggage into outgoing HTTP requests.
78+
79+
5680
```csharp
57-
builder.Services.AddOpenTelemetry()
81+
builder.Services.AddOpenTelemetry()
5882
.UseOtlpExporter()
5983
.WithTracing(tracing =>
60-
{
61-
tracing
84+
{
85+
tracing
6286
.AddSource(builder.Environment.ApplicationName)
6387
.AddAspNetCoreInstrumentation()
64-
.AddHttpClientInstrumentation()
65-
});
66-
67-
88+
.AddHttpClientInstrumentation();
89+
});
6890
```
6991

70-
If you are interested how the HTTP Propagation works - [Incomming HTTP](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs#L109), [Outgoing HTTP](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs#L94).
7192

7293

94+
If you want to see how this works under the hood, check out the OpenTelemetry .NET code for [incoming HTTP instrumentation](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs#L109) and [outgoing HTTP instrumentation]((https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs#L94)).
95+
7396

74-
Propagate contexts over other protocols - messaging, database, etc. You need to do it manually with the `Inject` and then `Extract` methods through transfer attributes by `Propagators.DefaultTextMapPropagator` that provides registered propagators.
97+
## Manual Propagation
98+
99+
For protocols not natively instrumented (e.g., messaging systems or databases), you'll need to manually propagate the context by calling the `Inject` and `Extract` methods on the `Propagators.DefaultTextMapPropagator`.
100+
101+
102+
```csharp
103+
public void SendMessage(IMessage message)
104+
{
105+
var propagationContext = new PropagationContext(Activity.Current?.Context ?? default, Baggage.Current);
106+
107+
108+
Propagators.DefaultTextMapPropagator.Inject(
109+
propagationContext,
110+
message.Headers,
111+
(headers, key, value) => headers[key] = value
112+
);
113+
114+
// Publishing ...
115+
}
116+
117+
public void ProcessMessage(IDictionary<string, string> messageHeaders)
118+
{
119+
var propagationContext = Propagators.DefaultTextMapPropagator.Extract(
120+
default,
121+
messageHeaders,
122+
(headers, key) => headers.TryGetValue(key, out var value) ? new[] { value } : Array.Empty<string>()
123+
);
124+
125+
using var activity = ActivityProvider.ActivitySource.StartActivity("receive", ActivityKind.Consumer, propagationContext.ActivityContext);
126+
127+
Baggage.Current = propagationContext.Baggage;
128+
129+
// Processing ...
130+
131+
}
132+
133+
```
134+
135+
Using this approach, you maintain consistent `trace` and `baggage` context across any protocol or communication mechanism in your distributed system.

0 commit comments

Comments
 (0)