Skip to content

copy_config_to_registered_loggers results in duplicate logs when using with existing loggers #1073

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
DonDebonair opened this issue Mar 8, 2022 · 21 comments
Assignees
Labels
bug Something isn't working

Comments

@DonDebonair
Copy link

When using utils.copy_config_to_registered_loggers() to copy the PowerLogger config to existing loggers created by a library, this results in duplicate log entries in AWS Lambda

Expected Behavior

When copying config from the AWS Powertools logger to existing loggers instantiated by a library, I expect the log statements of that library to appear once in the log stream, formatted as JSON

Current Behavior

When copying config from the AWS Powertools logger to existing loggers, I see log statements from existing loggers appearing twice in the log stream: once properly formatted as JSON and once as plain text

image

Possible Solution

I don't know why is this happening, so I can't really comment on a solution 😅

Steps to Reproduce (for bugs)

  1. Have a library that instantiates loggers the "regular" Python way, like this:
logger = logging.getLogger(__name__)

class MyClass:
    def my_func():
        logger.info("Hello")
  1. Import this library into your Lambda function
  2. Instantiate a logger from AWS Lambda Powertools and copy the config to existing loggers:
from aws_lambda_powertools import Logger
from mylibrary import MyClass

logger = Logger() # POWERTOOLS_SERVICE_NAME=myservice
utils.copy_config_to_registered_loggers(source_logger=logger)
  1. Observe duplicated logs in the Lambda log stream

Environment

  • Powertools version used: 1.25.1
  • Packaging format (Layers, PyPi): Docker image
  • AWS Lambda function runtime: Python 3.9
@DonDebonair DonDebonair added bug Something isn't working triage Pending triage from maintainers labels Mar 8, 2022
@boring-cyborg
Copy link

boring-cyborg bot commented Mar 8, 2022

Thanks for opening your first issue here! We'll come back to you as soon as we can.

@heitorlessa
Copy link
Contributor

Thanks a lot for reporting this @dandydev !! @mploski could you look into this? If I recall correctly, you fixed that with the filter two releases ago.

@mploski
Copy link
Contributor

mploski commented Mar 9, 2022

@heitorlessa I will look at this today's evening. There was PR created by @houbie #1001 to exclude source logger from a list.

@DonDebonair
Copy link
Author

If I understand #1001 correctly, that is about the source logger being excluded. And from what I understand, the source logger is the Lambda Powertools logger, from which the configs are copied, right?

The problem I'm having, is that the logs from another library are duplicated. They appear once properly formatted as JSON, and once as plain text (as per the original config)

@heitorlessa
Copy link
Contributor

yeah this seems different @dandydev. A logging filter would likely be the solution. Without revisiting the code, this typically happens when you have multiple handlers (we might not be removing existing handlers), or when the root logger is configured and logs get propagated hierarchically (we have a filter on this).

Thanks a lot @mploski !!

@DonDebonair
Copy link
Author

DonDebonair commented Mar 14, 2022

I've searched high and low, and the library that instantiates the logger I mentioned in my bug report, doesn't create any handlers. So that cannot be it.

Anyways, thanks for picking this up! I'm excited that there's already a PR open to fix this!

@heitorlessa
Copy link
Contributor

We're looking into this tomorrow @dandydev :) Should have a patch release by EOW (the latest).

@heitorlessa
Copy link
Contributor

All good @dandydev waiting @mploski for a final pass after changes to the PR, then we can prep a patch release for this.

@heitorlessa heitorlessa added pending-release Fix or implementation already in dev waiting to be released and removed triage Pending triage from maintainers labels Mar 16, 2022
@DonDebonair
Copy link
Author

Super swift! Amazing!

@github-actions
Copy link
Contributor

This is now released under 1.25.4 version!

@github-actions github-actions bot removed the pending-release Fix or implementation already in dev waiting to be released label Mar 17, 2022
@DonDebonair
Copy link
Author

DonDebonair commented Mar 18, 2022

Since updating to the newly released package, I see this in my logs:

[ERROR] IndexError: list index out of range
Traceback (most recent call last):
  File "/var/task/aws_lambda_powertools/logging/logger.py", line 345, in decorate
    self.append_keys(cold_start=cold_start, **lambda_context.__dict__)
  File "/var/task/aws_lambda_powertools/logging/logger.py", line 359, in append_keys
    self.registered_formatter.append_keys(**additional_keys)
  File "/var/task/aws_lambda_powertools/logging/logger.py", line 373, in registered_formatter
    return self.registered_handler.formatter  # type: ignore
  File "/var/task/aws_lambda_powertools/logging/logger.py", line 368, in registered_handler
    return handlers[0]

and nothing more.

This is the relevant code:

from aws_lambda_powertools import Logger
from aws_lambda_powertools.logging import utils

logger = Logger()
utils.copy_config_to_registered_loggers(source_logger=logger, exclude={'sqlalchemy'})

@logger.inject_lambda_context(log_event=True)
@event_parser(model=S3Model, envelope=envelopes.SqsEnvelope)
def handler(event, context):
    ...

@heitorlessa @mploski do you know what is going on?

@mploski
Copy link
Contributor

mploski commented Mar 18, 2022

@dandydev Looking at this, will ping you later today with the status

@mploski mploski reopened this Mar 18, 2022
@DonDebonair
Copy link
Author

Thanks @mploski , much appreciated!

@heitorlessa
Copy link
Contributor

Apologies for this regression @dandydev, it sounds like the formatter isn't being created in the parent Logger. Michal and I are trying to replicate with and without the log utils, and make a swift release.

@logger.inject_lambda_context(log_event=True) -> This calls append_keys which uses the Logger formatter to update state.

@DonDebonair
Copy link
Author

No apologies necessary! Software engineering is a finicky business :)

Thanks for getting on it so quickly!

@heitorlessa
Copy link
Contributor

Did a quick test and couldn't reproduce it - only differences are log_event and the event parser - which doesn't change much as the stack trace is on the formatter.

Could you share more info on what other loggers you have besides sqlalchemy? Trying to find ways to get a more accurate env to try and reproduce it.

Will try different angles in the meantime


def test_inject_lambda_context_with_config_clone(lambda_context, stdout):
    # GIVEN an external logger and Logger are initialized
    root_logger = logging.getLogger()
    handler = logging.StreamHandler(stdout)
    handler.setFormatter(logging.Formatter('{"message": "%(message)s"}'))
    root_logger.addHandler(handler)

    logger = Logger(service=service_name(), stream=stdout)
    utils.copy_config_to_registered_loggers(source_logger=logger)

    # WHEN a lambda function is decorated with logger
    @logger.inject_lambda_context
    def handler(event, context):
        logger.info("Hello")

    handler({}, lambda_context)

    # THEN lambda contextual info should always be in the logs
    log = capture_logging_output(stdout)
    expected_logger_context_keys = (
        "function_name",
        "function_memory_size",
        "function_arn",
        "function_request_id",
    )
    for key in expected_logger_context_keys:
        assert key in log  # GIVEN Logger is initialized

@heitorlessa
Copy link
Contributor

Reproduced it - the issue is in the new external logic - it only happens when you add external={"blah"}. We're working on it

@heitorlessa
Copy link
Contributor

We have a fix, @mploski is pushing a PR shortly, and we make a release right after. A functional test was missing so we wouldn't have been able to cover this regression either way.

@heitorlessa heitorlessa added the pending-release Fix or implementation already in dev waiting to be released label Mar 18, 2022
@github-actions
Copy link
Contributor

This is now released under 1.25.5 version!

@github-actions github-actions bot removed the pending-release Fix or implementation already in dev waiting to be released label Mar 18, 2022
@heitorlessa
Copy link
Contributor

heitorlessa commented Mar 18, 2022

hey @dandydev it's live on PyPi - could you give it a try?

@DonDebonair
Copy link
Author

Can confirm it works! Thanks for the hard work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants