|
| 1 | +import contextlib |
1 | 2 | import copy
|
2 | 3 | import functools
|
3 | 4 | import inspect
|
@@ -320,6 +321,39 @@ def lambda_handler(event: dict, context: Any) -> Dict:
|
320 | 321 | booking_id = event.get("booking_id")
|
321 | 322 | asyncio.run(confirm_booking(booking_id=booking_id))
|
322 | 323 |
|
| 324 | + **Custom generator function using capture_method decorator** |
| 325 | +
|
| 326 | + from aws_lambda_powertools import Tracer |
| 327 | + tracer = Tracer(service="booking") |
| 328 | +
|
| 329 | + @tracer.capture_method |
| 330 | + def bookings_generator(booking_id): |
| 331 | + resp = call_to_booking_service() |
| 332 | + yield resp[0] |
| 333 | + yield resp[1] |
| 334 | +
|
| 335 | + def lambda_handler(event: dict, context: Any) -> Dict: |
| 336 | + gen = bookings_generator(booking_id=booking_id) |
| 337 | + result = list(gen) |
| 338 | +
|
| 339 | + **Custom generator context manager using capture_method decorator** |
| 340 | +
|
| 341 | + from aws_lambda_powertools import Tracer |
| 342 | + tracer = Tracer(service="booking") |
| 343 | +
|
| 344 | + @tracer.capture_method |
| 345 | + @contextlib.contextmanager |
| 346 | + def booking_actions(booking_id): |
| 347 | + resp = call_to_booking_service() |
| 348 | + yield "example result" |
| 349 | + cleanup_stuff() |
| 350 | +
|
| 351 | + def lambda_handler(event: dict, context: Any) -> Dict: |
| 352 | + booking_id = event.get("booking_id") |
| 353 | +
|
| 354 | + with booking_actions(booking_id=booking_id) as booking: |
| 355 | + result = booking |
| 356 | +
|
323 | 357 | **Tracing nested async calls**
|
324 | 358 |
|
325 | 359 | from aws_lambda_powertools import Tracer
|
@@ -392,43 +426,93 @@ async def async_tasks():
|
392 | 426 | err
|
393 | 427 | Exception raised by method
|
394 | 428 | """
|
395 |
| - method_name = f"{method.__name__}" |
396 | 429 |
|
397 | 430 | if inspect.iscoroutinefunction(method):
|
| 431 | + decorate = self._decorate_async_function(method=method) |
| 432 | + elif inspect.isgeneratorfunction(method): |
| 433 | + decorate = self._decorate_generator_function(method=method) |
| 434 | + elif hasattr(method, "__wrapped__") and inspect.isgeneratorfunction(method.__wrapped__): |
| 435 | + decorate = self._decorate_generator_function_with_context_manager(method=method) |
| 436 | + else: |
| 437 | + decorate = self._decorate_sync_function(method=method) |
398 | 438 |
|
399 |
| - @functools.wraps(method) |
400 |
| - async def decorate(*args, **kwargs): |
401 |
| - async with self.provider.in_subsegment_async(name=f"## {method_name}") as subsegment: |
402 |
| - try: |
403 |
| - logger.debug(f"Calling method: {method_name}") |
404 |
| - response = await method(*args, **kwargs) |
405 |
| - self._add_response_as_metadata(function_name=method_name, data=response, subsegment=subsegment) |
406 |
| - except Exception as err: |
407 |
| - logger.exception(f"Exception received from '{method_name}' method") |
408 |
| - self._add_full_exception_as_metadata( |
409 |
| - function_name=method_name, error=err, subsegment=subsegment |
410 |
| - ) |
411 |
| - raise |
412 |
| - |
413 |
| - return response |
| 439 | + return decorate |
414 | 440 |
|
415 |
| - else: |
| 441 | + def _decorate_async_function(self, method: Callable = None): |
| 442 | + method_name = f"{method.__name__}" |
| 443 | + |
| 444 | + @functools.wraps(method) |
| 445 | + async def decorate(*args, **kwargs): |
| 446 | + async with self.provider.in_subsegment_async(name=f"## {method_name}") as subsegment: |
| 447 | + try: |
| 448 | + logger.debug(f"Calling method: {method_name}") |
| 449 | + response = await method(*args, **kwargs) |
| 450 | + self._add_response_as_metadata(function_name=method_name, data=response, subsegment=subsegment) |
| 451 | + except Exception as err: |
| 452 | + logger.exception(f"Exception received from '{method_name}' method") |
| 453 | + self._add_full_exception_as_metadata(function_name=method_name, error=err, subsegment=subsegment) |
| 454 | + raise |
416 | 455 |
|
417 |
| - @functools.wraps(method) |
418 |
| - def decorate(*args, **kwargs): |
419 |
| - with self.provider.in_subsegment(name=f"## {method_name}") as subsegment: |
420 |
| - try: |
421 |
| - logger.debug(f"Calling method: {method_name}") |
422 |
| - response = method(*args, **kwargs) |
423 |
| - self._add_response_as_metadata(function_name=method_name, data=response, subsegment=subsegment) |
424 |
| - except Exception as err: |
425 |
| - logger.exception(f"Exception received from '{method_name}' method") |
426 |
| - self._add_full_exception_as_metadata( |
427 |
| - function_name=method_name, error=err, subsegment=subsegment |
428 |
| - ) |
429 |
| - raise |
430 |
| - |
431 |
| - return response |
| 456 | + return response |
| 457 | + |
| 458 | + return decorate |
| 459 | + |
| 460 | + def _decorate_generator_function(self, method: Callable = None): |
| 461 | + method_name = f"{method.__name__}" |
| 462 | + |
| 463 | + @functools.wraps(method) |
| 464 | + def decorate(*args, **kwargs): |
| 465 | + with self.provider.in_subsegment(name=f"## {method_name}") as subsegment: |
| 466 | + try: |
| 467 | + logger.debug(f"Calling method: {method_name}") |
| 468 | + result = yield from method(*args, **kwargs) |
| 469 | + self._add_response_as_metadata(function_name=method_name, data=result, subsegment=subsegment) |
| 470 | + except Exception as err: |
| 471 | + logger.exception(f"Exception received from '{method_name}' method") |
| 472 | + self._add_full_exception_as_metadata(function_name=method_name, error=err, subsegment=subsegment) |
| 473 | + raise |
| 474 | + |
| 475 | + return result |
| 476 | + |
| 477 | + return decorate |
| 478 | + |
| 479 | + def _decorate_generator_function_with_context_manager(self, method: Callable = None): |
| 480 | + method_name = f"{method.__name__}" |
| 481 | + |
| 482 | + @functools.wraps(method) |
| 483 | + @contextlib.contextmanager |
| 484 | + def decorate(*args, **kwargs): |
| 485 | + with self.provider.in_subsegment(name=f"## {method_name}") as subsegment: |
| 486 | + try: |
| 487 | + logger.debug(f"Calling method: {method_name}") |
| 488 | + with method(*args, **kwargs) as return_val: |
| 489 | + result = return_val |
| 490 | + self._add_response_as_metadata(function_name=method_name, data=result, subsegment=subsegment) |
| 491 | + except Exception as err: |
| 492 | + logger.exception(f"Exception received from '{method_name}' method") |
| 493 | + self._add_full_exception_as_metadata(function_name=method_name, error=err, subsegment=subsegment) |
| 494 | + raise |
| 495 | + |
| 496 | + yield result |
| 497 | + |
| 498 | + return decorate |
| 499 | + |
| 500 | + def _decorate_sync_function(self, method: Callable = None): |
| 501 | + method_name = f"{method.__name__}" |
| 502 | + |
| 503 | + @functools.wraps(method) |
| 504 | + def decorate(*args, **kwargs): |
| 505 | + with self.provider.in_subsegment(name=f"## {method_name}") as subsegment: |
| 506 | + try: |
| 507 | + logger.debug(f"Calling method: {method_name}") |
| 508 | + response = method(*args, **kwargs) |
| 509 | + self._add_response_as_metadata(function_name=method_name, data=response, subsegment=subsegment) |
| 510 | + except Exception as err: |
| 511 | + logger.exception(f"Exception received from '{method_name}' method") |
| 512 | + self._add_full_exception_as_metadata(function_name=method_name, error=err, subsegment=subsegment) |
| 513 | + raise |
| 514 | + |
| 515 | + return response |
432 | 516 |
|
433 | 517 | return decorate
|
434 | 518 |
|
|
0 commit comments