Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.2.0](https://github.com/nhairs/python-json-logger/compare/v3.1.0...v3.2.0) - 2024-09-10

### Changed
- `defaults` parameter is no longer ignored and now conforms to the standard library. Setting a defaults dictionary will add the specified keys if the those keys do not exist in a record or weren't passed by the `extra` parameter when logging a message.

## [3.1.0](https://github.com/nhairs/python-json-logger/compare/v3.0.1...v3.1.0) - 2023-05-28

This splits common funcitonality out to allow supporting other JSON encoders. Although this is a large refactor, backwards compatibility has been maintained.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "python-json-logger"
version = "3.1.0"
version = "3.2.0"
description = "JSON Log Formatter for the Python Logging Package"
authors = [
{name = "Zakaria Zajac", email = "zak@madzak.com"},
Expand Down
10 changes: 8 additions & 2 deletions src/pythonjsonlogger/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def merge_record_extra(
target: Dict,
reserved: Container[str],
rename_fields: Optional[Dict[str, str]] = None,
defaults: Optional[Dict[str, Any]] = None,
) -> Dict:
"""
Merges extra attributes from LogRecord object into target dictionary
Expand All @@ -117,7 +118,8 @@ def merge_record_extra(
"""
if rename_fields is None:
rename_fields = {}
for key, value in record.__dict__.items():
record_dict = record.__dict__ if not defaults else (defaults | record.__dict__)
for key, value in record_dict.items():
# this allows to have numeric keys
if key not in reserved and not (hasattr(key, "startswith") and key.startswith("_")):
target[rename_fields.get(key, key)] = value
Expand Down Expand Up @@ -161,7 +163,9 @@ def __init__(
style: how to extract log fields from `fmt`
validate: validate `fmt` against style, if implementing a custom `style` you
must set this to `False`.
defaults: ignored - kept for compatibility with python 3.10+
defaults: a dictionary containing default values for unspecified
extras. {"key": 1234} will add the key to the json if
unspecified in the extras while logging a message.
prefix: an optional string prefix added at the beginning of
the formatted string
rename_fields: an optional dict, used to rename field names in the output.
Expand Down Expand Up @@ -215,6 +219,7 @@ def __init__(
self._required_fields = self.parse()
self._skip_fields = set(self._required_fields)
self._skip_fields.update(self.reserved_attrs)
self.defaults = defaults
return

def format(self, record: logging.LogRecord) -> str:
Expand Down Expand Up @@ -322,6 +327,7 @@ def add_fields(
log_record,
reserved=self._skip_fields,
rename_fields=self.rename_fields,
defaults=self.defaults,
)

if self.timestamp:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,18 @@ def test_percentage_format(env: LoggingEnvironment, class_: type[BaseJsonFormatt
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_defaults_field(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
env.set_formatter(class_(defaults={"first": 1, "second": 2}))

env.logger.info("testing defaults field", extra={"first": 1234})
log_json = env.load_json()

assert log_json["first"] == 1234
assert log_json["second"] == 2
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_rename_base_field(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
env.set_formatter(class_(rename_fields={"message": "@message"}))
Expand All @@ -186,6 +198,19 @@ def test_rename_base_field(env: LoggingEnvironment, class_: type[BaseJsonFormatt
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_rename_with_defaults(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
"""Make sure that the default fields are also renamed."""
env.set_formatter(class_(rename_fields={"custom": "@custom"}, defaults={"custom": 1234}))

msg = "testing rename with defaults"
env.logger.info(msg)
log_json = env.load_json()

assert log_json["@custom"] == 1234
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_rename_missing(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
env.set_formatter(class_(rename_fields={"missing_field": "new_field"}))
Expand Down