|
| 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