@@ -53,21 +53,20 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
53
53
# Use the parent sampling decision if we have an incoming trace.
54
54
# Note: we strongly recommend respecting the parent sampling decision,
55
55
# as this ensures your traces will be complete!
56
- parent_sampling_decision = sampling_context.get( " parent_sampled" )
56
+ parent_sampling_decision = sampling_context[ " parent_sampled" ]
57
57
if parent_sampling_decision is not None :
58
58
return float (parent_sampling_decision)
59
59
60
- ctx = sampling_context.get(" transaction_context" , {})
61
- name = ctx.get(" name" )
60
+ transaction_ctx = sampling_context[" transaction_context" ]
61
+ name = transaction_ctx[" name" ]
62
+ op = transaction_ctx[" op" ]
62
63
63
64
# Sample all checkout transactions
64
- if name and (' /checkout' in name or
65
- ctx.get(" op" ) == ' checkout' ):
65
+ if name and (' /checkout' in name or op == ' checkout' ):
66
66
return 1.0
67
67
68
68
# Sample 50% of login transactions
69
- if name and (' /login' in name or
70
- ctx.get(" op" ) == ' login' ):
69
+ if name and (' /login' in name or op == ' login' ):
71
70
return 0.5
72
71
73
72
# Sample 10% of everything else
@@ -89,11 +88,11 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
89
88
# Use the parent sampling decision if we have an incoming trace.
90
89
# Note: we strongly recommend respecting the parent sampling decision,
91
90
# as this ensures your traces will be complete!
92
- parent_sampling_decision = sampling_context.get( " parent_sampled" )
91
+ parent_sampling_decision = sampling_context[ " parent_sampled" ]
93
92
if parent_sampling_decision is not None :
94
93
return float (parent_sampling_decision)
95
94
96
- ctx = sampling_context.get( " transaction_context " , {})
95
+ custom_sampling_ctx = sampling_context[ " custom_sampling_context " ]
97
96
environment = os.environ.get(" ENVIRONMENT" , " development" )
98
97
99
98
# Sample all transactions in development
@@ -102,7 +101,7 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
102
101
103
102
# Sample more transactions if there are recent errors
104
103
# Note: hasRecentErrors is a custom attribute that needs to be set
105
- if ctx .get(" data " , {}).get( " hasRecentErrors" ):
104
+ if custom_sampling_ctx .get(" hasRecentErrors" ) is True :
106
105
return 0.8
107
106
108
107
# Sample based on environment
@@ -120,17 +119,15 @@ sentry_sdk.init(
120
119
traces_sampler = traces_sampler,
121
120
)
122
121
123
- # You can use the sampling function by setting custom attributes:
124
- # Option 1: When creating the transaction
125
- with sentry_sdk.start_transaction(name = " GET /api/users" , op = " http.request" ) as transaction:
126
- # Set custom attribute
127
- transaction.set_data(" hasRecentErrors" , True )
128
- # Your code here
129
-
130
- # Option 2: During the transaction's lifecycle
131
- with sentry_sdk.start_transaction(name = " GET /api/users" , op = " http.request" ) as transaction:
132
- # Your code here
133
- transaction.set_data(" hasRecentErrors" , True ) # Set custom attribute
122
+ # Custom attributes need to be set on transaction start via
123
+ # the `custom_sampling_context` argument in order to be available
124
+ # in the traces_sampler
125
+ with sentry_sdk.start_transaction(
126
+ name = " GET /api/users" ,
127
+ op = " http.request" ,
128
+ custom_sampling_context = {" hasRecentErrors" : True },
129
+ ) as transaction:
130
+ # your code here
134
131
```
135
132
136
133
3 . Controlling Sampling Based on User and Transaction Properties
@@ -143,33 +140,27 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
143
140
# Use the parent sampling decision if we have an incoming trace.
144
141
# Note: we strongly recommend respecting the parent sampling decision,
145
142
# as this ensures your traces will be complete!
146
- parent_sampling_decision = sampling_context.get( " parent_sampled" )
143
+ parent_sampling_decision = sampling_context[ " parent_sampled" ]
147
144
if parent_sampling_decision is not None :
148
145
return float (parent_sampling_decision)
149
146
150
- ctx = sampling_context.get(" transaction_context" , {})
151
- data = ctx.get(" data" , {})
147
+ custom_sampling_ctx = sampling_context[" custom_sampling_context" ]
152
148
153
149
# Always sample for premium users
154
150
# Note: user.tier is a custom attribute that needs to be set
155
- if data .get(" user" , {}).get(" tier" ) == " premium" :
151
+ if custom_sampling_ctx .get(" user" , {}).get(" tier" ) == " premium" :
156
152
return 1.0
157
153
158
154
# Sample more transactions for users experiencing errors
159
155
# Note: hasRecentErrors is a custom attribute
160
- if data .get(" hasRecentErrors" ):
156
+ if custom_sampling_ctx .get(" hasRecentErrors" ) is True :
161
157
return 0.8
162
158
163
159
# Sample less for high-volume, low-value paths
164
- # Note: name is an SDK-provided attribute
165
- if (ctx.get( " name" ) or " " ) .startswith(" /api/metrics" ):
160
+ name = sampling_context[ " transaction_context " ][ " name " ]
161
+ if name and name .startswith(" /api/metrics" ):
166
162
return 0.01
167
163
168
- # Sample more for slow transactions
169
- # Note: duration_ms is a custom attribute
170
- if data.get(" duration_ms" , 0 ) > 1000 : # Transactions over 1 second
171
- return 0.5
172
-
173
164
# Default sampling rate
174
165
return 0.2
175
166
@@ -180,13 +171,12 @@ sentry_sdk.init(
180
171
)
181
172
182
173
# To set custom attributes for this example:
183
- with sentry_sdk.start_transaction(name = " GET /api/users " , op = " http.request " ) as transaction:
184
- # Set custom attributes
185
- transaction.set_data( " user " , { " tier " : " premium " }) # Custom user data
186
- transaction.set_data( " hasRecentErrors " , True ) # Custom error flag
187
- transaction.set_data( " duration_ms " , 1500 ) # Custom timing data
174
+ with sentry_sdk.start_transaction(
175
+ name = " GET /api/users " ,
176
+ op = " http.request " ,
177
+ custom_sampling_context = { " user " : { " tier " : " premium " }, " hasRecentErrors " : True },
178
+ ) as transaction:
188
179
# Your code here
189
-
190
180
```
191
181
192
182
4 . Complex Business Logic Sampling
@@ -199,36 +189,36 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
199
189
# Use the parent sampling decision if we have an incoming trace.
200
190
# Note: we strongly recommend respecting the parent sampling decision,
201
191
# as this ensures your traces will be complete!
202
- parent_sampling_decision = sampling_context.get( " parent_sampled" )
192
+ parent_sampling_decision = sampling_context[ " parent_sampled" ]
203
193
if parent_sampling_decision is not None :
204
194
return float (parent_sampling_decision)
205
195
206
- ctx = sampling_context.get(" transaction_context" , {})
207
- data = ctx.get(" data" , {})
208
-
209
196
# Always sample critical business operations
210
197
# Note: op is an SDK-provided attribute
211
- if ctx.get(" op" ) in [" payment.process" , " order.create" , " user.verify" ]:
198
+ transaction_ctx = sampling_context[" transaction_context" ]
199
+ if transaction_ctx[" op" ] in [" payment.process" , " order.create" , " user.verify" ]:
212
200
return 1.0
213
201
202
+ custom_sampling_context = sampling_context[" custom_sampling_context" ]
203
+
214
204
# Sample based on user segment
215
205
# Note: user.segment is a custom attribute
216
- user_segment = data .get(" user" , {}).get(" segment" )
206
+ user_segment = custom_sampling_context .get(" user" , {}).get(" segment" )
217
207
if user_segment == " enterprise" :
218
208
return 0.8
219
209
elif user_segment == " premium" :
220
210
return 0.5
221
211
222
212
# Sample based on transaction value
223
213
# Note: transaction.value is a custom attribute
224
- transaction_value = data .get(" transaction" , {}).get(" value" , 0 )
225
- if transaction_value > 1000 : # High-value transactions
214
+ transaction_value = custom_sampling_context .get(" transaction" , {}).get(" value" )
215
+ if transaction_value is not None and transaction_value > 1000 : # High-value transactions
226
216
return 0.7
227
217
228
218
# Sample based on error rate in the service
229
219
# Note: service.error_rate is a custom attribute
230
- error_rate = data .get(" service" , {}).get(" error_rate" , 0 )
231
- if error_rate > 0.05 : # Error rate above 5%
220
+ error_rate = custom_sampling_context .get(" service" , {}).get(" error_rate" )
221
+ if error_rate is not None and error_rate > 0.05 : # Error rate above 5%
232
222
return 0.9
233
223
234
224
# Default sampling rate
@@ -241,11 +231,11 @@ sentry_sdk.init(
241
231
)
242
232
243
233
# To set custom attributes for this example:
244
- with sentry_sdk.start_transaction(name = " Process Payment " , op = " payment.process " ) as transaction:
245
- # Set custom attributes
246
- transaction.set_data( " user " , { " segment " : " enterprise " }) # Custom user data
247
- transaction.set_data( " transaction " , {" value" : 1500 }) # Custom transaction data
248
- transaction.set_data( " service " , { " error_rate " : 0.03 }) # Custom service data
234
+ with sentry_sdk.start_transaction(
235
+ name = " Process Payment " ,
236
+ op = " payment.process " ,
237
+ custom_sampling_context = { " user " : { " segment " : " enterprise " }, " transaction " : {" value" : 1500 }, " service " : { " error_rate " : 0.03 }},
238
+ ) as transaction:
249
239
# Your code here
250
240
251
241
```
@@ -260,31 +250,28 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
260
250
# Use the parent sampling decision if we have an incoming trace.
261
251
# Note: we strongly recommend respecting the parent sampling decision,
262
252
# as this ensures your traces will be complete!
263
- parent_sampling_decision = sampling_context.get( " parent_sampled" )
253
+ parent_sampling_decision = sampling_context[ " parent_sampled" ]
264
254
if parent_sampling_decision is not None :
265
255
return float (parent_sampling_decision)
266
256
267
- ctx = sampling_context.get(" transaction_context" , {})
268
- data = ctx.get(" data" , {})
269
-
270
- # Sample all slow transactions
271
- # Note: duration_ms is a custom attribute
272
- if data.get(" duration_ms" , 0 ) > 2000 : # Over 2 seconds
273
- return 1.0
257
+ custom_sampling_ctx = sampling_context[" custom_sampling_context" ]
274
258
275
259
# Sample more transactions with high memory usage
276
260
# Note: memory_usage_mb is a custom attribute
277
- if data.get(" memory_usage_mb" , 0 ) > 500 : # Over 500MB
261
+ memory_usage = custom_sampling_ctx.get(" memory_usage_mb" )
262
+ if memory_usage is not None and memory_usage > 500 :
278
263
return 0.8
279
264
280
265
# Sample more transactions with high CPU usage
281
266
# Note: cpu_percent is a custom attribute
282
- if data.get(" cpu_percent" , 0 ) > 80 : # Over 80% CPU
267
+ cpu_percent = custom_sampling_ctx.get(" cpu_percent" )
268
+ if cpu_percent is not None and cpu_percent > 80 :
283
269
return 0.8
284
270
285
271
# Sample more transactions with high database load
286
272
# Note: db_connections is a custom attribute
287
- if data.get(" db_connections" , 0 ) > 100 : # Over 100 connections
273
+ db_connections = custom_sampling_ctx.get(" db_connections" )
274
+ if db_connections is not None and db_connections > 100 :
288
275
return 0.7
289
276
290
277
# Default sampling rate
@@ -297,14 +284,12 @@ sentry_sdk.init(
297
284
)
298
285
299
286
# To set custom attributes for this example:
300
- with sentry_sdk.start_transaction(name = " Process Data" , op = " data.process" ) as transaction:
301
- # Set custom attributes
302
- transaction.set_data(" duration_ms" , 2500 ) # Custom timing data
303
- transaction.set_data(" memory_usage_mb" , 600 ) # Custom memory data
304
- transaction.set_data(" cpu_percent" , 85 ) # Custom CPU data
305
- transaction.set_data(" db_connections" , 120 ) # Custom database data
287
+ with sentry_sdk.start_transaction(
288
+ name = " Process Data" ,
289
+ op = " data.process" ,
290
+ custom_sampling_context = {" memory_usage_mb" : 600 , " cpu_percent" : 85 , " db_connections" : 120 },
291
+ ) as transaction:
306
292
# Your code here
307
-
308
293
```
309
294
</details >
310
295
@@ -315,13 +300,13 @@ When the `traces_sampler` function is called, the Sentry SDK passes a `sampling_
315
300
``` python
316
301
{
317
302
" transaction_context" : {
318
- " name" : str , # transaction title at creation time (SDK-provided)
319
- " op" : str , # short description of transaction type (SDK-provided)
320
- " data" : Optional[Dict [str , Any]] # custom data you've added to the transaction
303
+ " name" : str , # transaction title at creation time (SDK-provided)
304
+ " op" : str , # short description of transaction type (SDK-provided)
305
+ " data" : Optional[dict [str , Any]]
321
306
},
322
307
" parent_sampled" : Optional[bool ], # whether the parent transaction was sampled (SDK-provided)
323
- " parent_sample_rate" : Optional[float ], # the sample rate used by the parent (SDK-provided)
324
- " custom_sampling_context" : Optional[Dict [str , Any]] # additional custom data for sampling
308
+ " parent_sample_rate" : Optional[float ], # the sample rate used by the parent (SDK-provided)
309
+ " custom_sampling_context" : Optional[dict [str , Any]] # additional custom data for sampling
325
310
}
326
311
```
327
312
@@ -336,7 +321,6 @@ The sampling context contains both SDK-provided attributes and custom attributes
336
321
- ` parent_sample_rate ` : The sample rate used by the parent
337
322
338
323
** Custom Attributes:**
339
- - Any data you add to the ` set_data ` method on the transaction object. Use this for data that you want to include in the transaction data that gets sent to Sentry.
340
324
- Any data you add to the ` custom_sampling_context ` parameter in ` start_transaction ` . Use this for data that you want to use for sampling decisions but don't want to include in the transaction data that gets sent to Sentry. Read more about sampling context [ here] ( /platforms/python/configuration/sampling/#sampling-context ) .
341
325
342
326
## Sampling Decision Precedence
0 commit comments