diff --git a/aws_lambda_powertools/logging/formatter.py b/aws_lambda_powertools/logging/formatter.py index 1f01015051c..51f60a87021 100644 --- a/aws_lambda_powertools/logging/formatter.py +++ b/aws_lambda_powertools/logging/formatter.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union from ..shared import constants +from ..shared.functions import strtobool RESERVED_LOG_ATTRS = ( "name", @@ -111,9 +112,15 @@ def __init__( Key-value to be included in log messages """ + self.json_deserializer = json_deserializer or json.loads self.json_default = json_default or str - self.json_serializer = json_serializer or partial(json.dumps, default=self.json_default, separators=(",", ":")) + self.json_indent = ( + constants.PRETTY_INDENT if strtobool(os.getenv("POWERTOOLS_DEV", "0")) else constants.COMPACT_INDENT + ) # indented json serialization when in AWS SAM Local + self.json_serializer = json_serializer or partial( + json.dumps, default=self.json_default, separators=(",", ":"), indent=self.json_indent + ) self.datefmt = datefmt self.use_datetime_directive = use_datetime_directive diff --git a/aws_lambda_powertools/shared/constants.py b/aws_lambda_powertools/shared/constants.py index 48d94d88f1d..09d9132af90 100644 --- a/aws_lambda_powertools/shared/constants.py +++ b/aws_lambda_powertools/shared/constants.py @@ -32,3 +32,7 @@ "cold_start", "xray_trace_id", ] + +# JSON indentation level +PRETTY_INDENT: int = 4 +COMPACT_INDENT = None diff --git a/docs/core/logger.md b/docs/core/logger.md index c699568b349..9605017697c 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -369,6 +369,9 @@ If you prefer configuring it separately, or you'd want to bring this JSON Format | **`log_record_order`** | set order of log keys when logging | `["level", "location", "message", "timestamp"]` | | **`kwargs`** | key-value to be included in log messages | `None` | +???+ info + When `POWERTOOLS_DEV` env var is present and set to `"true"`, Logger's default serializer (`json.dumps`) will pretty-print log messages for easier readability. + ```python hl_lines="2 7-8" title="Pre-configuring Lambda Powertools Formatter" --8<-- "examples/logger/src/powertools_formatter_setup.py" ``` diff --git a/tests/functional/test_logger_powertools_formatter.py b/tests/functional/test_logger_powertools_formatter.py index c9f970e29a5..7276f49d487 100644 --- a/tests/functional/test_logger_powertools_formatter.py +++ b/tests/functional/test_logger_powertools_formatter.py @@ -1,6 +1,7 @@ """aws_lambda_logging tests.""" import io import json +import os import random import string import time @@ -288,3 +289,23 @@ def test_log_formatting(stdout, service_name): # THEN the formatting should be applied (NB. this is valid json, but hasn't be parsed) assert log_dict["message"] == '["foo bar 123 [1, None]", null]' + + +def test_log_json_indent_compact_indent(stdout, service_name, monkeypatch): + # GIVEN a logger with default settings and WHEN POWERTOOLS_DEV is not set + monkeypatch.delenv(name="POWERTOOLS_DEV", raising=False) + logger = Logger(service=service_name, stream=stdout) + logger.info("Test message") + # THEN the json should not have multiple lines + new_lines = stdout.getvalue().count(os.linesep) + assert new_lines == 1 + + +def test_log_json_pretty_indent(stdout, service_name, monkeypatch): + # GIVEN a logger with default settings and WHEN POWERTOOLS_DEV=="true" + monkeypatch.setenv(name="POWERTOOLS_DEV", value="true") + logger = Logger(service=service_name, stream=stdout) + logger.info("Test message") + # THEN the json should contain more than line + new_lines = stdout.getvalue().count(os.linesep) + assert new_lines > 1