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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ coverage.xml
docs/_build
build
dist
*.pyc
7 changes: 6 additions & 1 deletion src/dockerflow/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
import traceback


class SafeJSONEncoder(json.JSONEncoder):
def default(self, o):
return repr(o)


class JsonLogFormatter(logging.Formatter):
"""Log formatter that outputs machine-readable json.

Expand Down Expand Up @@ -85,7 +90,7 @@ def format(self, record):

out['Fields'] = fields

return json.dumps(out)
return json.dumps(out, cls=SafeJSONEncoder)


def safer_format_traceback(exc_typ, exc_val, exc_tb):
Expand Down
14 changes: 14 additions & 0 deletions tests/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ def test_custom_paramters(caplog):
assert details['Fields']['more'] == 'stuff'


def test_non_json_serializable_parameters_are_converted(caplog):
"""Ensure log formatter doesn't fail with non json-serializable params."""
foo = object()
foo_repr = repr(foo)
logger = logging.getLogger('dockerflow.test.test_logging')
logger.warning('custom test %s', 'hello', extra={'foo': foo})
details = assert_records(caplog.records)

assert details['Type'] == 'dockerflow.test.test_logging'
assert details['Severity'] == 4
assert details['Fields']['message'] == 'custom test hello'
assert details['Fields']['foo'] == foo_repr


def test_logging_error_tracebacks(caplog):
"""Ensure log formatter includes exception traceback information"""
try:
Expand Down