Skip to content

Commit 7d98138

Browse files
Adding more coverage + documentation
1 parent f7eeb2e commit 7d98138

File tree

4 files changed

+214
-179
lines changed

4 files changed

+214
-179
lines changed

aws_lambda_powertools/logging/buffer/cache.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ def add(self, key: str, item: Any) -> None:
137137
item_size = len(str(item))
138138
if item_size > self.max_size_bytes:
139139
warnings.warn(
140+
message=f"Cannot add item to the buffer "
140141
f"Item size {item_size} bytes exceeds total cache size {self.max_size_bytes} bytes",
141-
PowertoolsUserWarning,
142+
category=PowertoolsUserWarning,
142143
stacklevel=2,
143144
)
144145
return

aws_lambda_powertools/logging/exceptions.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,3 @@ class OrphanedChildLoggerError(Exception):
1212
"""
1313

1414
pass
15-
16-
17-
class InvalidBufferItem(Exception):
18-
"""
19-
Raised when a buffer item exceeds the maximum allowed buffer size.
20-
"""
21-
22-
pass

aws_lambda_powertools/logging/logger.py

Lines changed: 124 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
LOGGER_ATTRIBUTE_PRECONFIGURED,
2525
)
2626
from aws_lambda_powertools.logging.exceptions import (
27-
InvalidBufferItem,
2827
InvalidLoggerSamplingRateError,
2928
OrphanedChildLoggerError,
3029
)
@@ -510,136 +509,6 @@ def decorate(event, context, *args, **kwargs):
510509

511510
return decorate
512511

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-
643512
def debug(
644513
self,
645514
msg: object,
@@ -1139,6 +1008,130 @@ def _determine_log_level(self, level: str | int | None) -> str | int:
11391008
# Powertools log level is set, we use this
11401009
return powertools_log_level.upper()
11411010

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

11431136
def set_package_logger(
11441137
level: str | int = logging.DEBUG,

0 commit comments

Comments
 (0)