|
24 | 24 | LOGGER_ATTRIBUTE_PRECONFIGURED,
|
25 | 25 | )
|
26 | 26 | from aws_lambda_powertools.logging.exceptions import (
|
27 |
| - InvalidBufferItem, |
28 | 27 | InvalidLoggerSamplingRateError,
|
29 | 28 | OrphanedChildLoggerError,
|
30 | 29 | )
|
@@ -510,136 +509,6 @@ def decorate(event, context, *args, **kwargs):
|
510 | 509 |
|
511 | 510 | return decorate
|
512 | 511 |
|
513 |
| - def _create_and_flush_log_record(self, log_line: dict) -> None: |
514 |
| - """ |
515 |
| - Create and immediately flush a log record to the configured logger. |
516 |
| -
|
517 |
| - Parameters |
518 |
| - ---------- |
519 |
| - log_line : dict[str, Any] |
520 |
| - Dictionary containing log record details with keys: |
521 |
| - - 'level': Logging level |
522 |
| - - 'filename': Source filename |
523 |
| - - 'line': Line number |
524 |
| - - 'msg': Log message |
525 |
| - - 'function': Source function name |
526 |
| - - 'extra': Additional context |
527 |
| - - 'timestamp': Original log creation time |
528 |
| -
|
529 |
| - Notes |
530 |
| - ----- |
531 |
| - Bypasses standard logging flow by directly creating and handling a log record. |
532 |
| - Preserves original timestamp and source information. |
533 |
| - """ |
534 |
| - record = self._logger.makeRecord( |
535 |
| - name=self.name, |
536 |
| - level=log_line["level"], |
537 |
| - fn=log_line["filename"], |
538 |
| - lno=log_line["line"], |
539 |
| - msg=log_line["msg"], |
540 |
| - args=(), |
541 |
| - exc_info=None, |
542 |
| - func=log_line["function"], |
543 |
| - extra=log_line["extra"], |
544 |
| - ) |
545 |
| - record.created = log_line["timestamp"] |
546 |
| - self._logger.handle(record) |
547 |
| - |
548 |
| - def _add_log_record_to_buffer( |
549 |
| - self, |
550 |
| - level: int, |
551 |
| - msg: object, |
552 |
| - args: object, |
553 |
| - exc_info: logging._ExcInfoType = None, |
554 |
| - stack_info: bool = False, |
555 |
| - extra: Mapping[str, object] | None = None, |
556 |
| - ) -> None: |
557 |
| - """ |
558 |
| - Add log record to buffer with intelligent tracer ID handling. |
559 |
| -
|
560 |
| - Parameters |
561 |
| - ---------- |
562 |
| - level : int |
563 |
| - Logging level of the record. |
564 |
| - msg : object |
565 |
| - Log message to be recorded. |
566 |
| - args : object |
567 |
| - Additional arguments for the log message. |
568 |
| - exc_info : logging._ExcInfoType, optional |
569 |
| - Exception information for the log record. |
570 |
| - stack_info : bool, optional |
571 |
| - Whether to include stack information. |
572 |
| - extra : Mapping[str, object], optional |
573 |
| - Additional contextual information for the log record. |
574 |
| -
|
575 |
| - Raises |
576 |
| - ------ |
577 |
| - InvalidBufferItem |
578 |
| - If the log record cannot be added to the buffer. |
579 |
| -
|
580 |
| - Notes |
581 |
| - ----- |
582 |
| - Handles special first invocation buffering and migration of log records |
583 |
| - between different tracer contexts. |
584 |
| - """ |
585 |
| - # Determine tracer ID, defaulting to first invoke marker |
586 |
| - tracer_id = get_tracer_id() |
587 |
| - |
588 |
| - try: |
589 |
| - if tracer_id: |
590 |
| - log_record: dict[str, Any] = _create_buffer_record(level=level, msg=msg, args=args, extra=extra) |
591 |
| - self._buffer_cache.add(tracer_id, log_record) |
592 |
| - except InvalidBufferItem as exc: |
593 |
| - # Wrap and re-raise buffer addition error as warning |
594 |
| - warnings.warn( |
595 |
| - message=f"Cannot add item to the buffer: {str(exc)}", |
596 |
| - category=PowertoolsUserWarning, |
597 |
| - stacklevel=3, |
598 |
| - ) |
599 |
| - |
600 |
| - def flush_buffer(self) -> None: |
601 |
| - """ |
602 |
| - Flush all buffered log records associated with current execution. |
603 |
| -
|
604 |
| - Notes |
605 |
| - ----- |
606 |
| - Retrieves log records for current trace from buffer |
607 |
| - Immediately processes and logs each record |
608 |
| - Warning if some cache was evicted in that execution |
609 |
| - Clears buffer after complete processing |
610 |
| -
|
611 |
| - Raises |
612 |
| - ------ |
613 |
| - Any exceptions from underlying logging or buffer mechanisms |
614 |
| - will be propagated to caller |
615 |
| - """ |
616 |
| - tracer_id = get_tracer_id() |
617 |
| - |
618 |
| - # Flushing log without a tracer id? Return |
619 |
| - if not tracer_id: |
620 |
| - return |
621 |
| - |
622 |
| - # is buffer empty? return |
623 |
| - buffer = self._buffer_cache.get(tracer_id) |
624 |
| - if not buffer: |
625 |
| - return |
626 |
| - |
627 |
| - # Process log records |
628 |
| - for log_line in buffer: |
629 |
| - self._create_and_flush_log_record(log_line) |
630 |
| - |
631 |
| - # Has items evicted? |
632 |
| - if self._buffer_cache.has_items_evicted(tracer_id): |
633 |
| - warnings.warn( |
634 |
| - message="Some logs are not displayed because they were evicted from the buffer. " |
635 |
| - "Increase buffer size to store more logs in the buffer", |
636 |
| - category=PowertoolsUserWarning, |
637 |
| - stacklevel=2, |
638 |
| - ) |
639 |
| - |
640 |
| - # Clear the entire cache |
641 |
| - self._buffer_cache.clear() |
642 |
| - |
643 | 512 | def debug(
|
644 | 513 | self,
|
645 | 514 | msg: object,
|
@@ -1139,6 +1008,130 @@ def _determine_log_level(self, level: str | int | None) -> str | int:
|
1139 | 1008 | # Powertools log level is set, we use this
|
1140 | 1009 | return powertools_log_level.upper()
|
1141 | 1010 |
|
| 1011 | + # FUNCTIONS for Buffering log |
| 1012 | + |
| 1013 | + def _create_and_flush_log_record(self, log_line: dict) -> None: |
| 1014 | + """ |
| 1015 | + Create and immediately flush a log record to the configured logger. |
| 1016 | +
|
| 1017 | + Parameters |
| 1018 | + ---------- |
| 1019 | + log_line : dict[str, Any] |
| 1020 | + Dictionary containing log record details with keys: |
| 1021 | + - 'level': Logging level |
| 1022 | + - 'filename': Source filename |
| 1023 | + - 'line': Line number |
| 1024 | + - 'msg': Log message |
| 1025 | + - 'function': Source function name |
| 1026 | + - 'extra': Additional context |
| 1027 | + - 'timestamp': Original log creation time |
| 1028 | +
|
| 1029 | + Notes |
| 1030 | + ----- |
| 1031 | + Bypasses standard logging flow by directly creating and handling a log record. |
| 1032 | + Preserves original timestamp and source information. |
| 1033 | + """ |
| 1034 | + record = self._logger.makeRecord( |
| 1035 | + name=self.name, |
| 1036 | + level=log_line["level"], |
| 1037 | + fn=log_line["filename"], |
| 1038 | + lno=log_line["line"], |
| 1039 | + msg=log_line["msg"], |
| 1040 | + args=(), |
| 1041 | + exc_info=None, |
| 1042 | + func=log_line["function"], |
| 1043 | + extra=log_line["extra"], |
| 1044 | + ) |
| 1045 | + record.created = log_line["timestamp"] |
| 1046 | + self._logger.handle(record) |
| 1047 | + |
| 1048 | + def _add_log_record_to_buffer( |
| 1049 | + self, |
| 1050 | + level: int, |
| 1051 | + msg: object, |
| 1052 | + args: object, |
| 1053 | + exc_info: logging._ExcInfoType = None, |
| 1054 | + stack_info: bool = False, |
| 1055 | + extra: Mapping[str, object] | None = None, |
| 1056 | + ) -> None: |
| 1057 | + """ |
| 1058 | + Add log record to buffer with intelligent tracer ID handling. |
| 1059 | +
|
| 1060 | + Parameters |
| 1061 | + ---------- |
| 1062 | + level : int |
| 1063 | + Logging level of the record. |
| 1064 | + msg : object |
| 1065 | + Log message to be recorded. |
| 1066 | + args : object |
| 1067 | + Additional arguments for the log message. |
| 1068 | + exc_info : logging._ExcInfoType, optional |
| 1069 | + Exception information for the log record. |
| 1070 | + stack_info : bool, optional |
| 1071 | + Whether to include stack information. |
| 1072 | + extra : Mapping[str, object], optional |
| 1073 | + Additional contextual information for the log record. |
| 1074 | +
|
| 1075 | + Raises |
| 1076 | + ------ |
| 1077 | + InvalidBufferItem |
| 1078 | + If the log record cannot be added to the buffer. |
| 1079 | +
|
| 1080 | + Notes |
| 1081 | + ----- |
| 1082 | + Handles special first invocation buffering and migration of log records |
| 1083 | + between different tracer contexts. |
| 1084 | + """ |
| 1085 | + # Determine tracer ID, defaulting to first invoke marker |
| 1086 | + tracer_id = get_tracer_id() |
| 1087 | + |
| 1088 | + if tracer_id: |
| 1089 | + log_record: dict[str, Any] = _create_buffer_record(level=level, msg=msg, args=args, extra=extra) |
| 1090 | + self._buffer_cache.add(tracer_id, log_record) |
| 1091 | + |
| 1092 | + def flush_buffer(self) -> None: |
| 1093 | + """ |
| 1094 | + Flush all buffered log records associated with current execution. |
| 1095 | +
|
| 1096 | + Notes |
| 1097 | + ----- |
| 1098 | + Retrieves log records for current trace from buffer |
| 1099 | + Immediately processes and logs each record |
| 1100 | + Warning if some cache was evicted in that execution |
| 1101 | + Clears buffer after complete processing |
| 1102 | +
|
| 1103 | + Raises |
| 1104 | + ------ |
| 1105 | + Any exceptions from underlying logging or buffer mechanisms |
| 1106 | + will be propagated to caller |
| 1107 | + """ |
| 1108 | + tracer_id = get_tracer_id() |
| 1109 | + |
| 1110 | + # Flushing log without a tracer id? Return |
| 1111 | + if not tracer_id: |
| 1112 | + return |
| 1113 | + |
| 1114 | + # is buffer empty? return |
| 1115 | + buffer = self._buffer_cache.get(tracer_id) |
| 1116 | + if not buffer: |
| 1117 | + return |
| 1118 | + |
| 1119 | + # Process log records |
| 1120 | + for log_line in buffer: |
| 1121 | + self._create_and_flush_log_record(log_line) |
| 1122 | + |
| 1123 | + # Has items evicted? |
| 1124 | + if self._buffer_cache.has_items_evicted(tracer_id): |
| 1125 | + warnings.warn( |
| 1126 | + message="Some logs are not displayed because they were evicted from the buffer. " |
| 1127 | + "Increase buffer size to store more logs in the buffer", |
| 1128 | + category=PowertoolsUserWarning, |
| 1129 | + stacklevel=2, |
| 1130 | + ) |
| 1131 | + |
| 1132 | + # Clear the entire cache |
| 1133 | + self._buffer_cache.clear() |
| 1134 | + |
1142 | 1135 |
|
1143 | 1136 | def set_package_logger(
|
1144 | 1137 | level: str | int = logging.DEBUG,
|
|
0 commit comments