Skip to content

Commit cd4977e

Browse files
committed
defaults added
1 parent bc807f5 commit cd4977e

File tree

4 files changed

+39
-3
lines changed

4 files changed

+39
-3
lines changed

docs/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.2.0](https://github.com/nhairs/python-json-logger/compare/v3.1.0...v3.2.0) - 2024-09-10
8+
9+
### Changed
10+
- `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.
11+
712
## [3.1.0](https://github.com/nhairs/python-json-logger/compare/v3.0.1...v3.1.0) - 2023-05-28
813

914
This splits common funcitonality out to allow supporting other JSON encoders. Although this is a large refactor, backwards compatibility has been maintained.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "python-json-logger"
7-
version = "3.1.0"
7+
version = "3.2.0"
88
description = "JSON Log Formatter for the Python Logging Package"
99
authors = [
1010
{name = "Zakaria Zajac", email = "zak@madzak.com"},

src/pythonjsonlogger/core.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def merge_record_extra(
102102
target: Dict,
103103
reserved: Container[str],
104104
rename_fields: Optional[Dict[str, str]] = None,
105+
defaults: Optional[Dict[str, Any]] = None,
105106
) -> Dict:
106107
"""
107108
Merges extra attributes from LogRecord object into target dictionary
@@ -117,7 +118,8 @@ def merge_record_extra(
117118
"""
118119
if rename_fields is None:
119120
rename_fields = {}
120-
for key, value in record.__dict__.items():
121+
record_dict = record.__dict__ if not defaults else (defaults | record.__dict__)
122+
for key, value in record_dict.items():
121123
# this allows to have numeric keys
122124
if key not in reserved and not (hasattr(key, "startswith") and key.startswith("_")):
123125
target[rename_fields.get(key, key)] = value
@@ -161,7 +163,9 @@ def __init__(
161163
style: how to extract log fields from `fmt`
162164
validate: validate `fmt` against style, if implementing a custom `style` you
163165
must set this to `False`.
164-
defaults: ignored - kept for compatibility with python 3.10+
166+
defaults: a dictionary containing default values for unspecified
167+
extras. {"key": 1234} will add the key to the json if
168+
unspecified in the extras while logging a message.
165169
prefix: an optional string prefix added at the beginning of
166170
the formatted string
167171
rename_fields: an optional dict, used to rename field names in the output.
@@ -215,6 +219,7 @@ def __init__(
215219
self._required_fields = self.parse()
216220
self._skip_fields = set(self._required_fields)
217221
self._skip_fields.update(self.reserved_attrs)
222+
self.defaults = defaults
218223
return
219224

220225
def format(self, record: logging.LogRecord) -> str:
@@ -322,6 +327,7 @@ def add_fields(
322327
log_record,
323328
reserved=self._skip_fields,
324329
rename_fields=self.rename_fields,
330+
defaults=self.defaults,
325331
)
326332

327333
if self.timestamp:

tests/test_formatters.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,18 @@ def test_percentage_format(env: LoggingEnvironment, class_: type[BaseJsonFormatt
174174
return
175175

176176

177+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
178+
def test_defaults_field(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
179+
env.set_formatter(class_(defaults={"first": 1, "second": 2}))
180+
181+
env.logger.info("testing defaults field", extra={"first": 1234})
182+
log_json = env.load_json()
183+
184+
assert log_json["first"] == 1234
185+
assert log_json["second"] == 2
186+
return
187+
188+
177189
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
178190
def test_rename_base_field(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
179191
env.set_formatter(class_(rename_fields={"message": "@message"}))
@@ -186,6 +198,19 @@ def test_rename_base_field(env: LoggingEnvironment, class_: type[BaseJsonFormatt
186198
return
187199

188200

201+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
202+
def test_rename_with_defaults(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
203+
"""Make sure that the default fields are also renamed."""
204+
env.set_formatter(class_(rename_fields={"custom": "@custom"}, defaults={"custom": 1234}))
205+
206+
msg = "testing rename with defaults"
207+
env.logger.info(msg)
208+
log_json = env.load_json()
209+
210+
assert log_json["@custom"] == 1234
211+
return
212+
213+
189214
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
190215
def test_rename_missing(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
191216
env.set_formatter(class_(rename_fields={"missing_field": "new_field"}))

0 commit comments

Comments
 (0)