Skip to content

Commit b53b930

Browse files
authored
[core] Add support for comma format (#54)
Fixes #15 ### Test Plan - Unit tests
1 parent 0428e2b commit b53b930

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

docs/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
### Added
1010
- Support `DictConfigurator` prefixes for `rename_fields` and `static_fields`. [#45](https://github.com/nhairs/python-json-logger/pull/45)
1111
- Allows using values like `ext://sys.stderr` in `fileConfig`/`dictConfig` value fields.
12+
- Support comma seperated lists for Formatter `fmt` (`style=","`) e.g. `"asctime,message,levelname"` [#15](https://github.com/nhairs/python-json-logger/issues/15)
13+
- 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.
1214

1315
### Changed
1416
- Rename `pythonjsonlogger.core.LogRecord` and `log_record` arguments to avoid confusion / overlapping with `logging.LogRecord`. [#38](https://github.com/nhairs/python-json-logger/issues/38)

src/pythonjsonlogger/core.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,23 +175,31 @@ def __init__(
175175
- Renaming fields now preserves the order that fields were added in and avoids adding
176176
missing fields. The original behaviour, missing fields have a value of `None`, is still
177177
available by setting `rename_fields_keep_missing` to `True`.
178+
179+
*Added in 4.0*:
180+
181+
- `fmt` now supports comma seperated lists (`style=","`). Note that this style is specific
182+
to `python-json-logger` and thus care should be taken to not to pass this format to other
183+
logging Formatter implementations.
178184
"""
179185
## logging.Formatter compatibility
180186
## ---------------------------------------------------------------------
181-
# Note: validate added in 3.8, defaults added in 3.10
187+
# Note: validate added in python 3.8, defaults added in 3.10
182188
if style in logging._STYLES:
183189
_style = logging._STYLES[style][0](fmt) # type: ignore[operator]
184190
if validate:
185191
_style.validate()
186192
self._style = _style
187193
self._fmt = _style._fmt
188194

189-
elif not validate:
195+
elif style == "," or not validate:
190196
self._style = style
191197
self._fmt = fmt
192198

199+
# TODO: Validate comma format
200+
193201
else:
194-
raise ValueError(f"Style must be one of: {','.join(logging._STYLES.keys())}")
202+
raise ValueError("Style must be one of: '%{$,'")
195203

196204
self.datefmt = datefmt
197205

@@ -271,6 +279,12 @@ def parse(self) -> List[str]:
271279
Returns:
272280
list of fields to be extracted and serialized
273281
"""
282+
if self._fmt is None:
283+
return []
284+
285+
if isinstance(self._style, str) and self._style == ",":
286+
return [field.strip() for field in self._fmt.split(",") if field.strip()]
287+
274288
if isinstance(self._style, logging.StringTemplateStyle):
275289
formatter_style_pattern = STYLE_STRING_TEMPLATE_REGEX
276290

@@ -285,10 +299,7 @@ def parse(self) -> List[str]:
285299
else:
286300
raise ValueError(f"Style {self._style!r} is not supported")
287301

288-
if self._fmt:
289-
return formatter_style_pattern.findall(self._fmt)
290-
291-
return []
302+
return formatter_style_pattern.findall(self._fmt)
292303

293304
def serialize_log_record(self, log_data: LogData) -> str:
294305
"""Returns the final representation of the data to be logged

tests/test_formatters.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,22 @@ def test_default_format(env: LoggingEnvironment, class_: type[BaseJsonFormatter]
158158

159159
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
160160
def test_percentage_format(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
161-
env.set_formatter(
162-
class_(
163-
# All kind of different styles to check the regex
164-
"[%(levelname)8s] %(message)s %(filename)s:%(lineno)d %(asctime)"
165-
)
166-
)
161+
# Note: We use different %s styles in the format to check the regex correctly collects them
162+
env.set_formatter(class_("[%(levelname)8s] %(message)s %(filename)s:%(lineno)d %(asctime)"))
163+
164+
msg = "testing logging format"
165+
env.logger.info(msg)
166+
log_json = env.load_json()
167+
168+
assert log_json["message"] == msg
169+
assert log_json.keys() == {"levelname", "message", "filename", "lineno", "asctime"}
170+
return
171+
172+
173+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
174+
def test_comma_format(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
175+
# Note: we have double comma `,,` to test handling "empty" names
176+
env.set_formatter(class_("levelname,,message,filename,lineno,asctime,", style=","))
167177

168178
msg = "testing logging format"
169179
env.logger.info(msg)

0 commit comments

Comments
 (0)