Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- `pythonjsonlogger.[ORJSON,MSGSPEC]_AVAILABLE` no longer imports the respective package when determining availability.
- `pythonjsonlogger.[orjson,msgspec]` now throws a `pythonjsonlogger.exception.MissingPackageError` when required libraries are not available. These contain more information about what is missing whilst still being an `ImportError`.
- `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

Expand Down
12 changes: 12 additions & 0 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ logger.info(

Finally, any non-standard attributes added to a `LogRecord` will also be included in the logged data. See [Cookbook: Request / Trace IDs](cookbook.md#request-trace-ids) for an example.

#### Default Fields

Default fields that are added to every log record prior to any other field can be set using the `default` argument.

```python
formatter = JsonFormatter(
defaults={"environment": "dev"}
)
# ...
logger.info("this overwrites the environment field", extras={"environment": "dev"})
```

#### Static Fields

Static fields that are added to every log record can be set using the `static_fields` argument.
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.dev1"
description = "JSON Log Formatter for the Python Logging Package"
authors = [
{name = "Zakaria Zajac", email = "zak@madzak.com"},
Expand Down
9 changes: 8 additions & 1 deletion src/pythonjsonlogger/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ class BaseJsonFormatter(logging.Formatter):
Must not be used directly.

*New in 3.1*

*Changed in 3.2*: `defaults` argument is no longer ignored.
"""

_style: Union[logging.PercentStyle, str] # type: ignore[assignment]
Expand Down Expand Up @@ -161,7 +163,8 @@ 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 fields that are added before all other fields and
may be overridden. The supplied fields are still subject to `rename_fields`.
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 +218,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 if defaults is not None else {}
return

def format(self, record: logging.LogRecord) -> str:
Expand Down Expand Up @@ -310,6 +314,9 @@ def add_fields(
message_dict: dictionary that was logged instead of a message. e.g
`logger.info({"is_this_message_dict": True})`
"""
for field in self.defaults:
log_record[self._get_rename(field)] = self.defaults[field]

for field in self._required_fields:
log_record[self._get_rename(field)] = record.__dict__.get(field)

Expand Down
39 changes: 39 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,20 @@ 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
assert "custom" not in log_json
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 Expand Up @@ -321,6 +347,19 @@ def test_log_dict(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_log_dict_defaults(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
env.set_formatter(class_(defaults={"d1": 1234, "d2": "hello"}))

msg = {"d2": "world"}
env.logger.info(msg)
log_json = env.load_json()

assert log_json["d1"] == 1234
assert log_json["d2"] == "world"
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_log_extra(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
env.set_formatter(class_())
Expand Down
Loading