0
# Context Management
1
2
Comprehensive context management system for cross-cutting concerns in distributed applications. OpenTelemetry context provides immutable context propagation with copy-on-write semantics, enabling trace correlation, baggage handling, and instrumentation control across async boundaries and service calls.
3
4
## Capabilities
5
6
### Context Creation and Access
7
8
Manage immutable context objects for storing and propagating cross-cutting data.
9
10
```python { .api }
11
class Context:
12
"""Immutable context dictionary for cross-cutting concerns."""
13
14
def __init__(self, data: Optional[Dict[str, object]] = None) -> None:
15
"""
16
Creates a new context.
17
18
Parameters:
19
- data: Optional initial context data
20
"""
21
22
def get(self, key: str) -> object:
23
"""
24
Returns the value associated with the key.
25
26
Parameters:
27
- key: The context key
28
29
Returns:
30
The value associated with the key, or None if not found
31
"""
32
33
def copy(self) -> Dict[str, object]:
34
"""
35
Returns a shallow copy of the context data.
36
37
Returns:
38
Dictionary containing context key-value pairs
39
"""
40
41
def get_current() -> Context:
42
"""
43
Returns the current context.
44
45
Returns:
46
The current Context object
47
"""
48
```
49
50
### Key Management
51
52
Create and manage unique keys for context storage.
53
54
```python { .api }
55
def create_key(keyname: str) -> str:
56
"""
57
Creates a unique key for context storage.
58
59
Parameters:
60
- keyname: The key name for debugging purposes (not required to be unique)
61
62
Returns:
63
A unique string representing the newly created key
64
"""
65
```
66
67
### Context Value Operations
68
69
Store and retrieve values in context with immutable semantics.
70
71
```python { .api }
72
def get_value(key: str, context: Optional[Context] = None) -> object:
73
"""
74
Retrieves a value from the context.
75
76
Parameters:
77
- key: The key of the value to retrieve
78
- context: The context from which to retrieve the value, if None uses current context
79
80
Returns:
81
The value associated with the key
82
"""
83
84
def set_value(
85
key: str,
86
value: object,
87
context: Optional[Context] = None
88
) -> Context:
89
"""
90
Creates a new context with the specified key-value pair.
91
92
Parameters:
93
- key: The key of the entry to set
94
- value: The value of the entry to set
95
- context: The context to copy, if None uses current context
96
97
Returns:
98
A new Context containing the value set
99
"""
100
```
101
102
### Context Activation
103
104
Attach and detach contexts for scoped execution.
105
106
```python { .api }
107
def attach(context: Context) -> Token[Context]:
108
"""
109
Associates a Context with the caller's current execution unit.
110
111
Parameters:
112
- context: The Context to set as current
113
114
Returns:
115
A token that can be used with detach to reset the context
116
"""
117
118
def detach(token: Token[Context]) -> None:
119
"""
120
Resets the Context to the value before attaching a specified Context.
121
122
Parameters:
123
- token: The Token that was returned by a previous call to attach
124
"""
125
```
126
127
### Baggage Operations
128
129
Store and retrieve cross-service data using the baggage system.
130
131
```python { .api }
132
def get_all(context: Optional[Context] = None) -> Mapping[str, object]:
133
"""
134
Returns all name/value pairs in the Baggage.
135
136
Parameters:
137
- context: The Context to use, if not set uses current Context
138
139
Returns:
140
The name/value pairs in the Baggage
141
"""
142
143
def get_baggage(name: str, context: Optional[Context] = None) -> Optional[object]:
144
"""
145
Returns the value for a name/value pair in the Baggage.
146
147
Parameters:
148
- name: The name of the value to retrieve
149
- context: The Context to use, if not set uses current Context
150
151
Returns:
152
The value associated with the given name, or None if not present
153
"""
154
155
def set_baggage(
156
name: str,
157
value: object,
158
context: Optional[Context] = None
159
) -> Context:
160
"""
161
Sets a value in the Baggage.
162
163
Parameters:
164
- name: The name of the value to set
165
- value: The value to set
166
- context: The Context to use, if not set uses current Context
167
168
Returns:
169
A Context with the value updated
170
"""
171
172
def remove_baggage(name: str, context: Optional[Context] = None) -> Context:
173
"""
174
Removes a value from the Baggage.
175
176
Parameters:
177
- name: The name of the value to remove
178
- context: The Context to use, if not set uses current Context
179
180
Returns:
181
A Context with the name/value removed
182
"""
183
184
def clear(context: Optional[Context] = None) -> Context:
185
"""
186
Removes all values from the Baggage.
187
188
Parameters:
189
- context: The Context to use, if not set uses current Context
190
191
Returns:
192
A Context with all baggage entries removed
193
"""
194
```
195
196
### Runtime Context Implementation
197
198
Interface for runtime context implementations with different backends.
199
200
```python { .api }
201
class _RuntimeContext(ABC):
202
"""Abstract base class for runtime context implementations."""
203
204
def attach(self, context: Context) -> Token[Context]:
205
"""Attaches the given context and returns a token for detaching."""
206
207
def detach(self, token: Token[Context]) -> None:
208
"""Detaches the context associated with the given token."""
209
210
def get_current(self) -> Context:
211
"""Returns the current context."""
212
213
class ContextVarsRuntimeContext(_RuntimeContext):
214
"""Runtime context implementation using contextvars."""
215
216
def attach(self, context: Context) -> Token[Context]:
217
"""Attaches context using contextvars."""
218
219
def detach(self, token: Token[Context]) -> None:
220
"""Detaches context using contextvars."""
221
222
def get_current(self) -> Context:
223
"""Returns current context from contextvars."""
224
```
225
226
## Usage Examples
227
228
### Basic Context Operations
229
230
```python
231
from opentelemetry import context
232
233
# Create a context key
234
user_key = context.create_key("user.id")
235
236
# Set a value in context
237
ctx = context.set_value(user_key, "12345")
238
239
# Retrieve the value
240
user_id = context.get_value(user_key, ctx)
241
print(f"User ID: {user_id}") # Output: User ID: 12345
242
243
# Get current context
244
current_ctx = context.get_current()
245
```
246
247
### Context Activation with Tokens
248
249
```python
250
from opentelemetry import context
251
252
# Create a new context with data
253
request_key = context.create_key("request.id")
254
new_ctx = context.set_value(request_key, "req-123")
255
256
# Activate the context
257
token = context.attach(new_ctx)
258
259
try:
260
# Now this context is active
261
request_id = context.get_value(request_key) # Uses current context
262
print(f"Request ID: {request_id}") # Output: Request ID: req-123
263
264
# Do work in this context
265
process_request()
266
267
finally:
268
# Always detach to restore previous context
269
context.detach(token)
270
```
271
272
### Cross-Service Baggage Propagation
273
274
```python
275
from opentelemetry import baggage, context
276
277
# Set baggage values
278
ctx = baggage.set_baggage("user.id", "12345")
279
ctx = baggage.set_baggage("session.id", "abc-def", ctx)
280
281
# Activate the context
282
token = context.attach(ctx)
283
284
try:
285
# Baggage is available in current context
286
user_id = baggage.get_baggage("user.id")
287
session_id = baggage.get_baggage("session.id")
288
289
print(f"User: {user_id}, Session: {session_id}")
290
291
# Get all baggage
292
all_baggage = baggage.get_all()
293
print(f"All baggage: {dict(all_baggage)}")
294
295
# Make service call - baggage will be propagated
296
call_downstream_service()
297
298
finally:
299
context.detach(token)
300
```
301
302
### Context Manager Pattern
303
304
```python
305
from opentelemetry import context, baggage
306
from contextlib import contextmanager
307
308
@contextmanager
309
def with_user_context(user_id: str):
310
"""Context manager for user-scoped operations."""
311
ctx = baggage.set_baggage("user.id", user_id)
312
token = context.attach(ctx)
313
try:
314
yield
315
finally:
316
context.detach(token)
317
318
# Usage
319
with with_user_context("12345"):
320
# All operations in this block have user context
321
user_id = baggage.get_baggage("user.id")
322
perform_user_operation()
323
```
324
325
### Async Context Propagation
326
327
```python
328
import asyncio
329
from opentelemetry import context, baggage
330
331
async def async_operation():
332
"""Async function that preserves context."""
333
# Context is automatically propagated in async calls
334
user_id = baggage.get_baggage("user.id")
335
print(f"Processing for user: {user_id}")
336
337
await asyncio.sleep(1) # Simulated async work
338
339
# Context is still available
340
user_id = baggage.get_baggage("user.id")
341
print(f"Completed for user: {user_id}")
342
343
async def main():
344
# Set up context
345
ctx = baggage.set_baggage("user.id", "12345")
346
token = context.attach(ctx)
347
348
try:
349
# Start async operations - context propagates automatically
350
await async_operation()
351
352
# Multiple concurrent operations maintain their context
353
await asyncio.gather(
354
async_operation(),
355
async_operation(),
356
)
357
358
finally:
359
context.detach(token)
360
361
# Run async example
362
asyncio.run(main())
363
```
364
365
### Context Validation and Error Handling
366
367
```python
368
from opentelemetry import context, baggage
369
370
def safe_baggage_operations():
371
"""Demonstrate safe baggage operations."""
372
try:
373
# Set valid baggage
374
ctx = baggage.set_baggage("service.name", "user-service")
375
ctx = baggage.set_baggage("service.version", "1.2.3", ctx)
376
377
token = context.attach(ctx)
378
379
try:
380
# Get baggage safely
381
service_name = baggage.get_baggage("service.name")
382
if service_name:
383
print(f"Service: {service_name}")
384
385
# Handle missing keys gracefully
386
missing_value = baggage.get_baggage("nonexistent.key")
387
if missing_value is None:
388
print("Key not found, using default")
389
390
# Remove specific baggage
391
ctx = baggage.remove_baggage("service.version")
392
393
# Clear all baggage
394
ctx = baggage.clear()
395
396
finally:
397
context.detach(token)
398
399
except Exception as e:
400
print(f"Context operation failed: {e}")
401
# Handle context errors appropriately
402
```
403
404
## Constants and Internal Keys
405
406
```python { .api }
407
# Internal context keys (for reference, not direct usage)
408
_SUPPRESS_INSTRUMENTATION_KEY: str # Key for suppressing instrumentation
409
_SUPPRESS_HTTP_INSTRUMENTATION_KEY: str # Key for suppressing HTTP instrumentation
410
```