@@ -53,21 +53,20 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
5353 # Use the parent sampling decision if we have an incoming trace.
5454 # Note: we strongly recommend respecting the parent sampling decision,
5555 # 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" ]
5757 if parent_sampling_decision is not None :
5858 return float (parent_sampling_decision)
5959
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" ]
6263
6364 # 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' ):
6666 return 1.0
6767
6868 # 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' ):
7170 return 0.5
7271
7372 # Sample 10% of everything else
@@ -89,11 +88,11 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
8988 # Use the parent sampling decision if we have an incoming trace.
9089 # Note: we strongly recommend respecting the parent sampling decision,
9190 # 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" ]
9392 if parent_sampling_decision is not None :
9493 return float (parent_sampling_decision)
9594
96- ctx = sampling_context.get( " transaction_context " , {})
95+ custom_sampling_ctx = sampling_context[ " custom_sampling_context " ]
9796 environment = os.environ.get(" ENVIRONMENT" , " development" )
9897
9998 # Sample all transactions in development
@@ -102,7 +101,7 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
102101
103102 # Sample more transactions if there are recent errors
104103 # 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 :
106105 return 0.8
107106
108107 # Sample based on environment
@@ -120,17 +119,15 @@ sentry_sdk.init(
120119 traces_sampler = traces_sampler,
121120)
122121
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
134131```
135132
1361333 . Controlling Sampling Based on User and Transaction Properties
@@ -143,33 +140,27 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
143140 # Use the parent sampling decision if we have an incoming trace.
144141 # Note: we strongly recommend respecting the parent sampling decision,
145142 # 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" ]
147144 if parent_sampling_decision is not None :
148145 return float (parent_sampling_decision)
149146
150- ctx = sampling_context.get(" transaction_context" , {})
151- data = ctx.get(" data" , {})
147+ custom_sampling_ctx = sampling_context[" custom_sampling_context" ]
152148
153149 # Always sample for premium users
154150 # 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" :
156152 return 1.0
157153
158154 # Sample more transactions for users experiencing errors
159155 # Note: hasRecentErrors is a custom attribute
160- if data .get(" hasRecentErrors" ):
156+ if custom_sampling_ctx .get(" hasRecentErrors" ) is True :
161157 return 0.8
162158
163159 # 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" ):
166162 return 0.01
167163
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-
173164 # Default sampling rate
174165 return 0.2
175166
@@ -180,13 +171,12 @@ sentry_sdk.init(
180171)
181172
182173# 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:
188179 # Your code here
189-
190180```
191181
1921824 . Complex Business Logic Sampling
@@ -199,36 +189,36 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
199189 # Use the parent sampling decision if we have an incoming trace.
200190 # Note: we strongly recommend respecting the parent sampling decision,
201191 # 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" ]
203193 if parent_sampling_decision is not None :
204194 return float (parent_sampling_decision)
205195
206- ctx = sampling_context.get(" transaction_context" , {})
207- data = ctx.get(" data" , {})
208-
209196 # Always sample critical business operations
210197 # 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" ]:
212200 return 1.0
213201
202+ custom_sampling_context = sampling_context[" custom_sampling_context" ]
203+
214204 # Sample based on user segment
215205 # 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" )
217207 if user_segment == " enterprise" :
218208 return 0.8
219209 elif user_segment == " premium" :
220210 return 0.5
221211
222212 # Sample based on transaction value
223213 # 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
226216 return 0.7
227217
228218 # Sample based on error rate in the service
229219 # 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%
232222 return 0.9
233223
234224 # Default sampling rate
@@ -241,11 +231,11 @@ sentry_sdk.init(
241231)
242232
243233# 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:
249239 # Your code here
250240
251241```
@@ -260,31 +250,28 @@ def traces_sampler(sampling_context: SamplingContext) -> float:
260250 # Use the parent sampling decision if we have an incoming trace.
261251 # Note: we strongly recommend respecting the parent sampling decision,
262252 # 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" ]
264254 if parent_sampling_decision is not None :
265255 return float (parent_sampling_decision)
266256
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" ]
274258
275259 # Sample more transactions with high memory usage
276260 # 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 :
278263 return 0.8
279264
280265 # Sample more transactions with high CPU usage
281266 # 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 :
283269 return 0.8
284270
285271 # Sample more transactions with high database load
286272 # 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 :
288275 return 0.7
289276
290277 # Default sampling rate
@@ -297,14 +284,12 @@ sentry_sdk.init(
297284)
298285
299286# 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:
306292 # Your code here
307-
308293```
309294</details >
310295
@@ -315,13 +300,13 @@ When the `traces_sampler` function is called, the Sentry SDK passes a `sampling_
315300``` python
316301{
317302 " 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]]
321306 },
322307 " 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
325310}
326311```
327312
@@ -336,7 +321,6 @@ The sampling context contains both SDK-provided attributes and custom attributes
336321- ` parent_sample_rate ` : The sample rate used by the parent
337322
338323** 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.
340324- 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 ) .
341325
342326## Sampling Decision Precedence
0 commit comments