Skip to content

Commit 54d8967

Browse files
authored
feat: toggle to disable log deduplication locally for pytest live log #262 (#268)
* feat: add flag to disable log deduplication filter #262 * docs: add new env var, explicit warning on its use Signed-off-by: heitorlessa <[email protected]> * chore: address Nicolas' feedback on comment example
1 parent 1d0ee0e commit 54d8967

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-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+
# Example: `Logger(service="order")`, where service is Order
180+
# It'll reject all loggers starting with `order` e.g. 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

docs/content/core/logger.mdx

+12
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,18 @@ def test_lambda_handler(lambda_handler, lambda_context):
439439
lambda_handler(test_event, lambda_context) # this will now have a Context object populated
440440
```
441441

442+
### pytest live log feature
443+
444+
Pytest Live Log feature duplicates emitted log messages in order to style log statements according to their levels, for this to work use `POWERTOOLS_LOG_DEDUPLICATION_DISABLED` env var.
445+
446+
```bash:title=pytest_live_log.sh
447+
POWERTOOLS_LOG_DEDUPLICATION_DISABLED="1" pytest -o log_cli=1
448+
```
449+
450+
<Note type="warning">
451+
This feature should be used with care, as it explicitly disables our ability to filter propagated messages to the root logger (if configured).
452+
</Note><br/>
453+
442454
## FAQ
443455

444456
**How can I enable boto3 and botocore library logging?**

docs/content/index.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ Environment variable | Description | Utility | Default
138138
**POWERTOOLS_TRACE_MIDDLEWARES** | Creates sub-segment for each custom middleware | [Middleware factory](./utilities/middleware_factory) | `false`
139139
**POWERTOOLS_LOGGER_LOG_EVENT** | Logs incoming event | [Logging](./core/logger) | `false`
140140
**POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logging](./core/logger) | `0`
141+
**POWERTOOLS_LOG_DEDUPLICATION_DISABLED** | Disables log deduplication filter protection to use Pytest Live Log feature | [Logging](./core/logger) | `false`
141142
**LOG_LEVEL** | Sets logging level | [Logging](./core/logger) | `INFO`
142143

143144
## Debug mode

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)