@@ -34,6 +34,10 @@ class Tracer:
34
34
disable tracer (e.g. `"true", "True", "TRUE"`)
35
35
POWERTOOLS_SERVICE_NAME : str
36
36
service name
37
+ POWERTOOLS_TRACER_CAPTURE_RESPONSE : str
38
+ disable auto-capture response as metadata (e.g. `"true", "True", "TRUE"`)
39
+ POWERTOOLS_TRACER_CAPTURE_ERROR : str
40
+ disable auto-capture error as metadata (e.g. `"true", "True", "TRUE"`)
37
41
38
42
Parameters
39
43
----------
@@ -226,7 +230,12 @@ def patch(self, modules: Tuple[str] = None):
226
230
else :
227
231
aws_xray_sdk .core .patch (modules )
228
232
229
- def capture_lambda_handler (self , lambda_handler : Callable [[Dict , Any ], Any ] = None , capture_response : bool = True ):
233
+ def capture_lambda_handler (
234
+ self ,
235
+ lambda_handler : Callable [[Dict , Any ], Any ] = None ,
236
+ capture_response : bool = True ,
237
+ capture_error : bool = True ,
238
+ ):
230
239
"""Decorator to create subsegment for lambda handlers
231
240
232
241
As Lambda follows (event, context) signature we can remove some of the boilerplate
@@ -238,6 +247,8 @@ def capture_lambda_handler(self, lambda_handler: Callable[[Dict, Any], Any] = No
238
247
Method to annotate on
239
248
capture_response : bool, optional
240
249
Instructs tracer to not include handler's response as metadata, by default True
250
+ capture_error : bool, optional
251
+ Instructs tracer to not include handler's error as metadata, by default True
241
252
242
253
Example
243
254
-------
@@ -264,10 +275,17 @@ def handler(event, context):
264
275
# Return a partial function with args filled
265
276
if lambda_handler is None :
266
277
logger .debug ("Decorator called with parameters" )
267
- return functools .partial (self .capture_lambda_handler , capture_response = capture_response )
278
+ return functools .partial (
279
+ self .capture_lambda_handler , capture_response = capture_response , capture_error = capture_error
280
+ )
268
281
269
282
lambda_handler_name = lambda_handler .__name__
270
283
284
+ capture_response_env_option = str (os .getenv ("POWERTOOLS_TRACER_CAPTURE_RESPONSE" , "false" ))
285
+ capture_error_env_option = str (os .getenv ("POWERTOOLS_TRACER_CAPTURE_ERROR" , "false" ))
286
+ capture_response = strtobool (capture_response_env_option ) or capture_response
287
+ capture_error = strtobool (capture_error_env_option ) or capture_error
288
+
271
289
@functools .wraps (lambda_handler )
272
290
def decorate (event , context ):
273
291
with self .provider .in_subsegment (name = f"## { lambda_handler_name } " ) as subsegment :
@@ -290,15 +308,15 @@ def decorate(event, context):
290
308
except Exception as err :
291
309
logger .exception (f"Exception received from { lambda_handler_name } " )
292
310
self ._add_full_exception_as_metadata (
293
- method_name = lambda_handler_name , error = err , subsegment = subsegment
311
+ method_name = lambda_handler_name , error = err , subsegment = subsegment , capture_error = capture_error
294
312
)
295
313
raise
296
314
297
315
return response
298
316
299
317
return decorate
300
318
301
- def capture_method (self , method : Callable = None , capture_response : bool = True ):
319
+ def capture_method (self , method : Callable = None , capture_response : bool = True , capture_error : bool = True ):
302
320
"""Decorator to create subsegment for arbitrary functions
303
321
304
322
It also captures both response and exceptions as metadata
@@ -318,6 +336,8 @@ def capture_method(self, method: Callable = None, capture_response: bool = True)
318
336
Method to annotate on
319
337
capture_response : bool, optional
320
338
Instructs tracer to not include method's response as metadata, by default True
339
+ capture_error : bool, optional
340
+ Instructs tracer to not include handler's error as metadata, by default True
321
341
322
342
Example
323
343
-------
@@ -449,51 +469,62 @@ async def async_tasks():
449
469
# Return a partial function with args filled
450
470
if method is None :
451
471
logger .debug ("Decorator called with parameters" )
452
- return functools .partial (self .capture_method , capture_response = capture_response )
472
+ return functools .partial (
473
+ self .capture_method , capture_response = capture_response , capture_error = capture_error
474
+ )
453
475
454
476
method_name = f"{ method .__name__ } "
455
477
456
478
if inspect .iscoroutinefunction (method ):
457
479
return self ._decorate_async_function (
458
- method = method , capture_response = capture_response , method_name = method_name
480
+ method = method , capture_response = capture_response , capture_error = True , method_name = method_name
459
481
)
460
482
elif inspect .isgeneratorfunction (method ):
461
483
return self ._decorate_generator_function (
462
- method = method , capture_response = capture_response , method_name = method_name
484
+ method = method , capture_response = capture_response , capture_error = True , method_name = method_name
463
485
)
464
486
elif hasattr (method , "__wrapped__" ) and inspect .isgeneratorfunction (method .__wrapped__ ):
465
487
return self ._decorate_generator_function_with_context_manager (
466
- method = method , capture_response = capture_response , method_name = method_name
488
+ method = method , capture_response = capture_response , capture_error = True , method_name = method_name
467
489
)
468
490
else :
469
491
return self ._decorate_sync_function (
470
- method = method , capture_response = capture_response , method_name = method_name
492
+ method = method , capture_response = capture_response , capture_error = True , method_name = method_name
471
493
)
472
494
473
- def _decorate_async_function (self , method : Callable = None , capture_response : bool = True , method_name : str = None ):
495
+ def _decorate_async_function (
496
+ self ,
497
+ method : Callable = None ,
498
+ capture_response : bool = True ,
499
+ capture_error : bool = True ,
500
+ method_name : str = None ,
501
+ ):
474
502
@functools .wraps (method )
475
503
async def decorate (* args , ** kwargs ):
476
504
async with self .provider .in_subsegment_async (name = f"## { method_name } " ) as subsegment :
477
505
try :
478
506
logger .debug (f"Calling method: { method_name } " )
479
507
response = await method (* args , ** kwargs )
480
508
self ._add_response_as_metadata (
481
- method_name = method_name ,
482
- data = response ,
483
- subsegment = subsegment ,
484
- capture_response = capture_response ,
509
+ method_name = method_name , data = response , subsegment = subsegment , capture_response = capture_response
485
510
)
486
511
except Exception as err :
487
512
logger .exception (f"Exception received from '{ method_name } ' method" )
488
- self ._add_full_exception_as_metadata (method_name = method_name , error = err , subsegment = subsegment )
513
+ self ._add_full_exception_as_metadata (
514
+ method_name = method_name , error = err , subsegment = subsegment , capture_error = capture_error
515
+ )
489
516
raise
490
517
491
518
return response
492
519
493
520
return decorate
494
521
495
522
def _decorate_generator_function (
496
- self , method : Callable = None , capture_response : bool = True , method_name : str = None
523
+ self ,
524
+ method : Callable = None ,
525
+ capture_response : bool = True ,
526
+ capture_error : bool = True ,
527
+ method_name : str = None ,
497
528
):
498
529
@functools .wraps (method )
499
530
def decorate (* args , ** kwargs ):
@@ -506,15 +537,21 @@ def decorate(*args, **kwargs):
506
537
)
507
538
except Exception as err :
508
539
logger .exception (f"Exception received from '{ method_name } ' method" )
509
- self ._add_full_exception_as_metadata (method_name = method_name , error = err , subsegment = subsegment )
540
+ self ._add_full_exception_as_metadata (
541
+ method_name = method_name , error = err , subsegment = subsegment , capture_error = capture_error
542
+ )
510
543
raise
511
544
512
545
return result
513
546
514
547
return decorate
515
548
516
549
def _decorate_generator_function_with_context_manager (
517
- self , method : Callable = None , capture_response : bool = True , method_name : str = None
550
+ self ,
551
+ method : Callable = None ,
552
+ capture_response : bool = True ,
553
+ capture_error : bool = True ,
554
+ method_name : str = None ,
518
555
):
519
556
@functools .wraps (method )
520
557
@contextlib .contextmanager
@@ -530,12 +567,20 @@ def decorate(*args, **kwargs):
530
567
)
531
568
except Exception as err :
532
569
logger .exception (f"Exception received from '{ method_name } ' method" )
533
- self ._add_full_exception_as_metadata (method_name = method_name , error = err , subsegment = subsegment )
570
+ self ._add_full_exception_as_metadata (
571
+ method_name = method_name , error = err , subsegment = subsegment , capture_error = capture_error
572
+ )
534
573
raise
535
574
536
575
return decorate
537
576
538
- def _decorate_sync_function (self , method : Callable = None , capture_response : bool = True , method_name : str = None ):
577
+ def _decorate_sync_function (
578
+ self ,
579
+ method : Callable = None ,
580
+ capture_response : bool = True ,
581
+ capture_error : bool = True ,
582
+ method_name : str = None ,
583
+ ):
539
584
@functools .wraps (method )
540
585
def decorate (* args , ** kwargs ):
541
586
with self .provider .in_subsegment (name = f"## { method_name } " ) as subsegment :
@@ -550,7 +595,9 @@ def decorate(*args, **kwargs):
550
595
)
551
596
except Exception as err :
552
597
logger .exception (f"Exception received from '{ method_name } ' method" )
553
- self ._add_full_exception_as_metadata (method_name = method_name , error = err , subsegment = subsegment )
598
+ self ._add_full_exception_as_metadata (
599
+ method_name = method_name , error = err , subsegment = subsegment , capture_error = capture_error
600
+ )
554
601
raise
555
602
556
603
return response
@@ -583,7 +630,11 @@ def _add_response_as_metadata(
583
630
subsegment .put_metadata (key = f"{ method_name } response" , value = data , namespace = self ._config ["service" ])
584
631
585
632
def _add_full_exception_as_metadata (
586
- self , method_name : str = None , error : Exception = None , subsegment : aws_xray_sdk .core .models .subsegment = None
633
+ self ,
634
+ method_name : str = None ,
635
+ error : Exception = None ,
636
+ subsegment : aws_xray_sdk .core .models .subsegment = None ,
637
+ capture_error : bool = True ,
587
638
):
588
639
"""Add full exception object as metadata for given subsegment
589
640
@@ -595,7 +646,12 @@ def _add_full_exception_as_metadata(
595
646
error to add as subsegment metadata, by default None
596
647
subsegment : aws_xray_sdk.core.models.subsegment, optional
597
648
existing subsegment to add metadata on, by default None
649
+ capture_error : bool, optional
650
+ Do not include error as metadata, by default True
598
651
"""
652
+ if error is None or not capture_error or subsegment is None :
653
+ return
654
+
599
655
subsegment .put_metadata (key = f"{ method_name } error" , value = error , namespace = self ._config ["service" ])
600
656
601
657
@staticmethod
0 commit comments