From eee0acc2f9a93da803339df6701230ba50926f4d Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Wed, 9 Mar 2022 18:05:53 +0100 Subject: [PATCH 01/16] docs(layer): update to 1.25.3 --- docs/index.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/index.md b/docs/index.md index ca850823ad4..ffe0dc38bfd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,7 +24,7 @@ Core utilities such as Tracing, Logging, Metrics, and Event Handler will be avai Powertools is available in the following formats: -* **Lambda Layer**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:**](#){: .copyMe} +* **Lambda Layer**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:**](#){: .copyMe} * **PyPi**: **`pip install aws-lambda-powertools`** ### Lambda Layer @@ -37,23 +37,23 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: | Region | Layer ARN |--------------------------- | --------------------------- - | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} - | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPython:11 :clipboard:](#){: .copyMe} + | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} + | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPython:13 :clipboard:](#){: .copyMe} === "SAM" @@ -62,7 +62,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: Type: AWS::Serverless::Function Properties: Layers: - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:11 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:13 ``` === "Serverless framework" @@ -72,7 +72,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: hello: handler: lambda_function.lambda_handler layers: - - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPython:11 + - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPython:13 ``` === "CDK" @@ -88,7 +88,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn( self, id="lambda-powertools", - layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPython:11" + layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPython:13" ) aws_lambda.Function(self, 'sample-app-lambda', @@ -137,7 +137,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: role = aws_iam_role.iam_for_lambda.arn handler = "index.test" runtime = "python3.9" - layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:11"] + layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:13"] source_code_hash = filebase64sha256("lambda_function_payload.zip") } @@ -156,7 +156,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: ? Do you want to configure advanced settings? Yes ... ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:11 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:13 ❯ amplify push -y @@ -167,7 +167,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: - Name: ? Which setting do you want to update? Lambda layers configuration ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:11 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:13 ? Do you want to edit the local lambda function now? No ``` @@ -175,7 +175,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: Change {region} to your AWS region, e.g. `eu-west-1` ```bash title="AWS CLI" - aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:11 --region {region} + aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:13 --region {region} ``` The pre-signed URL to download this Lambda Layer will be within `Location` key. From 51ee897abb3197acd24a44e061a702f130f6e1bb Mon Sep 17 00:00:00 2001 From: Michal Ploski Date: Thu, 10 Mar 2022 14:54:55 +0100 Subject: [PATCH 02/16] Ensure external loggers doesnt propagate logs --- aws_lambda_powertools/logging/utils.py | 9 +++++---- tests/functional/test_logger_utils.py | 28 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/aws_lambda_powertools/logging/utils.py b/aws_lambda_powertools/logging/utils.py index 41c2f2927b0..48d2a6db9e8 100644 --- a/aws_lambda_powertools/logging/utils.py +++ b/aws_lambda_powertools/logging/utils.py @@ -24,7 +24,7 @@ def copy_config_to_registered_loggers( exclude : Optional[Set[str]], optional List of logger names to exclude, by default None """ - + package_logger = logging.getLogger("aws_lambda_powertools") level = log_level or source_logger.level # Assumptions: Only take parent loggers not children (dot notation rule) @@ -34,11 +34,11 @@ def copy_config_to_registered_loggers( # 3. Include and exclude set? Add Logger if it’s in include and not in exclude # 4. Only exclude set? Ignore Logger in the excluding list - # Exclude source logger by default + # Exclude source and powertools package logger by default if exclude: - exclude.add(source_logger.name) + exclude.update(source_logger.name, package_logger.name) else: - exclude = {source_logger.name} + exclude = {source_logger.name, package_logger.name} # Prepare loggers set if include: @@ -75,6 +75,7 @@ def _find_registered_loggers( def _configure_logger(source_logger: Logger, logger: logging.Logger, level: Union[int, str]) -> None: logger.handlers = [] logger.setLevel(level) + logger.propagate = False source_logger.debug(f"Logger {logger} reconfigured to use logging level {level}") for source_handler in source_logger.handlers: logger.addHandler(source_handler) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index 6d048b22dd6..cd431d52543 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -184,7 +184,7 @@ def test_copy_config_to_ext_loggers_custom_log_level(stdout, logger, log_level): assert log["level"] == log_level.WARNING.name -def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, logger, log_level): +def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, log_level): # GIVEN powertools logger initialized powertools_logger = Logger(service=service_name(), level=log_level.INFO.value, stream=stdout) @@ -193,3 +193,29 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, logger, # THEN append_keys should not raise an exception powertools_logger.append_keys(key="value") + + +def test_copy_config_to_ext_loggers_no_duplicate_logs(stdout, logger, log_level): + # GIVEN an root logger, external logger and powertools logger initialized + + root_logger = logging.getLogger() + handler = logging.StreamHandler(stdout) + formatter = logging.Formatter('{"message": "%(message)s"}') + handler.setFormatter(formatter) + root_logger.handlers = [handler] + + logger = logger() + + powertools_logger = Logger(service=service_name(), level=log_level.CRITICAL.value, stream=stdout) + level = log_level.WARNING.name + + # WHEN configuration copied from powertools logger + # AND external logger used with custom log_level + utils.copy_config_to_registered_loggers(source_logger=powertools_logger, include={logger.name}, log_level=level) + msg = "test message4" + logger.warning(msg) + + # THEN no root logger logs AND log is not duplicated + logs = capture_multiple_logging_statements_output(stdout) + assert not {"message": msg} in logs + assert sum(msg in log.values() for log in logs) == 1 From 565d0a5897a7418aed61993028c9d8f7827fe89d Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Thu, 10 Mar 2022 18:08:57 +0100 Subject: [PATCH 03/16] docs(contributing): operational excellence pause --- CONTRIBUTING.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 060726ec11a..563372a53d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,11 +15,13 @@ reported the issue. Please try to include as much information as you can. ## Contributing via Pull Requests -Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: +We are temporarily de-prioritizing and pausing external contributions until end of July 2022. You can read more here: https://github.com/awslabs/aws-lambda-powertools-python/issues/1076 + + ### Dev setup From 3d3bfc81bbdc49cedea3900aaa31f0d2fa27181d Mon Sep 17 00:00:00 2001 From: Michal Ploski Date: Mon, 14 Mar 2022 16:15:18 +0100 Subject: [PATCH 04/16] Add child loggers validation test --- tests/functional/test_logger_utils.py | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index cd431d52543..e28b3850855 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -6,6 +6,7 @@ from enum import Enum import pytest +from pytest_mock import MockerFixture from aws_lambda_powertools import Logger from aws_lambda_powertools.logging import formatter, utils @@ -195,6 +196,64 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, log_lev powertools_logger.append_keys(key="value") +def test_copy_config_to_ext_loggers_child_loggers_append_before_work(stdout): + # GIVEN powertools logger AND child initialized AND + + # GIVEN Loggers are initialized + # create child logger before parent to mimick + # importing logger from another module/file + # as loggers are created in global scope + service = service_name() + child = Logger(stream=stdout, service=service, child=True) + parent = Logger(stream=stdout, service=service) + + # WHEN a child Logger adds an additional key AND parent logger adds additional key + child.structure_logs(append=True, customer_id="value") + parent.structure_logs(append=True, user_id="value") + # WHEN configuration copied from powertools logger + # AND powertools logger and child logger used + utils.copy_config_to_registered_loggers(source_logger=parent) + parent.warning("Logger message") + child.warning("Child logger message") + + # THEN payment_id key added to both powertools logger and child logger + parent_log, child_log = capture_multiple_logging_statements_output(stdout) + assert "customer_id" in parent_log + assert "customer_id" in child_log + assert "user_id" in parent_log + assert "user_id" in child_log + assert child.parent.name == service + + +def test_copy_config_to_ext_loggers_child_loggers_append_after_works(stdout): + # GIVEN powertools logger AND child initialized AND + + # GIVEN Loggers are initialized + # create child logger before parent to mimick + # importing logger from another module/file + # as loggers are created in global scope + service = service_name() + child = Logger(stream=stdout, service=service, child=True) + parent = Logger(stream=stdout, service=service) + + # WHEN a child Logger adds an additional key AND parent logger adds additional key + # AND configuration copied from powertools logger + # AND powertools logger and child logger used + utils.copy_config_to_registered_loggers(source_logger=parent) + child.structure_logs(append=True, customer_id="value") + parent.structure_logs(append=True, user_id="value") + parent.warning("Logger message") + child.warning("Child logger message") + + # THEN payment_id key added to both powertools logger and child logger + parent_log, child_log = capture_multiple_logging_statements_output(stdout) + assert "customer_id" in parent_log + assert "customer_id" in child_log + assert "user_id" in parent_log + assert "user_id" in child_log + assert child.parent.name == service + + def test_copy_config_to_ext_loggers_no_duplicate_logs(stdout, logger, log_level): # GIVEN an root logger, external logger and powertools logger initialized From 42fec202c511e8e82c2cc546c79bf7efde915182 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 13:20:46 +0100 Subject: [PATCH 05/16] chore: lint unused import --- tests/functional/test_logger_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index e28b3850855..1234d3069dd 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -6,7 +6,6 @@ from enum import Enum import pytest -from pytest_mock import MockerFixture from aws_lambda_powertools import Logger from aws_lambda_powertools.logging import formatter, utils @@ -45,6 +44,7 @@ def capture_multiple_logging_statements_output(stdout): return [json.loads(line.strip()) for line in stdout.getvalue().split("\n") if line] +@pytest.fixture def service_name(): chars = string.ascii_letters + string.digits return "".join(random.SystemRandom().choice(chars) for _ in range(15)) From f6d3e6f1e139cbea63728468e3374f6532195b5a Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 13:24:06 +0100 Subject: [PATCH 06/16] revert: service_name fixture --- tests/functional/test_logger_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index 1234d3069dd..571c7f68da5 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -44,7 +44,6 @@ def capture_multiple_logging_statements_output(stdout): return [json.loads(line.strip()) for line in stdout.getvalue().split("\n") if line] -@pytest.fixture def service_name(): chars = string.ascii_letters + string.digits return "".join(random.SystemRandom().choice(chars) for _ in range(15)) From 683a03ebfdd0ef24885e7f07483302f71159f9a6 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 13:29:04 +0100 Subject: [PATCH 07/16] fix: use addHandler over monkeypatch --- tests/functional/test_logger_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index 571c7f68da5..57a3df324a9 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -260,7 +260,7 @@ def test_copy_config_to_ext_loggers_no_duplicate_logs(stdout, logger, log_level) handler = logging.StreamHandler(stdout) formatter = logging.Formatter('{"message": "%(message)s"}') handler.setFormatter(formatter) - root_logger.handlers = [handler] + root_logger.addHandler(handler) logger = logger() @@ -275,5 +275,5 @@ def test_copy_config_to_ext_loggers_no_duplicate_logs(stdout, logger, log_level) # THEN no root logger logs AND log is not duplicated logs = capture_multiple_logging_statements_output(stdout) - assert not {"message": msg} in logs + assert {"message": msg} not in logs assert sum(msg in log.values() for log in logs) == 1 From e4f8fa831fc6fbb009244fe10b441e71dc13a0b3 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 13:29:59 +0100 Subject: [PATCH 08/16] chore: remove unnecessary test --- tests/functional/test_logger_utils.py | 29 --------------------------- 1 file changed, 29 deletions(-) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index 57a3df324a9..31ebef21d51 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -195,35 +195,6 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, log_lev powertools_logger.append_keys(key="value") -def test_copy_config_to_ext_loggers_child_loggers_append_before_work(stdout): - # GIVEN powertools logger AND child initialized AND - - # GIVEN Loggers are initialized - # create child logger before parent to mimick - # importing logger from another module/file - # as loggers are created in global scope - service = service_name() - child = Logger(stream=stdout, service=service, child=True) - parent = Logger(stream=stdout, service=service) - - # WHEN a child Logger adds an additional key AND parent logger adds additional key - child.structure_logs(append=True, customer_id="value") - parent.structure_logs(append=True, user_id="value") - # WHEN configuration copied from powertools logger - # AND powertools logger and child logger used - utils.copy_config_to_registered_loggers(source_logger=parent) - parent.warning("Logger message") - child.warning("Child logger message") - - # THEN payment_id key added to both powertools logger and child logger - parent_log, child_log = capture_multiple_logging_statements_output(stdout) - assert "customer_id" in parent_log - assert "customer_id" in child_log - assert "user_id" in parent_log - assert "user_id" in child_log - assert child.parent.name == service - - def test_copy_config_to_ext_loggers_child_loggers_append_after_works(stdout): # GIVEN powertools logger AND child initialized AND From 51558cfc0d628454dcec9bb862844437d3cad9a0 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 13:53:21 +0100 Subject: [PATCH 09/16] fix: repurpose test to cover parent loggers case --- tests/functional/test_logger_utils.py | 33 +++++++++++---------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index 31ebef21d51..559defdf316 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -195,32 +195,25 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, log_lev powertools_logger.append_keys(key="value") -def test_copy_config_to_ext_loggers_child_loggers_append_after_works(stdout): - # GIVEN powertools logger AND child initialized AND - - # GIVEN Loggers are initialized - # create child logger before parent to mimick - # importing logger from another module/file - # as loggers are created in global scope +def test_copy_config_to_parent_loggers_only(stdout): + # GIVEN Powertools Logger and Child Logger are initialized + # and Powertools Logger config is copied over service = service_name() child = Logger(stream=stdout, service=service, child=True) parent = Logger(stream=stdout, service=service) - - # WHEN a child Logger adds an additional key AND parent logger adds additional key - # AND configuration copied from powertools logger - # AND powertools logger and child logger used utils.copy_config_to_registered_loggers(source_logger=parent) - child.structure_logs(append=True, customer_id="value") - parent.structure_logs(append=True, user_id="value") - parent.warning("Logger message") - child.warning("Child logger message") - # THEN payment_id key added to both powertools logger and child logger + # WHEN either parent or child logger append keys + child.append_keys(customer_id="value") + parent.append_keys(user_id="value") + parent.info("Logger message") + child.info("Child logger message") + + # THEN both custom keys should be propagated bi-directionally in parent and child loggers + # as child logger won't be touched when config is being copied parent_log, child_log = capture_multiple_logging_statements_output(stdout) - assert "customer_id" in parent_log - assert "customer_id" in child_log - assert "user_id" in parent_log - assert "user_id" in child_log + assert "customer_id" in parent_log, child_log + assert "user_id" in parent_log, child_log assert child.parent.name == service From bc2273d66ddd2284b61fda27e822fb4e39a7c25d Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 13:59:30 +0100 Subject: [PATCH 10/16] chore: comment reason for change --- aws_lambda_powertools/logging/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_lambda_powertools/logging/utils.py b/aws_lambda_powertools/logging/utils.py index 48d2a6db9e8..bbfddcb7f68 100644 --- a/aws_lambda_powertools/logging/utils.py +++ b/aws_lambda_powertools/logging/utils.py @@ -75,7 +75,7 @@ def _find_registered_loggers( def _configure_logger(source_logger: Logger, logger: logging.Logger, level: Union[int, str]) -> None: logger.handlers = [] logger.setLevel(level) - logger.propagate = False + logger.propagate = False # ensure we don't propagate logs to existing loggers, #1073 source_logger.debug(f"Logger {logger} reconfigured to use logging level {level}") for source_handler in source_logger.handlers: logger.addHandler(source_handler) From 4fde7515bc9c0f095f99185ee1d814e6b1e40dc6 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 14:01:10 +0100 Subject: [PATCH 11/16] fix: package_logger as const over logger instance --- aws_lambda_powertools/logging/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws_lambda_powertools/logging/utils.py b/aws_lambda_powertools/logging/utils.py index bbfddcb7f68..5a786426ee3 100644 --- a/aws_lambda_powertools/logging/utils.py +++ b/aws_lambda_powertools/logging/utils.py @@ -3,6 +3,8 @@ from .logger import Logger +PACKAGE_LOGGER = "aws_lambda_powertools" + def copy_config_to_registered_loggers( source_logger: Logger, @@ -24,7 +26,6 @@ def copy_config_to_registered_loggers( exclude : Optional[Set[str]], optional List of logger names to exclude, by default None """ - package_logger = logging.getLogger("aws_lambda_powertools") level = log_level or source_logger.level # Assumptions: Only take parent loggers not children (dot notation rule) @@ -36,9 +37,9 @@ def copy_config_to_registered_loggers( # Exclude source and powertools package logger by default if exclude: - exclude.update(source_logger.name, package_logger.name) + exclude.update(source_logger.name, PACKAGE_LOGGER) else: - exclude = {source_logger.name, package_logger.name} + exclude = {source_logger.name, PACKAGE_LOGGER} # Prepare loggers set if include: From 7e56b8ad049a4c18900f27603970584b11dec074 Mon Sep 17 00:00:00 2001 From: Michal Ploski Date: Tue, 15 Mar 2022 16:30:24 +0100 Subject: [PATCH 12/16] Ensure we don't brake bi-directional propagation if child powertools logger is passed as source_logger --- aws_lambda_powertools/logging/utils.py | 8 +++++-- tests/functional/test_logger_utils.py | 31 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/logging/utils.py b/aws_lambda_powertools/logging/utils.py index 5a786426ee3..e2dcfdf2122 100644 --- a/aws_lambda_powertools/logging/utils.py +++ b/aws_lambda_powertools/logging/utils.py @@ -36,10 +36,14 @@ def copy_config_to_registered_loggers( # 4. Only exclude set? Ignore Logger in the excluding list # Exclude source and powertools package logger by default + # If source logger is a child ensure we exclude parent logger to not break child logger + # from receiving/pushing updates to keys being added/removed + source_logger_name = source_logger.name.split(".")[0] if source_logger.child else source_logger.name + if exclude: - exclude.update(source_logger.name, PACKAGE_LOGGER) + exclude.update(source_logger_name, PACKAGE_LOGGER) else: - exclude = {source_logger.name, PACKAGE_LOGGER} + exclude = {source_logger_name, PACKAGE_LOGGER} # Prepare loggers set if include: diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index 559defdf316..f3796d408ce 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -195,6 +195,37 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, log_lev powertools_logger.append_keys(key="value") +def test_copy_child_config_to_ext_loggers_should_not_break_append_keys(stdout): + # GIVEN powertools logger AND child initialized AND + + # GIVEN Loggers are initialized + # create child logger before parent to mimick + # importing logger from another module/file + # as loggers are created in global scope + service = service_name() + child = Logger(stream=stdout, service=service, child=True) + parent = Logger(stream=stdout, service=service) + + # WHEN a child Logger adds an additional key AND child logger adds additional key + # AND configuration copied from powertools child logger + # AND powertools logger and child logger used + child.structure_logs(append=True, customer_id="value") + parent.structure_logs(append=True, user_id="value") + utils.copy_config_to_registered_loggers(source_logger=child) + parent.warning("Logger message") + child.warning("Child logger message") + + # THEN both custom keys should be propagated bi-directionally in parent and child loggers + # as parent logger won't be touched when config is being copied + parent_log, child_log = capture_multiple_logging_statements_output(stdout) + assert "customer_id" in parent_log + assert "customer_id" in child_log + assert "user_id" in parent_log + assert "user_id" in child_log + assert "Child Logger message" not in parent_log + assert child.parent.name == service + + def test_copy_config_to_parent_loggers_only(stdout): # GIVEN Powertools Logger and Child Logger are initialized # and Powertools Logger config is copied over From 491829b545b23fea416d1bf20631fd77cebb4163 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 15 Mar 2022 17:43:03 +0100 Subject: [PATCH 13/16] chore: remove duplicate test --- tests/functional/test_logger_utils.py | 31 --------------------------- 1 file changed, 31 deletions(-) diff --git a/tests/functional/test_logger_utils.py b/tests/functional/test_logger_utils.py index f3796d408ce..559defdf316 100644 --- a/tests/functional/test_logger_utils.py +++ b/tests/functional/test_logger_utils.py @@ -195,37 +195,6 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, log_lev powertools_logger.append_keys(key="value") -def test_copy_child_config_to_ext_loggers_should_not_break_append_keys(stdout): - # GIVEN powertools logger AND child initialized AND - - # GIVEN Loggers are initialized - # create child logger before parent to mimick - # importing logger from another module/file - # as loggers are created in global scope - service = service_name() - child = Logger(stream=stdout, service=service, child=True) - parent = Logger(stream=stdout, service=service) - - # WHEN a child Logger adds an additional key AND child logger adds additional key - # AND configuration copied from powertools child logger - # AND powertools logger and child logger used - child.structure_logs(append=True, customer_id="value") - parent.structure_logs(append=True, user_id="value") - utils.copy_config_to_registered_loggers(source_logger=child) - parent.warning("Logger message") - child.warning("Child logger message") - - # THEN both custom keys should be propagated bi-directionally in parent and child loggers - # as parent logger won't be touched when config is being copied - parent_log, child_log = capture_multiple_logging_statements_output(stdout) - assert "customer_id" in parent_log - assert "customer_id" in child_log - assert "user_id" in parent_log - assert "user_id" in child_log - assert "Child Logger message" not in parent_log - assert child.parent.name == service - - def test_copy_config_to_parent_loggers_only(stdout): # GIVEN Powertools Logger and Child Logger are initialized # and Powertools Logger config is copied over From 3c4df97a67264f0c2bada63577fd2f0a4ec1b4b6 Mon Sep 17 00:00:00 2001 From: mploski Date: Tue, 15 Mar 2022 22:37:19 +0100 Subject: [PATCH 14/16] Update aws_lambda_powertools/logging/utils.py Co-authored-by: Heitor Lessa --- aws_lambda_powertools/logging/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_lambda_powertools/logging/utils.py b/aws_lambda_powertools/logging/utils.py index e2dcfdf2122..6559fd37ef3 100644 --- a/aws_lambda_powertools/logging/utils.py +++ b/aws_lambda_powertools/logging/utils.py @@ -38,7 +38,7 @@ def copy_config_to_registered_loggers( # Exclude source and powertools package logger by default # If source logger is a child ensure we exclude parent logger to not break child logger # from receiving/pushing updates to keys being added/removed - source_logger_name = source_logger.name.split(".")[0] if source_logger.child else source_logger.name + source_logger_name = source_logger.name.split(".")[0] if exclude: exclude.update(source_logger_name, PACKAGE_LOGGER) From 6280fbae2a879e2d582ac43149f27407735d6427 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Thu, 17 Mar 2022 08:28:47 +0100 Subject: [PATCH 15/16] docs(appsync): fix typo --- docs/core/event_handler/appsync.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/event_handler/appsync.md b/docs/core/event_handler/appsync.md index 19205289bfd..95457aa7736 100644 --- a/docs/core/event_handler/appsync.md +++ b/docs/core/event_handler/appsync.md @@ -374,7 +374,7 @@ You can nest `app.resolver()` decorator multiple times when resolving fields wit } type Query { - listLocations: [Todo] + listLocations: [Location] } type Location { From 64ab0b798acd5450bc987382a28696ab8d7ff59a Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Thu, 17 Mar 2022 17:53:21 +0100 Subject: [PATCH 16/16] chore: bump to 1.25.4 --- CHANGELOG.md | 11 +++++++++++ pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00b83d4952e..8a612ec4755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format for changes and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.25.4 - 2022-03-17 + +### Bug Fixes + +* **logger-utils**: ensure external loggers doesn't propagate logs when copying config + +### Documentation + +* **appsync:** fix typo on `listLocations` return +* **contributing:** pause new features/enhancements over operational excellence focus + ## 1.25.3 - 2022-03-09 ### Bug Fixes diff --git a/pyproject.toml b/pyproject.toml index a44a3ca133b..e72c537e403 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aws_lambda_powertools" -version = "1.25.3" +version = "1.25.4" description = "A suite of utilities for AWS Lambda functions to ease adopting best practices such as tracing, structured logging, custom metrics, batching, idempotency, feature flags, and more." authors = ["Amazon Web Services"] include = ["aws_lambda_powertools/py.typed", "THIRD-PARTY-LICENSES"]