Skip to content

Commit bb4647f

Browse files
authored
Add default/fallback behavior for json.dumps (#47)
* Add test case * Add default/fallback behavior for json.dumps * CHANGELOG * Collapse duplicate json.dumps kwargs * Update precommit * Remove whitespace * Add more pre-commit (black, flake8, mypy) * Fix mypy * Update pre-commit
1 parent 850c9cb commit bb4647f

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

.pre-commit-config.yaml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v2.2.3
3+
rev: v4.0.1
44
hooks:
55
- id: check-case-conflict
66
- id: check-executables-have-shebangs
77
- id: check-merge-conflict
8-
98
- repo: [email protected]:elastic/apm-pipeline-library
109
rev: current
1110
hooks:
1211
- id: check-bash-syntax
1312
- id: check-jenkins-pipelines
1413
- id: check-jjbb
14+
- repo: https://github.com/pre-commit/mirrors-mypy
15+
rev: v0.910
16+
hooks:
17+
- id: mypy
18+
args: [--strict]
19+
- repo: https://github.com/ambv/black
20+
rev: 21.6b0
21+
hooks:
22+
- id: black
23+
language_version: python3
24+
- repo: https://gitlab.com/pycqa/flake8
25+
rev: 3.9.2
26+
hooks:
27+
- id: flake8
28+
exclude: tests|conftest.py|setup.py

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Fixed an issue in `StructlogFormatter` caused by a conflict with `event`
66
(used for the log `message`) and `event.dataset` (a field provided by the
77
`elasticapm` integration) ([#46](https://github.com/elastic/ecs-logging-python/pull/46))
8+
* Add default/fallback handling for json.dumps ([#47](https://github.com/elastic/ecs-logging-python/pull/47))
89

910
## 1.0.0 (2021-02-08)
1011

ecs_logging/_utils.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# under the License.
1717

1818
import json
19+
import functools
1920

2021
try:
2122
import typing
@@ -152,24 +153,45 @@ def json_dumps(value):
152153
except KeyError:
153154
pass
154155

156+
json_dumps = functools.partial(
157+
json.dumps, sort_keys=True, separators=(",", ":"), default=_json_dumps_fallback
158+
)
159+
155160
# Because we want to use 'sorted_keys=True' we manually build
156161
# the first three keys and then build the rest with json.dumps()
157162
if ordered_fields:
158163
# Need to call json.dumps() on values just in
159164
# case the given values aren't strings (even though
160165
# they should be according to the spec)
161166
ordered_json = ",".join(
162-
'"%s":%s' % (k, json.dumps(v, sort_keys=True, separators=(",", ":")))
167+
'"%s":%s'
168+
% (
169+
k,
170+
json_dumps(v),
171+
)
163172
for k, v in ordered_fields
164173
)
165174
if value:
166175
return "{%s,%s" % (
167176
ordered_json,
168-
json.dumps(value, sort_keys=True, separators=(",", ":"))[1:],
177+
json_dumps(value)[1:],
169178
)
170179
else:
171180
return "{%s}" % ordered_json
172181
# If there are no fields with ordering requirements we
173182
# pass everything into json.dumps()
174183
else:
175-
return json.dumps(value, sort_keys=True, separators=(",", ":"))
184+
return json_dumps(value)
185+
186+
187+
def _json_dumps_fallback(value):
188+
# type: (Any) -> Any
189+
"""
190+
Fallback handler for json.dumps to handle objects json doesn't know how to
191+
serialize.
192+
"""
193+
try:
194+
# This is what structlog's json fallback does
195+
return value.__structlog__()
196+
except AttributeError:
197+
return repr(value)

tests/test_structlog_formatter.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,18 @@
2323
import pytest
2424

2525

26+
class NotSerializable:
27+
def __repr__(self):
28+
return "<NotSerializable>"
29+
30+
2631
def make_event_dict():
2732
return {
2833
"event": "test message",
2934
"event.dataset": "agent.log",
3035
"log.logger": "logger-name",
3136
"foo": "bar",
37+
"baz": NotSerializable(),
3238
}
3339

3440

@@ -47,7 +53,9 @@ def test_event_dict_formatted(time, spec_validator):
4753
formatter = ecs_logging.StructlogFormatter()
4854
assert spec_validator(formatter(None, "debug", make_event_dict())) == (
4955
'{"@timestamp":"2020-03-20T16:16:37.187Z","log.level":"debug",'
50-
'"message":"test message","ecs":{"version":"1.6.0"},'
56+
'"message":"test message",'
57+
'"baz":"<NotSerializable>",'
58+
'"ecs":{"version":"1.6.0"},'
5159
'"event":{"dataset":"agent.log"},'
5260
'"foo":"bar",'
5361
'"log":{"logger":"logger-name"}}'

0 commit comments

Comments
 (0)