Skip to content

Commit 982773b

Browse files
authored
docs(logger): snippets split, improved, and lint (#1262)
1 parent 5f06a9e commit 982773b

File tree

55 files changed

+916
-726
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+916
-726
lines changed

docs/core/logger.md

Lines changed: 199 additions & 721 deletions
Large diffs are not rendered by default.

docs/core/tracer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Tracer is an opinionated thin wrapper for [AWS X-Ray Python SDK](https://github.
2121
Before your use this utility, your AWS Lambda function [must have permissions](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html#services-xray-permissions) to send traces to AWS X-Ray.
2222

2323
```yaml hl_lines="9 12" title="AWS Serverless Application Model (SAM) example"
24-
--8<-- "examples/tracer/template.yaml"
24+
--8<-- "examples/tracer/sam/template.yaml"
2525
```
2626

2727
### Lambda handler

examples/tracer/template.yaml renamed to examples/logger/sam/template.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ Globals:
99
Tracing: Active
1010
Environment:
1111
Variables:
12-
POWERTOOLS_SERVICE_NAME: example
12+
POWERTOOLS_SERVICE_NAME: payment
13+
LOG_LEVEL: INFO
1314
Layers:
1415
# Find the latest Layer version in the official documentation
1516
# https://awslabs.github.io/aws-lambda-powertools-python/latest/#lambda-layer
1617
- !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:21
1718

1819
Resources:
19-
CaptureLambdaHandlerExample:
20+
LoggerLambdaHandlerExample:
2021
Type: AWS::Serverless::Function
2122
Properties:
22-
CodeUri: src
23-
Handler: capture_lambda_handler.handler
23+
CodeUri: ../src
24+
Handler: inject_lambda_context.handler

examples/logger/src/append_keys.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
def handler(event: dict, context: LambdaContext) -> str:
8+
order_id = event.get("order_id")
9+
10+
# this will ensure order_id key always has the latest value before logging
11+
# alternative, you can use `clear_state=True` parameter in @inject_lambda_context
12+
logger.append_keys(order_id=order_id)
13+
logger.info("Collecting payment")
14+
15+
return "hello world"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
def handler(event: dict, context: LambdaContext) -> str:
8+
fields = {"request_id": "1123"}
9+
logger.info("Collecting payment", extra=fields)
10+
11+
return "hello world"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"level": "INFO",
3+
"location": "collect.handler:9",
4+
"message": "Collecting payment",
5+
"timestamp": "2021-05-03 11:47:12,494+0200",
6+
"service": "payment",
7+
"request_id": "1123"
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"level": "INFO",
3+
"location": "collect.handler:11",
4+
"message": "Collecting payment",
5+
"timestamp": "2021-05-03 11:47:12,494+0200",
6+
"service": "payment",
7+
"order_id": "order_id_value"
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import os
2+
3+
import requests
4+
5+
from aws_lambda_powertools import Logger
6+
7+
ENDPOINT = os.getenv("PAYMENT_API", "")
8+
logger = Logger(service="payment")
9+
10+
11+
class PaymentError(Exception):
12+
...
13+
14+
15+
def handler(event, context):
16+
logger.append_keys(payment_id="123456789")
17+
charge_id = event.get("charge_id", "")
18+
19+
try:
20+
ret = requests.post(url=f"{ENDPOINT}/collect", data={"charge_id": charge_id})
21+
ret.raise_for_status()
22+
23+
logger.info("Charge collected successfully", extra={"charge_id": charge_id})
24+
return ret.json()
25+
except requests.HTTPError as e:
26+
raise PaymentError(f"Unable to collect payment for charge {charge_id}") from e
27+
28+
logger.info("goodbye")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[
2+
{
3+
"level": "INFO",
4+
"location": "<module>:22",
5+
"message": "Charge collected successfully",
6+
"timestamp": "2021-01-12 14:09:10,859",
7+
"service": "payment",
8+
"sampling_rate": 0.0,
9+
"payment_id": "123456789",
10+
"charge_id": "75edbad0-0857-4fc9-b547-6180e2f7959b"
11+
},
12+
{
13+
"level": "INFO",
14+
"location": "<module>:27",
15+
"message": "goodbye",
16+
"timestamp": "2021-01-12 14:09:10,860",
17+
"service": "payment",
18+
"sampling_rate": 0.0,
19+
"payment_id": "123456789"
20+
}
21+
]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.logging.formatter import LambdaPowertoolsFormatter
3+
4+
5+
class CustomFormatter(LambdaPowertoolsFormatter):
6+
def serialize(self, log: dict) -> str:
7+
"""Serialize final structured log dict to JSON str"""
8+
log["event"] = log.pop("message") # rename message key to event
9+
return self.json_serializer(log) # use configured json serializer
10+
11+
12+
logger = Logger(service="payment", logger_formatter=CustomFormatter())
13+
logger.info("hello")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import json
2+
import logging
3+
from typing import Iterable, List, Optional
4+
5+
from aws_lambda_powertools import Logger
6+
from aws_lambda_powertools.logging.formatter import BasePowertoolsFormatter
7+
8+
9+
class CustomFormatter(BasePowertoolsFormatter):
10+
def __init__(self, log_record_order: Optional[List[str]], *args, **kwargs):
11+
self.log_record_order = log_record_order or ["level", "location", "message", "timestamp"]
12+
self.log_format = dict.fromkeys(self.log_record_order)
13+
super().__init__(*args, **kwargs)
14+
15+
def append_keys(self, **additional_keys):
16+
# also used by `inject_lambda_context` decorator
17+
self.log_format.update(additional_keys)
18+
19+
def remove_keys(self, keys: Iterable[str]):
20+
for key in keys:
21+
self.log_format.pop(key, None)
22+
23+
def clear_state(self):
24+
self.log_format = dict.fromkeys(self.log_record_order)
25+
26+
def format(self, record: logging.LogRecord) -> str: # noqa: A003
27+
"""Format logging record as structured JSON str"""
28+
return json.dumps(
29+
{
30+
"event": super().format(record),
31+
"timestamp": self.formatTime(record),
32+
"my_default_key": "test",
33+
**self.log_format,
34+
}
35+
)
36+
37+
38+
logger = Logger(service="payment", logger_formatter=CustomFormatter())
39+
40+
41+
@logger.inject_lambda_context
42+
def handler(event, context):
43+
logger.info("Collecting payment")
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"event": "Collecting payment",
3+
"timestamp": "2021-05-03 11:47:12,494",
4+
"my_default_key": "test",
5+
"cold_start": true,
6+
"lambda_function_name": "test",
7+
"lambda_function_memory_size": 128,
8+
"lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
9+
"lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"level": "INFO",
3+
"location": "<module>:16",
4+
"timestamp": "2021-12-30 13:41:53,413+0100",
5+
"service": "payment",
6+
"event": "hello"
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import logging
2+
from pathlib import Path
3+
4+
from aws_lambda_powertools import Logger
5+
6+
log_file = Path("/tmp/log.json")
7+
log_file_handler = logging.FileHandler(filename=log_file)
8+
9+
logger = Logger(service="payment", logger_handler=log_file_handler)
10+
11+
logger.info("hello world")
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import functools
2+
3+
import orjson
4+
5+
from aws_lambda_powertools import Logger
6+
7+
custom_serializer = orjson.dumps
8+
custom_deserializer = orjson.loads
9+
10+
logger = Logger(service="payment", json_serializer=custom_serializer, json_deserializer=custom_deserializer)
11+
12+
# NOTE: when using parameters, you can pass a partial
13+
custom_serializer_with_parameters = functools.partial(orjson.dumps, option=orjson.OPT_SERIALIZE_NUMPY)
14+
15+
logger_two = Logger(
16+
service="payment", json_serializer=custom_serializer_with_parameters, json_deserializer=custom_deserializer
17+
)

examples/logger/src/clear_state.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
@logger.inject_lambda_context(clear_state=True)
8+
def handler(event: dict, context: LambdaContext) -> str:
9+
if event.get("special_key"):
10+
# Should only be available in the first request log
11+
# as the second request doesn't contain `special_key`
12+
logger.append_keys(debugging_key="value")
13+
14+
logger.info("Collecting payment")
15+
16+
return "hello world"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"level": "INFO",
3+
"location": "collect.handler:10",
4+
"message": "Collecting payment",
5+
"timestamp": "2021-05-03 11:47:12,494+0200",
6+
"service": "payment",
7+
"special_key": "debug_key",
8+
"cold_start": true,
9+
"lambda_function_name": "test",
10+
"lambda_function_memory_size": 128,
11+
"lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
12+
"lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"level": "INFO",
3+
"location": "collect.handler:10",
4+
"message": "Collecting payment",
5+
"timestamp": "2021-05-03 11:47:12,494+0200",
6+
"service": "payment",
7+
"cold_start": false,
8+
"lambda_function_name": "test",
9+
"lambda_function_memory_size": 128,
10+
"lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
11+
"lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import logging
2+
3+
from aws_lambda_powertools import Logger
4+
from aws_lambda_powertools.logging import utils
5+
6+
logger = Logger()
7+
8+
external_logger = logging.logger()
9+
10+
utils.copy_config_to_registered_loggers(source_logger=logger)
11+
external_logger.info("test message")
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from typing import Dict, List
2+
3+
import boto3
4+
5+
from aws_lambda_powertools import Logger
6+
from aws_lambda_powertools.utilities.typing import LambdaContext
7+
8+
boto3.set_stream_logger()
9+
boto3.set_stream_logger("botocore")
10+
11+
logger = Logger()
12+
client = boto3.client("s3")
13+
14+
15+
def handler(event: Dict, context: LambdaContext) -> List:
16+
response = client.list_buckets()
17+
18+
return response.get("Buckets", [])
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from dataclasses import dataclass
2+
3+
import fake_lambda_context_for_logger_module # sample module for completeness
4+
import pytest
5+
6+
7+
@pytest.fixture
8+
def lambda_context():
9+
@dataclass
10+
class LambdaContext:
11+
function_name: str = "test"
12+
memory_limit_in_mb: int = 128
13+
invoked_function_arn: str = "arn:aws:lambda:eu-west-1:809313241:function:test"
14+
aws_request_id: str = "52fdfc07-2182-154f-163f-5f0f9a621d72"
15+
16+
return LambdaContext()
17+
18+
19+
def test_lambda_handler(lambda_context):
20+
test_event = {"test": "event"}
21+
fake_lambda_context_for_logger_module.handler(test_event, lambda_context)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
@logger.inject_lambda_context
8+
def handler(event: dict, context: LambdaContext) -> str:
9+
logger.info("Collecting payment")
10+
11+
return "hello world"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
@logger.inject_lambda_context
8+
def handler(event: dict, context: LambdaContext) -> str:
9+
logger.info("Collecting payment")
10+
11+
# You can log entire objects too
12+
logger.info({"operation": "collect_payment", "charge_id": event["charge_id"]})
13+
return "hello world"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[
2+
{
3+
"level": "INFO",
4+
"location": "collect.handler:9",
5+
"message": "Collecting payment",
6+
"timestamp": "2021-05-03 11:47:12,494+0200",
7+
"service": "payment",
8+
"cold_start": true,
9+
"lambda_function_name": "test",
10+
"lambda_function_memory_size": 128,
11+
"lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
12+
"lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
13+
},
14+
{
15+
"level": "INFO",
16+
"location": "collect.handler:12",
17+
"message": {
18+
"operation": "collect_payment",
19+
"charge_id": "ch_AZFlk2345C0"
20+
},
21+
"timestamp": "2021-05-03 11:47:12,494+0200",
22+
"service": "payment",
23+
"cold_start": true,
24+
"lambda_function_name": "test",
25+
"lambda_function_memory_size": 128,
26+
"lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
27+
"lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
28+
}
29+
]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
logger = Logger()
5+
6+
7+
@logger.inject_lambda_context(log_event=True)
8+
def handler(event: dict, context: LambdaContext) -> str:
9+
return "hello world"

0 commit comments

Comments
 (0)