0
# Annotations and Metadata
1
2
Data attachment capabilities for enriching X-Ray traces with searchable annotations and debugging metadata. Annotations are indexed and searchable in the X-Ray console, while metadata provides additional context for debugging and analysis.
3
4
## Capabilities
5
6
### Annotation Management
7
8
Add searchable key-value pairs to traces that are indexed by X-Ray for filtering and analysis.
9
10
```python { .api }
11
def put_annotation(key: str, value: str) -> None:
12
"""
13
Add an annotation to the current active trace entity.
14
15
Args:
16
key (str): Annotation key (must be a string)
17
value (str): Annotation value (must be a string)
18
19
Notes:
20
- Annotations are indexed and searchable in X-Ray console
21
- Maximum 50 annotations per segment/subsegment
22
- Key and value must be strings
23
- Used for filtering traces in X-Ray console queries
24
"""
25
```
26
27
### Metadata Management
28
29
Add arbitrary structured data to traces for debugging and context information.
30
31
```python { .api }
32
def put_metadata(key: str, value: Any, namespace: str = 'default') -> None:
33
"""
34
Add metadata to the current active trace entity.
35
36
Args:
37
key (str): Metadata key
38
value (Any): Metadata value (can be any JSON-serializable type)
39
namespace (str): Optional namespace for organizing metadata (default: 'default')
40
41
Notes:
42
- Metadata is not indexed but provides rich debugging context
43
- Can store complex objects, lists, dictionaries
44
- Organized by namespaces for better organization
45
- No limit on metadata size (within segment size limits)
46
"""
47
```
48
49
### Sampling Status
50
51
Check if the current trace is being sampled to optimize expensive operations.
52
53
```python { .api }
54
def is_sampled() -> bool:
55
"""
56
Check if the current trace entity is being sampled.
57
58
Returns:
59
bool: True if the current entity is sampled, False otherwise
60
61
Notes:
62
- Use to conditionally execute expensive annotation/metadata generation
63
- Unsampled traces still record structure but skip detailed data
64
"""
65
```
66
67
## Entity-Level Methods
68
69
### Segment and Subsegment Methods
70
71
Both Segment and Subsegment classes provide direct methods for adding annotations and metadata.
72
73
```python { .api }
74
class Segment:
75
def put_annotation(self, key: str, value: str) -> None:
76
"""Add annotation directly to this segment."""
77
78
def put_metadata(self, key: str, value: Any, namespace: str = 'default') -> None:
79
"""Add metadata directly to this segment."""
80
81
class Subsegment:
82
def put_annotation(self, key: str, value: str) -> None:
83
"""Add annotation directly to this subsegment."""
84
85
def put_metadata(self, key: str, value: Any, namespace: str = 'default') -> None:
86
"""Add metadata directly to this subsegment."""
87
```
88
89
### HTTP-Specific Metadata
90
91
Add HTTP-related metadata to traces for web applications.
92
93
```python { .api }
94
def put_http_meta(key: str, value: Any) -> None:
95
"""
96
Add HTTP-specific metadata to the current trace entity.
97
98
Args:
99
key (str): HTTP metadata key ('url', 'method', 'status', 'user_agent', etc.)
100
value (Any): HTTP metadata value
101
102
Common Keys:
103
- 'url': Request URL
104
- 'method': HTTP method (GET, POST, etc.)
105
- 'status': HTTP status code
106
- 'user_agent': Client user agent
107
- 'client_ip': Client IP address
108
- 'content_length': Response content length
109
"""
110
```
111
112
### Status Flags
113
114
Mark traces with status indicators for error analysis.
115
116
```python { .api }
117
def add_throttle_flag() -> None:
118
"""Mark the current entity as throttled."""
119
120
def add_fault_flag() -> None:
121
"""Mark the current entity as having a fault (5xx errors)."""
122
123
def add_error_flag() -> None:
124
"""Mark the current entity as having an error (4xx errors)."""
125
126
def apply_status_code(status_code: int) -> None:
127
"""
128
Apply HTTP status code effects to the current entity.
129
130
Args:
131
status_code (int): HTTP status code
132
133
Effects:
134
- 4xx codes: Adds error flag
135
- 5xx codes: Adds fault flag
136
- 429 code: Adds throttle flag
137
"""
138
```
139
140
### Exception Handling
141
142
Automatically capture exception information in traces.
143
144
```python { .api }
145
def add_exception(exception: Exception, stack: list = None, remote: bool = False) -> None:
146
"""
147
Add exception information to the current trace entity.
148
149
Args:
150
exception (Exception): Exception object to record
151
stack (list): Optional stack trace (auto-generated if not provided)
152
remote (bool): Whether the exception originated from a remote service
153
154
Notes:
155
- Automatically called when exceptions occur within traced code
156
- Can be called manually for custom exception handling
157
- Records exception type, message, and stack trace
158
"""
159
```
160
161
## Usage Patterns
162
163
### Basic Annotations
164
165
```python
166
from aws_xray_sdk.core import xray_recorder
167
168
with xray_recorder.in_segment('user-request') as segment:
169
# Add searchable annotations
170
xray_recorder.put_annotation('user_id', '12345')
171
xray_recorder.put_annotation('user_type', 'premium')
172
xray_recorder.put_annotation('region', 'us-east-1')
173
174
# These annotations can be used for filtering in X-Ray console:
175
# annotation.user_type = "premium"
176
# annotation.region = "us-east-1"
177
```
178
179
### Rich Metadata
180
181
```python
182
from aws_xray_sdk.core import xray_recorder
183
184
with xray_recorder.in_segment('api-request') as segment:
185
# Add structured metadata
186
xray_recorder.put_metadata('request_info', {
187
'method': 'POST',
188
'path': '/api/users',
189
'query_params': {'limit': 50, 'offset': 0},
190
'headers': {'user-agent': 'MyApp/1.0'},
191
'payload_size': 1024
192
})
193
194
# Add metadata in different namespaces
195
xray_recorder.put_metadata('database_config', {
196
'host': 'db.example.com',
197
'database': 'users',
198
'connection_pool_size': 10
199
}, namespace='database')
200
201
xray_recorder.put_metadata('feature_flags', {
202
'new_ui': True,
203
'advanced_search': False,
204
'beta_features': True
205
}, namespace='configuration')
206
```
207
208
### Conditional Expensive Operations
209
210
```python
211
from aws_xray_sdk.core import xray_recorder
212
213
with xray_recorder.in_segment('data-processing') as segment:
214
# Only perform expensive operations if trace is sampled
215
if xray_recorder.is_sampled():
216
# Generate expensive debugging information
217
performance_metrics = analyze_performance_deep()
218
system_state = capture_system_state()
219
220
xray_recorder.put_metadata('performance', performance_metrics)
221
xray_recorder.put_metadata('system_state', system_state)
222
223
# Generate detailed annotations
224
xray_recorder.put_annotation('cpu_usage', str(performance_metrics['cpu']))
225
xray_recorder.put_annotation('memory_usage', str(performance_metrics['memory']))
226
else:
227
# Minimal annotation for unsampled traces
228
xray_recorder.put_annotation('operation', 'data_processing')
229
```
230
231
### HTTP Request Tracing
232
233
```python
234
from aws_xray_sdk.core import xray_recorder
235
import requests
236
237
with xray_recorder.in_segment('web-request') as segment:
238
# Add HTTP-specific metadata
239
segment.put_http_meta('method', 'GET')
240
segment.put_http_meta('url', 'https://api.example.com/users')
241
segment.put_http_meta('user_agent', 'MyApp/1.0')
242
243
try:
244
response = requests.get('https://api.example.com/users')
245
246
# Add response information
247
segment.put_http_meta('status', response.status_code)
248
segment.put_http_meta('content_length', len(response.content))
249
250
# Apply status code effects
251
segment.apply_status_code(response.status_code)
252
253
# Add business logic annotations
254
xray_recorder.put_annotation('api_version', response.headers.get('API-Version', 'unknown'))
255
xray_recorder.put_annotation('response_size', str(len(response.content)))
256
257
except requests.RequestException as e:
258
# Exception is automatically captured
259
xray_recorder.put_annotation('error_type', 'network_error')
260
raise
261
```
262
263
### Database Operation Tracing
264
265
```python
266
from aws_xray_sdk.core import xray_recorder
267
import sqlite3
268
269
with xray_recorder.in_segment('database-operation') as segment:
270
with xray_recorder.in_subsegment('user-query') as subsegment:
271
# Add database-specific annotations
272
subsegment.put_annotation('table', 'users')
273
subsegment.put_annotation('operation', 'SELECT')
274
subsegment.put_annotation('index_used', 'user_id_idx')
275
276
# Add detailed metadata
277
subsegment.put_metadata('query_info', {
278
'sql': 'SELECT * FROM users WHERE user_id = ?',
279
'parameters': ['12345'],
280
'estimated_rows': 1,
281
'execution_plan': 'index_scan'
282
}, namespace='database')
283
284
# Execute query
285
conn = sqlite3.connect('app.db')
286
cursor = conn.cursor()
287
cursor.execute('SELECT * FROM users WHERE user_id = ?', ('12345',))
288
result = cursor.fetchone()
289
290
# Add result metadata
291
subsegment.put_metadata('result_info', {
292
'rows_returned': 1 if result else 0,
293
'execution_time_ms': 15.2,
294
'cache_hit': False
295
}, namespace='database')
296
```
297
298
### Error Handling and Status
299
300
```python
301
from aws_xray_sdk.core import xray_recorder
302
303
with xray_recorder.in_segment('error-prone-operation') as segment:
304
try:
305
# Risky operation
306
result = perform_risky_operation()
307
308
# Success annotations
309
xray_recorder.put_annotation('status', 'success')
310
311
except ValueError as e:
312
# Client error (4xx equivalent)
313
segment.add_error_flag()
314
xray_recorder.put_annotation('error_type', 'validation_error')
315
xray_recorder.put_metadata('error_details', {
316
'error_message': str(e),
317
'error_code': 'INVALID_INPUT'
318
})
319
raise
320
321
except ConnectionError as e:
322
# Server fault (5xx equivalent)
323
segment.add_fault_flag()
324
xray_recorder.put_annotation('error_type', 'connection_error')
325
raise
326
327
except Exception as e:
328
# Unknown error
329
segment.add_fault_flag()
330
xray_recorder.put_annotation('error_type', 'unknown_error')
331
# Exception details are automatically captured
332
raise
333
```
334
335
### Entity-Specific Metadata
336
337
```python
338
from aws_xray_sdk.core import xray_recorder
339
340
with xray_recorder.in_segment('multi-step-process') as segment:
341
# Segment-level metadata
342
segment.put_annotation('process_type', 'batch_job')
343
segment.put_metadata('job_config', {
344
'batch_size': 1000,
345
'timeout': 300,
346
'retry_count': 3
347
})
348
349
for i in range(3):
350
with xray_recorder.in_subsegment(f'step-{i+1}') as subsegment:
351
# Subsegment-specific metadata
352
subsegment.put_annotation('step_number', str(i+1))
353
subsegment.put_metadata('step_config', {
354
'input_size': 100 * (i+1),
355
'processing_mode': 'parallel' if i > 0 else 'sequential'
356
})
357
358
# Process step
359
process_step(i+1)
360
```
361
362
## Best Practices
363
364
### Annotation Guidelines
365
366
1. **Use for Filtering**: Only add annotations that you'll use for filtering in X-Ray console
367
2. **String Values Only**: Annotations must have string keys and string values
368
3. **Limit Quantity**: Maximum 50 annotations per segment/subsegment
369
4. **Meaningful Names**: Use descriptive keys like 'user_id', 'operation_type', 'region'
370
371
### Metadata Guidelines
372
373
1. **Rich Context**: Use metadata for detailed debugging information
374
2. **Namespace Organization**: Group related metadata using namespaces
375
3. **JSON Serializable**: Ensure metadata values can be serialized to JSON
376
4. **Size Consideration**: Large metadata affects segment size and performance
377
378
### Performance Optimization
379
380
```python
381
from aws_xray_sdk.core import xray_recorder
382
383
with xray_recorder.in_segment('optimized-operation') as segment:
384
# Always add essential annotations
385
xray_recorder.put_annotation('operation_id', operation_id)
386
387
# Conditionally add expensive metadata
388
if xray_recorder.is_sampled():
389
# Expensive operations only for sampled traces
390
detailed_metrics = generate_detailed_metrics()
391
xray_recorder.put_metadata('detailed_metrics', detailed_metrics)
392
393
# Lightweight annotations for all traces
394
xray_recorder.put_annotation('status', 'processed')
395
```