Skip to content

[core] Add support for comma format #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: nhairs-log-record
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Support `DictConfigurator` prefixes for `rename_fields` and `static_fields`. [#45](https://github.com/nhairs/python-json-logger/pull/45)
- Allows using values like `ext://sys.stderr` in `fileConfig`/`dictConfig` value fields.
- Support comma seperated lists for Formatter `fmt` (`style=","`) e.g. `"asctime,message,levelname"` [#15](https://github.com/nhairs/python-json-logger/issues/15)
- Note that this style is specific to `python-json-logger` and thus care should be taken not to pass this format to other logging Formatter implementations.

### Changed
- Rename `pythonjsonlogger.core.LogRecord` and `log_record` arguemtns to avoid confusion / overlapping with `logging.LogRecord`. [#38](https://github.com/nhairs/python-json-logger/issues/38)
Expand Down
25 changes: 20 additions & 5 deletions src/pythonjsonlogger/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ def __init__(
- Renaming fields now preserves the order that fields were added in and avoids adding
missing fields. The original behaviour, missing fields have a value of `None`, is still
available by setting `rename_fields_keep_missing` to `True`.

*Added in 4.0*:

- `fmt` now supports comma seperated lists (`style=","`). Note that this style is specific
to `python-json-logger` and thus care should be taken to not to pass this format to other
logging Formatter implementations.
"""
## logging.Formatter compatibility
## ---------------------------------------------------------------------
Expand All @@ -186,7 +192,7 @@ def __init__(
self._style = _style
self._fmt = _style._fmt

elif not validate:
elif style == "," or not validate:
self._style = style
self._fmt = fmt

Expand Down Expand Up @@ -271,6 +277,18 @@ def parse(self) -> List[str]:
Returns:
list of fields to be extracted and serialized
"""
if self._fmt is None:
# TODO: does it matter that we do this before checking if the style is valid?
# (we already (mostly) check for valid style names in __init__
return []
Comment on lines +280 to +283
Copy link
Owner Author

@nhairs nhairs May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter that we do this before checking if the style is valid?
We already (mostly) check for valid style names in __init__


if isinstance(self._style, str) and self._style == ",":
# TODO: should we check that there are no empty fields?
# If yes we should do this in __init__ where we validate other styles?
# Do we drop empty fields?
# etc
return [field.strip() for field in self._fmt.split(",") if field.strip()]
Comment on lines +285 to +290
Copy link
Owner Author

@nhairs nhairs May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that there are no empty fields?
If yes we should do this in __init__ where we validate other styles?
Is it okay that we drop empty fields?
etc


if isinstance(self._style, logging.StringTemplateStyle):
formatter_style_pattern = STYLE_STRING_TEMPLATE_REGEX

Expand All @@ -285,10 +303,7 @@ def parse(self) -> List[str]:
else:
raise ValueError(f"Style {self._style!r} is not supported")
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs updating. Probably need to find a different representation since $,%,{,, isn't exactly intuitive...


if self._fmt:
return formatter_style_pattern.findall(self._fmt)

return []
return formatter_style_pattern.findall(self._fmt)

def serialize_log_record(self, log_data: LogData) -> str:
"""Returns the final representation of the data to be logged
Expand Down
22 changes: 16 additions & 6 deletions tests/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,22 @@ def test_default_format(env: LoggingEnvironment, class_: type[BaseJsonFormatter]

@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_percentage_format(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
env.set_formatter(
class_(
# All kind of different styles to check the regex
"[%(levelname)8s] %(message)s %(filename)s:%(lineno)d %(asctime)"
)
)
# Note: All kind of different %s styles to check the regex
env.set_formatter(class_("[%(levelname)8s] %(message)s %(filename)s:%(lineno)d %(asctime)"))

msg = "testing logging format"
env.logger.info(msg)
log_json = env.load_json()

assert log_json["message"] == msg
assert log_json.keys() == {"levelname", "message", "filename", "lineno", "asctime"}
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_comma_format(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
# Note: we have double comma `,,` to test handling "empty" names
env.set_formatter(class_("levelname,,message,filename,lineno,asctime,", style=","))

msg = "testing logging format"
env.logger.info(msg)
Expand Down