Skip to content

Commit e4c1e8e

Browse files
committed
refactor: make requested changes
Changes: * Add missing comments and docs * formatter - Group the kwargs code * logger - convert back to class static methods
1 parent 3e0116b commit e4c1e8e

File tree

3 files changed

+39
-32
lines changed

3 files changed

+39
-32
lines changed

aws_lambda_powertools/logging/formatter.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,23 @@ def __init__(self, **kwargs):
2020
unserializable values. It must not throw. Defaults to a function that
2121
coerces the value to a string.
2222
23+
The `log_record_order` kwarg is used to specify the order of the keys used in
24+
the structured json logs. By default the order is: "level", "location", "message", "timestamp",
25+
"service" and "sampling_rate".
26+
2327
Other kwargs are used to specify log field format strings.
2428
"""
29+
# Set the default unserializable function, by default values will be cast as str.
2530
self.default_json_formatter = kwargs.pop("json_default", str)
26-
datefmt = kwargs.pop("datefmt", None)
31+
# Set the insertion order for the log messages
32+
self.format_dict = dict.fromkeys(kwargs.pop("log_record_order", ["level", "location", "message", "timestamp"]))
33+
# Set timestamp the date format
34+
super(JsonFormatter, self).__init__(datefmt=kwargs.pop("datefmt", None))
2735

28-
super(JsonFormatter, self).__init__(datefmt=datefmt)
2936
self.reserved_keys = ["timestamp", "level", "location"]
30-
self.format_dict = dict.fromkeys(kwargs.pop("format_keys", ["level", "location", "message", "timestamp"]))
3137
self.format_dict.update(
32-
{"level": "%(levelname)s", "location": "%(funcName)s:%(lineno)d", "timestamp": "%(asctime)s"}
38+
{"level": "%(levelname)s", "location": "%(funcName)s:%(lineno)d", "timestamp": "%(asctime)s", **kwargs}
3339
)
34-
self.format_dict.update(kwargs)
3540

3641
def update_formatter(self, **kwargs):
3742
self.format_dict.update(kwargs)

aws_lambda_powertools/logging/logger.py

+20-20
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def __init__(
123123
):
124124
self.service = service or os.getenv("POWERTOOLS_SERVICE_NAME") or "service_undefined"
125125
self.sampling_rate = sampling_rate or os.getenv("POWERTOOLS_LOGGER_SAMPLE_RATE") or 0.0
126-
self.log_level = _get_log_level(level)
126+
self.log_level = self._get_log_level(level)
127127
self.child = child
128128
self._handler = logging.StreamHandler(stream) if stream is not None else logging.StreamHandler(sys.stdout)
129129
self._default_log_keys = {"service": self.service, "sampling_rate": self.sampling_rate}
@@ -140,7 +140,7 @@ def _get_logger(self):
140140
""" Returns a Logger named {self.service}, or {self.service.filename} for child loggers"""
141141
logger_name = self.service
142142
if self.child:
143-
logger_name = f"{self.service}.{_get_caller_filename()}"
143+
logger_name = f"{self.service}.{self._get_caller_filename()}"
144144

145145
return logging.getLogger(logger_name)
146146

@@ -272,28 +272,28 @@ def structure_logs(self, append: bool = False, **kwargs):
272272
# Set a new formatter for a logger handler
273273
handler.setFormatter(JsonFormatter(**self._default_log_keys, **kwargs))
274274

275+
@staticmethod
276+
def _get_log_level(level: Union[str, int]) -> Union[str, int]:
277+
""" Returns preferred log level set by the customer in upper case """
278+
if isinstance(level, int):
279+
return level
275280

276-
def _get_log_level(level: Union[str, int]) -> Union[str, int]:
277-
""" Returns preferred log level set by the customer in upper case """
278-
if isinstance(level, int):
279-
return level
281+
log_level: str = level or os.getenv("LOG_LEVEL")
282+
log_level = log_level.upper() if log_level is not None else logging.INFO
280283

281-
log_level: str = level or os.getenv("LOG_LEVEL")
282-
log_level = log_level.upper() if log_level is not None else logging.INFO
284+
return log_level
283285

284-
return log_level
286+
@staticmethod
287+
def _get_caller_filename():
288+
""" Return caller filename by finding the caller frame """
289+
# Current frame => _get_logger()
290+
# Previous frame => logger.py
291+
# Before previous frame => Caller
292+
frame = inspect.currentframe()
293+
caller_frame = frame.f_back.f_back.f_back
294+
filename = caller_frame.f_globals["__name__"]
285295

286-
287-
def _get_caller_filename():
288-
""" Return caller filename by finding the caller frame """
289-
# Current frame => _get_logger()
290-
# Previous frame => logger.py
291-
# Before previous frame => Caller
292-
frame = inspect.currentframe()
293-
caller_frame = frame.f_back.f_back.f_back
294-
filename = caller_frame.f_globals["__name__"]
295-
296-
return filename
296+
return filename
297297

298298

299299
def set_package_logger(

tests/functional/test_aws_lambda_logging.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ class Unserializable:
119119

120120

121121
def test_log_dict_key_seq(stdout):
122-
# GIVEN any logger configuration
123-
logger = Logger(level="INFO", stream=stdout, another="xxx")
122+
# GIVEN the default logger configuration
123+
logger = Logger(stream=stdout)
124124

125125
# WHEN logging a message
126126
logger.info("Message")
@@ -133,7 +133,7 @@ def test_log_dict_key_seq(stdout):
133133

134134
def test_log_dict_key_custom_seq(stdout):
135135
# GIVEN a logger configuration with format_keys set to ["message"]
136-
logger = Logger(stream=stdout, format_keys=["message"])
136+
logger = Logger(stream=stdout, log_record_order=["message"])
137137

138138
# WHEN logging a message
139139
logger.info("Message")
@@ -145,21 +145,23 @@ def test_log_dict_key_custom_seq(stdout):
145145

146146

147147
def test_log_custom_formatting(stdout):
148-
# GIVEN a logger where we have a custom location format
149-
logger = Logger(stream=stdout, location="[%(funcName)s] %(module)s")
148+
# GIVEN a logger where we have a custom `location`, 'datefmt' format
149+
logger = Logger(stream=stdout, location="[%(funcName)s] %(module)s", datefmt="fake-datefmt")
150150

151151
# WHEN logging a message
152152
logger.info("foo")
153153

154154
log_dict: dict = json.loads(stdout.getvalue())
155155

156-
# THEN the `location` match the formatting
156+
# THEN the `location` and "timestamp" should match the formatting
157157
assert log_dict["location"] == "[test_log_custom_formatting] test_aws_lambda_logging"
158+
assert log_dict["timestamp"] == "fake-datefmt"
158159

159160

160161
def test_log_dict_key_strip_nones(stdout):
161162
# GIVEN a logger confirmation where we set `location` and `timestamp` to None
162-
logger = Logger(stream=stdout, location=None, timestamp=None)
163+
# Note: level, sampling_rate and service can not be suppressed
164+
logger = Logger(stream=stdout, level=None, location=None, timestamp=None, sampling_rate=None, service=None)
163165

164166
# WHEN logging a message
165167
logger.info("foo")

0 commit comments

Comments
 (0)