Skip to content

Commit b8f094b

Browse files
authored
Handle exc_info=False in logging formatter (#48)
https://docs.python.org/3/library/logging.html#logrecord-objects mentions exc_info should be a tuple or None, but False can be passed to a log statement according to https://docs.python.org/3/library/logging.html#logging.debug and when that happens, the exc_info on the LogRecord object *will* be False as well, so we need to handle that to avoid crashing.
1 parent 02e94f6 commit b8f094b

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

src/dockerflow/logging.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def convert_record(self, record):
123123
fields["msg"] = message
124124

125125
# If there is an error, format it for nice output.
126-
if record.exc_info is not None:
126+
if record.exc_info:
127127
fields["error"] = repr(record.exc_info[1])
128128
fields["traceback"] = safer_format_traceback(*record.exc_info)
129129

tests/core/test_logging.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import logging
66
import logging.config
77
import os
8+
import sys
89
import textwrap
910

1011
import jsonschema
12+
import pytest
1113
from dockerflow.logging import JsonLogFormatter
1214

1315
logger_name = "tests"
@@ -116,6 +118,41 @@ def test_logging_error_tracebacks(caplog):
116118
assert "ValueError" in details["Fields"]["traceback"]
117119

118120

121+
@pytest.mark.skipif(sys.version_info < (3, 5), reason="Requires python >= 3.5")
122+
def test_logging_exc_info_false_3x(caplog):
123+
"""Ensure log formatter does not fail and does not include exception
124+
traceback information when exc_info is False under Python 3.x"""
125+
try:
126+
raise ValueError("\n")
127+
except Exception:
128+
logging.exception("there was an error", exc_info=False)
129+
details = assert_records(caplog.records)
130+
131+
assert details["Severity"] == 3
132+
assert details["Fields"]["msg"] == "there was an error"
133+
assert "error" not in details["Fields"]
134+
assert "traceback" not in details["Fields"]
135+
136+
137+
@pytest.mark.skipif(sys.version_info >= (3,), reason="Requires python 2")
138+
def test_logging_exc_info_false_2x(caplog):
139+
"""Ensure log formatter does not fail *but* still includes exception
140+
traceback information when exc_info is False under Python 2.x"""
141+
try:
142+
raise ValueError("\n")
143+
except Exception:
144+
logging.exception("there was an error", exc_info=False)
145+
details = assert_records(caplog.records)
146+
147+
assert details["Severity"] == 3
148+
assert details["Fields"]["msg"] == "there was an error"
149+
# In Python 2, when exc_info=False is passed, we still see a tuple in the
150+
# formatter, so we still include the error and traceback keys.
151+
assert details["Fields"]["error"].startswith("ValueError('\\n'")
152+
assert details["Fields"]["traceback"].startswith("Uncaught exception:")
153+
assert "ValueError" in details["Fields"]["traceback"]
154+
155+
119156
def test_ignore_json_message(caplog):
120157
"""Ensure log formatter ignores messages that are JSON already"""
121158
try:

0 commit comments

Comments
 (0)