From 252445d1866a24936ca6399a79da8ff40ca35e06 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 25 Jul 2023 14:39:50 +0200 Subject: [PATCH 1/7] fix(parameters): make cache aware of single vs multiple calls Signed-off-by: heitorlessa --- aws_lambda_powertools/utilities/parameters/base.py | 2 +- aws_lambda_powertools/utilities/parameters/types.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aws_lambda_powertools/utilities/parameters/base.py b/aws_lambda_powertools/utilities/parameters/base.py index 710634636d..411a2520ae 100644 --- a/aws_lambda_powertools/utilities/parameters/base.py +++ b/aws_lambda_powertools/utilities/parameters/base.py @@ -27,7 +27,7 @@ from aws_lambda_powertools.shared import constants, user_agent from aws_lambda_powertools.shared.functions import resolve_max_age -from aws_lambda_powertools.utilities.parameters.types import TransformOptions +from aws_lambda_powertools.utilities.parameters.types import RecursiveOptions, TransformOptions from .exceptions import GetParameterError, TransformParameterError diff --git a/aws_lambda_powertools/utilities/parameters/types.py b/aws_lambda_powertools/utilities/parameters/types.py index faa06cee89..a916f1a344 100644 --- a/aws_lambda_powertools/utilities/parameters/types.py +++ b/aws_lambda_powertools/utilities/parameters/types.py @@ -1,3 +1,4 @@ from aws_lambda_powertools.shared.types import Literal TransformOptions = Literal["json", "binary", "auto", None] +RecursiveOptions = Literal[True, False] From 4140d3169b02c3408c142e6fad6ddfd511db278e Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 25 Jul 2023 15:16:51 +0200 Subject: [PATCH 2/7] chore: cleanup, add test for single and nested Signed-off-by: heitorlessa --- aws_lambda_powertools/utilities/parameters/base.py | 2 +- aws_lambda_powertools/utilities/parameters/types.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/aws_lambda_powertools/utilities/parameters/base.py b/aws_lambda_powertools/utilities/parameters/base.py index 411a2520ae..710634636d 100644 --- a/aws_lambda_powertools/utilities/parameters/base.py +++ b/aws_lambda_powertools/utilities/parameters/base.py @@ -27,7 +27,7 @@ from aws_lambda_powertools.shared import constants, user_agent from aws_lambda_powertools.shared.functions import resolve_max_age -from aws_lambda_powertools.utilities.parameters.types import RecursiveOptions, TransformOptions +from aws_lambda_powertools.utilities.parameters.types import TransformOptions from .exceptions import GetParameterError, TransformParameterError diff --git a/aws_lambda_powertools/utilities/parameters/types.py b/aws_lambda_powertools/utilities/parameters/types.py index a916f1a344..faa06cee89 100644 --- a/aws_lambda_powertools/utilities/parameters/types.py +++ b/aws_lambda_powertools/utilities/parameters/types.py @@ -1,4 +1,3 @@ from aws_lambda_powertools.shared.types import Literal TransformOptions = Literal["json", "binary", "auto", None] -RecursiveOptions = Literal[True, False] From 9198e5c8b6ad9bb4ced80813980879a33d31fccb Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 21 Nov 2023 09:42:14 +0100 Subject: [PATCH 3/7] feat(logger): add logFilter method --- aws_lambda_powertools/logging/logger.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index dc626471f3..172b04b2cc 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -67,7 +67,7 @@ def _is_cold_start() -> bool: return cold_start -class Logger: +class Logger(logging.Logger): """Creates and setups a logger to format statements in JSON. Includes service name and any additional key=value into logs @@ -683,6 +683,9 @@ def setLevel(self, level: Union[str, int, None]) -> None: def addHandler(self, handler: logging.Handler) -> None: return self._logger.addHandler(handler) + def addFilter(self, filter: logging._FilterType) -> None: # noqa: A002 # filter built-in usage + return self._logger.addFilter(filter) + @property def registered_handler(self) -> logging.Handler: """Convenience property to access the first logger handler""" From 2e1dfb60e6ee938e3c2401c9646e86f38b61ee91 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 21 Nov 2023 09:54:47 +0100 Subject: [PATCH 4/7] chore(logger): test addFilter --- tests/functional/test_logger.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index 4a34da946b..1811a1c00d 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -5,6 +5,7 @@ import logging import random import re +import secrets import string import sys import warnings @@ -1076,3 +1077,23 @@ def test_log_level_advanced_logging_controler_warning_different_log_levels_using # THEN Logger must be INFO because it takes precedence over POWERTOOLS_LOG_LEVEL assert logger.log_level == logging.INFO + + +def test_logger_add_filter(stdout, service_name): + # GIVEN a Logger with a custom logging filter + class MyFilter(logging.Filter): + def filter(self, record): + if getattr(record, "api_key", None): + record.api_key = "REDACTED" + + return True + + logger = Logger(service=service_name, stream=stdout) + logger.addFilter(MyFilter()) + + # WHEN a new log statement is issued + logger.info("log", api_key=secrets.token_urlsafe()) + + # THEN logging filter should be called and mutate the log record accordingly + log = capture_logging_output(stdout) + assert log["api_key"] == "REDACTED" From 0d227b7b485b22b5654f0cb6af5815060a9fbec7 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 21 Nov 2023 10:24:40 +0100 Subject: [PATCH 5/7] feat(logger): add removeFilter --- aws_lambda_powertools/logging/logger.py | 5 ++++- tests/functional/test_logger.py | 17 +++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index 172b04b2cc..7ad63a1c5f 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -67,7 +67,7 @@ def _is_cold_start() -> bool: return cold_start -class Logger(logging.Logger): +class Logger: """Creates and setups a logger to format statements in JSON. Includes service name and any additional key=value into logs @@ -686,6 +686,9 @@ def addHandler(self, handler: logging.Handler) -> None: def addFilter(self, filter: logging._FilterType) -> None: # noqa: A002 # filter built-in usage return self._logger.addFilter(filter) + def removeFilter(self, filter: logging._FilterType) -> None: # noqa: A002 # filter built-in usage + return self._logger.removeFilter(filter) + @property def registered_handler(self) -> logging.Handler: """Convenience property to access the first logger handler""" diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index 1811a1c00d..e868d42b21 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -1079,21 +1079,26 @@ def test_log_level_advanced_logging_controler_warning_different_log_levels_using assert logger.log_level == logging.INFO -def test_logger_add_filter(stdout, service_name): +def test_logger_add_remove_filter(stdout, service_name): # GIVEN a Logger with a custom logging filter - class MyFilter(logging.Filter): + class ApiKeyFilter(logging.Filter): def filter(self, record): if getattr(record, "api_key", None): record.api_key = "REDACTED" return True + redact_api_key_filter = ApiKeyFilter() logger = Logger(service=service_name, stream=stdout) - logger.addFilter(MyFilter()) + logger.addFilter(redact_api_key_filter) # WHEN a new log statement is issued - logger.info("log", api_key=secrets.token_urlsafe()) + # AND another log statement is issued after filter is removed + logger.info("filtered", api_key=secrets.token_urlsafe()) + logger.removeFilter(redact_api_key_filter) + logger.info("unfiltered", api_key=secrets.token_urlsafe()) # THEN logging filter should be called and mutate the log record accordingly - log = capture_logging_output(stdout) - assert log["api_key"] == "REDACTED" + log = capture_multiple_logging_statements_output(stdout) + assert log[0]["api_key"] == "REDACTED" + assert log[1]["api_key"] != "REDACTED" From 59e3d72233672fa6d70c5126fe622124dce4a691 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 21 Nov 2023 10:29:37 +0100 Subject: [PATCH 6/7] chore: ignore sonar false positive --- tests/functional/test_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index e868d42b21..b7eeed779c 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -1081,7 +1081,7 @@ def test_log_level_advanced_logging_controler_warning_different_log_levels_using def test_logger_add_remove_filter(stdout, service_name): # GIVEN a Logger with a custom logging filter - class ApiKeyFilter(logging.Filter): + class ApiKeyFilter(logging.Filter): # NOSONAR # need filter to test actual impl. def filter(self, record): if getattr(record, "api_key", None): record.api_key = "REDACTED" From 62b4afdf91dba935c49c6b945f99d52bfb45fc91 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 21 Nov 2023 10:35:32 +0100 Subject: [PATCH 7/7] chore: minor typing correction that cpython didn't have --- aws_lambda_powertools/logging/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index 7ad63a1c5f..b147824e2c 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -507,7 +507,7 @@ def exception( self, msg: object, *args, - exc_info=True, + exc_info: logging._ExcInfoType = True, stack_info: bool = False, stacklevel: int = 2, extra: Optional[Mapping[str, object]] = None,