Skip to content

Commit 06c0d3e

Browse files
erikayao93heitorlessaleandrodamascena
authored andcommitted
feat(logger): type log record in LambdaPowertoolsFormatter with TypedDict (aws-powertools#2419)
Co-authored-by: erikayao93 <[email protected]> Co-authored-by: Heitor Lessa <[email protected]> Co-authored-by: Leandro Damascena <[email protected]>
1 parent bb9860c commit 06c0d3e

File tree

6 files changed

+76
-19
lines changed

6 files changed

+76
-19
lines changed

.pre-commit-config.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
repos:
77
- repo: https://github.com/pre-commit/pre-commit-hooks
8-
rev: v2.4.0
8+
rev: "f71fa2c1f9cf5cb705f73dffe4b21f7c61470ba9" # v4.4.0
99
hooks:
1010
- id: check-merge-conflict
1111
- id: trailing-whitespace
@@ -30,9 +30,9 @@ repos:
3030
language: system
3131
types: [python]
3232
- repo: https://github.com/igorshubovych/markdownlint-cli
33-
rev: "11c08644ce6df850480d98f628596446a526cbc6" # frozen: v0.31.1
33+
rev: "ce0d77ac47dc921b62429804fe763d4d35f66a76" # v0.34.0
3434
hooks:
35-
- id: markdownlint
35+
- id: markdownlint-docker
3636
args: ["--fix"]
3737
- repo: local
3838
hooks:
@@ -43,7 +43,7 @@ repos:
4343
types: [yaml]
4444
files: examples/.*
4545
- repo: https://github.com/rhysd/actionlint
46-
rev: v1.6.23
46+
rev: "fd7ba3c382e13dcc0248e425b4cbc3f1185fa3ee" # v1.6.24
4747
hooks:
4848
- id: actionlint-docker
4949
args: [-pyflakes=]

aws_lambda_powertools/logging/formatter.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import inspect
24
import json
35
import logging
@@ -8,8 +10,9 @@
810
from functools import partial
911
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
1012

11-
from ..shared import constants
12-
from ..shared.functions import powertools_dev_is_set
13+
from aws_lambda_powertools.logging.types import LogRecord
14+
from aws_lambda_powertools.shared import constants
15+
from aws_lambda_powertools.shared.functions import powertools_dev_is_set
1316

1417
RESERVED_LOG_ATTRS = (
1518
"name",
@@ -66,12 +69,12 @@ class LambdaPowertoolsFormatter(BasePowertoolsFormatter):
6669

6770
def __init__(
6871
self,
69-
json_serializer: Optional[Callable[[Dict], str]] = None,
70-
json_deserializer: Optional[Callable[[Union[Dict, str, bool, int, float]], str]] = None,
71-
json_default: Optional[Callable[[Any], Any]] = None,
72-
datefmt: Optional[str] = None,
72+
json_serializer: Callable[[LogRecord], str] | None = None,
73+
json_deserializer: Callable[[Dict | str | bool | int | float], str] | None = None,
74+
json_default: Callable[[Any], Any] | None = None,
75+
datefmt: str | None = None,
7376
use_datetime_directive: bool = False,
74-
log_record_order: Optional[List[str]] = None,
77+
log_record_order: List[str] | None = None,
7578
utc: bool = False,
7679
use_rfc3339: bool = False,
7780
**kwargs,
@@ -144,7 +147,7 @@ def __init__(
144147

145148
super().__init__(datefmt=self.datefmt)
146149

147-
def serialize(self, log: Dict) -> str:
150+
def serialize(self, log: LogRecord) -> str:
148151
"""Serialize structured log dict to JSON str"""
149152
return self.json_serializer(log)
150153

aws_lambda_powertools/logging/formatters/datadog.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from __future__ import annotations
22

3-
from typing import Any, Callable
3+
from typing import Any, Callable, Dict
44

55
from aws_lambda_powertools.logging.formatter import LambdaPowertoolsFormatter
6+
from aws_lambda_powertools.logging.types import LogRecord
67

78

89
class DatadogLogFormatter(LambdaPowertoolsFormatter):
910
def __init__(
1011
self,
11-
json_serializer: Callable[[dict], str] | None = None,
12-
json_deserializer: Callable[[dict | str | bool | int | float], str] | None = None,
12+
json_serializer: Callable[[LogRecord], str] | None = None,
13+
json_deserializer: Callable[[Dict | str | bool | int | float], str] | None = None,
1314
json_default: Callable[[Any], Any] | None = None,
1415
datefmt: str | None = None,
1516
use_datetime_directive: bool = False,
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from __future__ import annotations
2+
3+
import sys
4+
5+
if sys.version_info >= (3, 11):
6+
from typing import NotRequired
7+
else:
8+
from typing_extensions import NotRequired
9+
10+
if sys.version_info >= (3, 8):
11+
from typing import TypedDict
12+
else:
13+
from typing_extensions import TypedDict
14+
15+
if sys.version_info >= (3, 10):
16+
from typing import TypeAlias
17+
else:
18+
from typing_extensions import TypeAlias
19+
20+
from typing import Any, Dict, List, Union
21+
22+
LogRecord: TypeAlias = Union[Dict[str, Any], "PowertoolsLogRecord"]
23+
24+
25+
class PowertoolsLogRecord(TypedDict):
26+
# Base fields (required)
27+
level: str
28+
location: str
29+
message: Dict[str, Any] | str | bool | List[Any]
30+
timestamp: str | int
31+
service: str
32+
33+
# Fields from logger.inject_lambda_context
34+
cold_start: NotRequired[bool]
35+
function_name: NotRequired[str]
36+
function_memory_size: NotRequired[int]
37+
function_arn: NotRequired[str]
38+
function_request_id: NotRequired[str]
39+
# From logger.inject_lambda_context if AWS X-Ray is enabled
40+
xray_trace_id: NotRequired[str]
41+
42+
# If sample_rate is defined
43+
sampling_rate: NotRequired[float]
44+
45+
# From logger.set_correlation_id
46+
correlation_id: NotRequired[str]
47+
48+
# Fields from logger.exception
49+
exception_name: NotRequired[str]
50+
exception: NotRequired[str]

docs/core/logger.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ For these, you can override the `serialize` method from [LambdaPowertoolsFormatt
604604

605605
=== "bring_your_own_formatter.py"
606606

607-
```python hl_lines="2 5-6 12"
607+
```python hl_lines="2-3 6 11-12 15"
608608
--8<-- "examples/logger/src/bring_your_own_formatter.py"
609609
```
610610

examples/logger/src/bring_your_own_formatter.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
from aws_lambda_powertools import Logger
22
from aws_lambda_powertools.logging.formatter import LambdaPowertoolsFormatter
3+
from aws_lambda_powertools.logging.types import LogRecord
34

45

56
class CustomFormatter(LambdaPowertoolsFormatter):
6-
def serialize(self, log: dict) -> str:
7+
def serialize(self, log: LogRecord) -> str:
78
"""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
9+
# in this example, log["message"] is a required field
10+
# but we want to remap to "event" and delete "message", hence mypy ignore checks
11+
log["event"] = log.pop("message") # type: ignore[typeddict-unknown-key,misc]
12+
return self.json_serializer(log)
1013

1114

1215
logger = Logger(service="payment", logger_formatter=CustomFormatter())

0 commit comments

Comments
 (0)