Skip to content

Commit 55ad6fa

Browse files
committed
feat: add flag to disable log deduplication filter #262
1 parent 454d669 commit 55ad6fa

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

aws_lambda_powertools/logging/logger.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ def __init__(
129129
self.sampling_rate = resolve_env_var_choice(
130130
choice=sampling_rate, env=os.getenv(constants.LOGGER_LOG_SAMPLING_RATE, 0.0)
131131
)
132+
self._is_deduplication_disabled = resolve_truthy_env_var_choice(
133+
env=os.getenv(constants.LOGGER_LOG_DEDUPLICATION_ENV, "false")
134+
)
132135
self.log_level = self._get_log_level(level)
133136
self.child = child
134137
self._handler = logging.StreamHandler(stream) if stream is not None else logging.StreamHandler(sys.stdout)
135138
self._default_log_keys = {"service": self.service, "sampling_rate": self.sampling_rate}
136139
self._logger = self._get_logger()
137-
138140
self._init_logger(**kwargs)
139141

140142
def __getattr__(self, name):
@@ -167,12 +169,16 @@ def _init_logger(self, **kwargs):
167169
self._logger.addHandler(self._handler)
168170
self.structure_logs(**kwargs)
169171

170-
logger.debug("Adding filter in root logger to suppress child logger records to bubble up")
171-
for handler in logging.root.handlers:
172-
# It'll add a filter to suppress any child logger from self.service
173-
# Where service is Order, it'll reject parent logger Order,
174-
# and child loggers such as Order.checkout, Order.shared
175-
handler.addFilter(SuppressFilter(self.service))
172+
# Pytest Live Log feature duplicates log records for colored output
173+
# but we explicitly add a filter for log deduplication.
174+
# This flag disables this protection when you explicit want logs to be duplicated (#262)
175+
if not self._is_deduplication_disabled:
176+
logger.debug("Adding filter in root logger to suppress child logger records to bubble up")
177+
for handler in logging.root.handlers:
178+
# It'll add a filter to suppress any child logger from self.service
179+
# Where service is Order, it'll reject parent logger Order,
180+
# and child loggers such as Order.checkout, Order.shared
181+
handler.addFilter(SuppressFilter(self.service))
176182

177183
# as per bug in #249, we should not be pre-configuring an existing logger
178184
# therefore we set a custom attribute in the Logger that will be returned

aws_lambda_powertools/shared/constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
LOGGER_LOG_SAMPLING_RATE: str = "POWERTOOLS_LOGGER_SAMPLE_RATE"
66
LOGGER_LOG_EVENT_ENV: str = "POWERTOOLS_LOGGER_LOG_EVENT"
7+
LOGGER_LOG_DEDUPLICATION_ENV: str = "POWERTOOLS_LOG_DEDUPLICATION_DISABLED"
78

89
MIDDLEWARE_FACTORY_TRACE_ENV: str = "POWERTOOLS_TRACE_MIDDLEWARES"
910

tests/functional/test_logger.py

+22
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from aws_lambda_powertools import Logger, Tracer
1212
from aws_lambda_powertools.logging.exceptions import InvalidLoggerSamplingRateError
1313
from aws_lambda_powertools.logging.logger import set_package_logger
14+
from aws_lambda_powertools.shared import constants
1415

1516

1617
@pytest.fixture
@@ -376,6 +377,7 @@ def test_logger_do_not_log_twice_when_root_logger_is_setup(stdout, service_name)
376377
child_logger = Logger(service=service_name, child=True, stream=stdout)
377378
logger.info("PARENT")
378379
child_logger.info("CHILD")
380+
root_logger.info("ROOT")
379381

380382
# THEN it should only contain only two log entries
381383
# since child's log records propagated to root logger should be rejected
@@ -400,3 +402,23 @@ def test_logger_extra_kwargs(stdout, service_name):
400402

401403
# THEN second log should not have request_id in the root structure
402404
assert "request_id" not in no_extra_fields_log
405+
406+
407+
def test_logger_log_twice_when_log_filter_isnt_present_and_root_logger_is_setup(monkeypatch, stdout, service_name):
408+
# GIVEN Lambda configures the root logger with a handler
409+
root_logger = logging.getLogger()
410+
root_logger.addHandler(logging.StreamHandler(stream=stdout))
411+
412+
# WHEN we create a new Logger and child Logger
413+
# and log deduplication filter for child messages are disabled
414+
# see #262 for more details on why this is needed for Pytest Live Log feature
415+
monkeypatch.setenv(constants.LOGGER_LOG_DEDUPLICATION_ENV, "true")
416+
logger = Logger(service=service_name, stream=stdout)
417+
child_logger = Logger(service=service_name, child=True, stream=stdout)
418+
logger.info("PARENT")
419+
child_logger.info("CHILD")
420+
421+
# THEN it should only contain only two log entries
422+
# since child's log records propagated to root logger should be rejected
423+
logs = list(stdout.getvalue().strip().split("\n"))
424+
assert len(logs) == 4

0 commit comments

Comments
 (0)