/

Logger

Core utility


Logger provides an opinionated logger with output structured as JSON.

Key features

  • Capture key fields from Lambda context, cold start and structures logging output as JSON
  • Log Lambda event when instructed (disabled by default)
    • Enable via POWERTOOLS_LOGGER_LOG_EVENT="true" or explicitly via decorator param
  • Log sampling enables DEBUG log level for a percentage of requests (disabled by default)
    • Enable via POWERTOOLS_LOGGER_SAMPLE_RATE=0.1, ranges from 0 to 1, where 0.1 is 10% and 1 is 100%
  • Append additional keys to structured log at any point in time

Initialization

Set LOG_LEVEL env var as a start - Here is an example using AWS Serverless Application Model (SAM)

template.yaml
Resources:
    HelloWorldFunction:
        Type: AWS::Serverless::Function
        Properties:
        ...
        Runtime: python3.8
        Environment:
            Variables:
                LOG_LEVEL: INFO

By default, Logger uses INFO log level. You can either change log level via level param or via env var.

You can also explicitly set a service name via service param or via POWERTOOLS_SERVICE_NAME env var. This sets service key that will be present across all log statements.

app.py
from aws_lambda_powertools import Logger
# POWERTOOLS_SERVICE_NAME defined
logger = Logger()
# Explicit definition
Logger(service="payment", level="INFO")

Standard structured keys

Your Logger will always include the following keys to your structured logging:

KeyTypeExampleDescription
timestampstr"2020-05-24 18:17:33,774"Timestamp of actual log statement
levelstr"INFO"Logging level
locationstr"collect.handler:1"Source code location where statement was executed
servicestr"payment"Service name defined. "service_undefined" will be used if unknown
sampling_rateint0.1Debug logging sampling rate in percentage e.g. 1% in this case
messageany"Collecting payment"Log statement value. Unserializable JSON values will be casted to string

Capturing context Lambda info

You can enrich your structured logs with key Lambda context information via inject_lambda_context.

collect.py
from aws_lambda_powertools import Logger

logger = Logger()

@logger.inject_lambda_context
def handler(event, context):
   logger.info("Collecting payment")
   ...
   # You can log entire objects too
   logger.info({
      "operation": "collect_payment",
      "charge_id": event['charge_id']
   })
   ...

You can also explicitly log any incoming event using log_event param or via POWERTOOLS_LOGGER_LOG_EVENT env var.

This is disabled by default to prevent sensitive info being logged.

log_handler_event.py
from aws_lambda_powertools import Logger

logger = Logger()

def handler(event, context):   ...

When used, this will include the following keys:

KeyTypeExample
cold_startboolfalse
function_namestr"example-powertools-HelloWorldFunction-1P1Z6B39FLU73"
function_memory_sizeint128
function_arnstr"arn:aws:lambda:eu-west-1:012345678910:function:example-powertools-HelloWorldFunction-1P1Z6B39FLU73"
function_request_idstr"899856cb-83d1-40d7-8611-9e78f15f32f4"
Exerpt output in CloudWatch Logs
cloudwatch_logs.json
{
   "timestamp":"2020-05-24 18:17:33,774",
   "level":"INFO",
   "location":"collect.handler:1",
   "service":"payment",
   "lambda_function_name":"test",   "lambda_function_memory_size": 128,   "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",   "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",   "cold_start": true,   "sampling_rate": 0.0,
   "message": "Collecting payment"
}

{
   "timestamp":"2020-05-24 18:17:33,774",
   "level":"INFO",
   "location":"collect.handler:15",
   "service":"payment",
   "lambda_function_name":"test",
   "lambda_function_memory_size": 128,
   "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
   "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
   "cold_start": true,
   "sampling_rate": 0.0,
   "message":{      "operation":"collect_payment",      "charge_id": "ch_AZFlk2345C0"   }}

Appending additional keys

You can append your own keys to your existing Logger via structure_logs with append param.

collect.py
from aws_lambda_powertools import Logger

logger = Logger()

def handler(event, context):
   if "order_id" in event:
      logger.structure_logs(append=True, order_id=event["order_id"])      logger.info("Collecting payment")
      ...
Exerpt output in CloudWatch Logs
cloudwatch_logs.jsonn
{
   "timestamp": "2020-05-24 18:17:33,774",
   "level": "INFO",
   "location": "collect.handler:1",
   "service": "payment",
   "lambda_function_name": "test",
   "lambda_function_memory_size": 128,
   "lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
   "lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
   "cold_start": true,
   "sampling_rate": 0.0,
   "order_id": "order_id_value",   "message": "Collecting payment"
}

Sampling debug logs

You can dynamically set a percentage of your logs to DEBUG level using sample_rate param or via env var POWERTOOLS_LOGGER_SAMPLE_RATE.

This happens on an entire request basis, and DEBUG level is set at the constructor. That means, concurrent requests or infrequent invocations are more likely to occur as new Lambda execution contexts are created, not reused.

If you want this logic to happen on every invocation regardless whether Lambda reuses the execution environment or not, then create your Logger inside your Lambda handler.

collect.py
from aws_lambda_powertools import Logger

# Sample 1% of debug logs e.g. 0.1
logger = Logger(sample_rate=0.1)
def handler(event, context):
   if "order_id" in event:
      logger.info("Collecting payment")
      ...
Exerpt output in CloudWatch Logs
cloudwatch_logs.json
{
   "timestamp": "2020-05-24 18:17:33,774",
   "level": "INFO",
   "location": "collect.handler:1",
   "service": "payment",
   "lambda_function_name": "test",
   "lambda_function_memory_size": 128,
   "lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
   "lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
   "cold_start": true,
   "sampling_rate": 0.1,   "message": "Collecting payment"
}
Edit on GitHub