Skip to content

Commit db04a0f

Browse files
1hakusai1nhairs
andauthored
Add options to encode stack information into an array (#39)
close #35 This PR add options to encode stack information into an array. - If `exc_info_as_array` is True (Defualt: False), formatter encode `exc_info` into an array. - If `stack_info_as_array` is True (Defualt: False), formatter encode `stack_info` into an array. ### Test plan - run tests --------- Co-authored-by: Nicholas Hairs <[email protected]>
1 parent 0092ea0 commit db04a0f

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

docs/changelog.md

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ 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+
## [UNRELEASED]
8+
9+
### Added
10+
- `exc_info_as_array` and `stack_info_as_array` options are added to `pythonjsonlogger.core.BaseJsonFormatter`.
11+
- If `exc_info_as_array` is True (Defualt: False), formatter encode exc_info into an array.
12+
- If `stack_info_as_array` is True (Defualt: False), formatter encode stack_info into an array.
13+
714
## [3.2.1](https://github.com/nhairs/python-json-logger/compare/v3.2.0...v3.2.1) - 2024-12-16
815

916
### Fixed

src/pythonjsonlogger/core.py

+24
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ class BaseJsonFormatter(logging.Formatter):
134134
*New in 3.1*
135135
136136
*Changed in 3.2*: `defaults` argument is no longer ignored.
137+
138+
*Added in UNRELEASED*: `exc_info_as_array` and `stack_info_as_array` options are added.
137139
"""
138140

139141
_style: Union[logging.PercentStyle, str] # type: ignore[assignment]
@@ -155,6 +157,8 @@ def __init__(
155157
reserved_attrs: Optional[Sequence[str]] = None,
156158
timestamp: Union[bool, str] = False,
157159
defaults: Optional[Dict[str, Any]] = None,
160+
exc_info_as_array: bool = False,
161+
stack_info_as_array: bool = False,
158162
) -> None:
159163
"""
160164
Args:
@@ -177,6 +181,8 @@ def __init__(
177181
outputting the json log record. If string is passed, timestamp will be added
178182
to log record using string as key. If True boolean is passed, timestamp key
179183
will be "timestamp". Defaults to False/off.
184+
exc_info_as_array: break the exc_info into a list of lines based on line breaks.
185+
stack_info_as_array: break the stack_info into a list of lines based on line breaks.
180186
181187
*Changed in 3.1*:
182188
@@ -219,6 +225,8 @@ def __init__(
219225
self._skip_fields = set(self._required_fields)
220226
self._skip_fields.update(self.reserved_attrs)
221227
self.defaults = defaults if defaults is not None else {}
228+
self.exc_info_as_array = exc_info_as_array
229+
self.stack_info_as_array = stack_info_as_array
222230
return
223231

224232
def format(self, record: logging.LogRecord) -> str:
@@ -368,3 +376,19 @@ def process_log_record(self, log_record: LogRecord) -> LogRecord:
368376
log_record: incoming data
369377
"""
370378
return log_record
379+
380+
def formatException(self, ei) -> Union[str, list[str]]: # type: ignore
381+
"""Format and return the specified exception information.
382+
383+
If exc_info_as_array is set to True, This method returns an array of strings.
384+
"""
385+
exception_info_str = super().formatException(ei)
386+
return exception_info_str.splitlines() if self.exc_info_as_array else exception_info_str
387+
388+
def formatStack(self, stack_info) -> Union[str, list[str]]: # type: ignore
389+
"""Format and return the specified stack information.
390+
391+
If stack_info_as_array is set to True, This method returns an array of strings.
392+
"""
393+
stack_info_str = super().formatStack(stack_info)
394+
return stack_info_str.splitlines() if self.stack_info_as_array else stack_info_str

tests/test_formatters.py

+49
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,55 @@ def custom_default(obj):
622622
return
623623

624624

625+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
626+
def test_exc_info_as_array(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
627+
env.set_formatter(class_(exc_info_as_array=True))
628+
629+
try:
630+
raise Exception("Error")
631+
except BaseException:
632+
env.logger.exception("Error occurs")
633+
log_json = env.load_json()
634+
635+
assert isinstance(log_json["exc_info"], list)
636+
return
637+
638+
639+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
640+
def test_exc_info_as_array_no_exc_info(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
641+
env.set_formatter(class_(exc_info_as_array=True))
642+
643+
env.logger.info("hello")
644+
log_json = env.load_json()
645+
646+
assert "exc_info" not in log_json
647+
return
648+
649+
650+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
651+
def test_stack_info_as_array(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
652+
env.set_formatter(class_(stack_info_as_array=True))
653+
654+
env.logger.info("hello", stack_info=True)
655+
log_json = env.load_json()
656+
657+
assert isinstance(log_json["stack_info"], list)
658+
return
659+
660+
661+
@pytest.mark.parametrize("class_", ALL_FORMATTERS)
662+
def test_stack_info_as_array_no_stack_info(
663+
env: LoggingEnvironment, class_: type[BaseJsonFormatter]
664+
):
665+
env.set_formatter(class_(stack_info_as_array=True))
666+
667+
env.logger.info("hello", stack_info=False)
668+
log_json = env.load_json()
669+
670+
assert "stack_info" not in log_json
671+
return
672+
673+
625674
## JsonFormatter Specific
626675
## -----------------------------------------------------------------------------
627676
def test_json_ensure_ascii_true(env: LoggingEnvironment):

0 commit comments

Comments
 (0)