Skip to content

Commit 0c8cb3b

Browse files
Adding decorator
1 parent 7d98138 commit 0c8cb3b

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

aws_lambda_powertools/logging/logger.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ def inject_lambda_context(
400400
log_event: bool | None = None,
401401
correlation_id_path: str | None = None,
402402
clear_state: bool | None = False,
403+
flush_buffer_on_uncaught_error: bool = False,
403404
) -> AnyCallableT: ...
404405

405406
@overload
@@ -409,6 +410,7 @@ def inject_lambda_context(
409410
log_event: bool | None = None,
410411
correlation_id_path: str | None = None,
411412
clear_state: bool | None = False,
413+
flush_buffer_on_uncaught_error: bool = False,
412414
) -> Callable[[AnyCallableT], AnyCallableT]: ...
413415

414416
def inject_lambda_context(
@@ -417,6 +419,7 @@ def inject_lambda_context(
417419
log_event: bool | None = None,
418420
correlation_id_path: str | None = None,
419421
clear_state: bool | None = False,
422+
flush_buffer_on_uncaught_error: bool = False,
420423
) -> Any:
421424
"""Decorator to capture Lambda contextual info and inject into logger
422425
@@ -473,6 +476,7 @@ def handler(event, context):
473476
log_event=log_event,
474477
correlation_id_path=correlation_id_path,
475478
clear_state=clear_state,
479+
flush_buffer_on_uncaught_error=flush_buffer_on_uncaught_error,
476480
)
477481

478482
log_event = resolve_truthy_env_var_choice(
@@ -505,7 +509,18 @@ def decorate(event, context, *args, **kwargs):
505509
if self.sampling_rate and not cold_start:
506510
self.refresh_sample_rate_calculation()
507511

508-
return lambda_handler(event, context, *args, **kwargs)
512+
try:
513+
# Execute the Lambda handler with provided event and context
514+
return lambda_handler(event, context, *args, **kwargs)
515+
except:
516+
# Re-raise any exceptions that occur during handler execution
517+
raise
518+
finally:
519+
# Flush the log buffer if configured to do so on uncaught errors
520+
# Ensures logging state is cleaned up even if an exception is raised
521+
if flush_buffer_on_uncaught_error:
522+
logger.debug("An error happened, flushing the buffer")
523+
self.flush_buffer()
509524

510525
return decorate
511526

tests/functional/logger/required_dependencies/test_powertools_logger_buffer.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,51 @@ def test_logger_buffer_log_output_for_levels_above_minimum(log_level, stdout, se
273273
log = capture_multiple_logging_statements_output(stdout)
274274
assert len(log) == 1
275275
assert log[0]["message"] == msg
276+
277+
278+
def test_logger_buffer_flush_on_uncaught_exception(stdout, service_name, monkeypatch, lambda_context):
279+
monkeypatch.setenv(constants.XRAY_TRACE_ID_ENV, "1234")
280+
281+
# GIVEN: A logger configured with a large buffer and error-based flushing
282+
logger_buffer_config = LoggerBufferConfig(max_size=10240, minimum_log_level="DEBUG", flush_on_error=True)
283+
logger = Logger(level="DEBUG", service=service_name, stream=stdout, logger_buffer=logger_buffer_config)
284+
285+
@logger.inject_lambda_context(flush_buffer_on_uncaught_error=True)
286+
def handler(event, context):
287+
# Log messages that should be flushed when an exception occurs
288+
logger.debug("this log line will be flushed after error - 1")
289+
logger.debug("this log line will be flushed after error - 2")
290+
raise ValueError("Test error")
291+
292+
# WHEN Invoking the handler and expecting a ValueError
293+
with pytest.raises(ValueError):
294+
handler({}, lambda_context)
295+
296+
# THEN Verify that buffered log messages are flushed before the exception
297+
log = capture_multiple_logging_statements_output(stdout)
298+
assert len(log) == 2, "Expected two log messages to be flushed"
299+
assert log[0]["message"] == "this log line will be flushed after error - 1"
300+
assert log[1]["message"] == "this log line will be flushed after error - 2"
301+
302+
303+
def test_logger_buffer_not_flush_on_uncaught_exception(stdout, service_name, monkeypatch, lambda_context):
304+
monkeypatch.setenv(constants.XRAY_TRACE_ID_ENV, "1234")
305+
306+
# GIVEN: A logger configured with a large buffer and error-based flushing
307+
logger_buffer_config = LoggerBufferConfig(max_size=10240, minimum_log_level="DEBUG", flush_on_error=True)
308+
logger = Logger(level="DEBUG", service=service_name, stream=stdout, logger_buffer=logger_buffer_config)
309+
310+
@logger.inject_lambda_context(flush_buffer_on_uncaught_error=False)
311+
def handler(event, context):
312+
# Log messages that should be flushed when an exception occurs
313+
logger.debug("this log line will be flushed after error - 1")
314+
logger.debug("this log line will be flushed after error - 2")
315+
raise ValueError("Test error")
316+
317+
# WHEN Invoking the handler and expecting a ValueError
318+
with pytest.raises(ValueError):
319+
handler({}, lambda_context)
320+
321+
# THEN Verify that buffered log messages are flushed before the exception
322+
log = capture_multiple_logging_statements_output(stdout)
323+
assert len(log) == 0

0 commit comments

Comments
 (0)