Using python Logging with AWS Lambda

PythonAmazon Web-ServicesLoggingAws Lambda

Python Problem Overview


As the AWS documentation suggests:

import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def my_logging_handler(event, context):
    logger.info('got event{}'.format(event))
    logger.error('something went wrong')

Now I made:

import logging
logging.basicConfig(level = logging.INFO)
logging.info("Hello World!")

The first snippet of code prints in the Cloud Watch console, but the second one no.

I didn't see any difference as the two snippets are using the root logger.

Python Solutions


Solution 1 - Python

The reason that logging does not seem to work is because the AWS Lambda Python runtime pre-configures a logging handler that, depending on the version of the runtime selected, might modify the format of the message logged, and might also add some metadata to the record if available. What is not preconfigured though is the log-level. This means that no matter the type of log-message you try to send, it will not actually print.

As AWS documents themselves, to correctly use the logging library in the AWS Lambda context, you only need to set the log-level for the root-logger:

import logging
logging.getLogger().setLevel(logging.INFO)

If you want your Python-script to be both executable on AWS Lambda, but also with your local Python interpreter, you can check whether a handler is configured or not, and fall back to basicConfig (which creates the default stderr-handler) otherwise:

if len(logging.getLogger().handlers) > 0:
    # The Lambda environment pre-configures a handler logging to stderr. If a handler is already configured,
    # `.basicConfig` does not execute. Thus we set the level directly.
    logging.getLogger().setLevel(logging.INFO)
else:
    logging.basicConfig(level=logging.INFO)

Solution 2 - Python

Copied straight from the top answer in the question @StevenBohrer's answer links to (this did the trick for me, replacing the last line with my own config):

root = logging.getLogger()
if root.handlers:
    for handler in root.handlers:
        root.removeHandler(handler)
logging.basicConfig(format='%(asctime)s %(message)s',level=logging.DEBUG)

Solution 3 - Python

I've struggled with this exact problem. The solution that works both locally and on AWS CloudWatch is to setup your logging like this:

import logging

# Initialize you log configuration using the base class
logging.basicConfig(level = logging.INFO)

# Retrieve the logger instance
logger = logging.getLogger()

# Log your output to the retrieved logger instance
logger.info("Python for the win!")

Solution 4 - Python

I had a similar problem, and I suspect that the lambda container is calling logging.basicConfig to add handlers BEFORE the lambda code is imported. This seems like bad form...

Workaround was to see if root logger handlers were configured and if so, remove them, add my formatter and desired log level (using basicConfig), and restore the handlers.

See this article https://stackoverflow.com/questions/1943747/python-logging-before-you-run-logging-basicconfig

Solution 5 - Python

Probably not referencing the same logger, actually. In the first snippet, log the return of: logging.Logger.manager.loggerDict

It will return a dict of the loggers already initialized.

Also, from the logging documentation, an important note on logging.basicConfig:

> Does basic configuration for the logging system by creating a StreamHandler with a default Formatter and adding it to the root logger. The functions debug(), info(), warning(), error() and critical() will call basicConfig() automatically if no handlers are defined for the root logger. > >This function does nothing if the root logger already has handlers configured for it.

Source: https://docs.python.org/2/library/logging.html#logging.basicConfig

Solution 6 - Python

It depends upon the aws lambda python version

If python version 3.8 and above

import os
import logging

default_log_args = {
    "level": logging.DEBUG if os.environ.get("DEBUG", False) else logging.INFO,
    "format": "%(asctime)s [%(levelname)s] %(name)s - %(message)s",
    "datefmt": "%d-%b-%y %H:%M",
    "force": True,
}


logging.basicConfig(**default_log_args)
log = logging.getLogger("Run-Lambda")

log.info("I m here too)

If python version 3.7 and below

import os
import logging

root = logging.getLogger()
if root.handlers:
    for handler in root.handlers:
        root.removeHandler(handler)

default_log_args = {
    "level": logging.DEBUG if os.environ.get("DEBUG", False) else logging.INFO,
    "format": "%(asctime)s [%(levelname)s] %(name)s - %(message)s",
    "datefmt": "%d-%b-%y %H:%M"
}

logging.basicConfig(**default_log_args)
log = logging.getLogger("Run-Lambda")

log.info("Iam here")

Solution 7 - Python

Essentially, the AWS logging monkey patch needs to be handled in a very particular way, where:

  1. The log level is set from the TOP level of the script (e.g., at import time)
  2. The log statements you are interested in are invoked from within the lambda function

Since it's generally considered good form not to run arbitrary code in Python module import, you usually should be able to restructure your code so that the heavy lifting occurs only inside the lambda function.

Solution 8 - Python

I would suggest use aws python lambda powertools. The logging doc is here. Code example:

from aws_lambda_powertools import Logger
logger = Logger() # Sets service via env var
# OR logger = Logger(service="example")

It works works both locally and on CloudWatch for me.

Solution 9 - Python

    LOGGER = logging.getLogger()
    HANDLER = LOGGER.handlers[0]
    HANDLER.setFormatter(
        logging.Formatter(“[%(asctime)s] %(levelname)s:%(name)s:%(message)s”, “%Y-%m-%d %H:%M:%S”)
    )

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionp.magalhaesView Question on Stackoverflow
Solution 1 - PythonPitView Answer on Stackoverflow
Solution 2 - PythonBrett BeattyView Answer on Stackoverflow
Solution 3 - PythonKinmanView Answer on Stackoverflow
Solution 4 - PythonSteven BohrerView Answer on Stackoverflow
Solution 5 - PythonHEADLESS_0NEView Answer on Stackoverflow
Solution 6 - PythonVijay Anand PandianView Answer on Stackoverflow
Solution 7 - PythonEdward Z. YangView Answer on Stackoverflow
Solution 8 - PythonYuantaoView Answer on Stackoverflow
Solution 9 - PythonPeters MondayView Answer on Stackoverflow