Skip to content

Commit de90726

Browse files
committed
Fix NewRelicContextFormatter bug
Previously, there was a bug in NewRelicContextFormatter where "message" was added to the default set of keys to exclude. This made the default key list (default keys + 1) in length. Since the logic check was based on the length, rather than presence of certain keys, anything that had one extra key than the default would not have that extra key added to the ouput because the length would match the (default keys + 1) length. The length check is a bit odd here as it leads to a bug in the implementation. Instead, let's check for presence of keys which is more reflective of our intended goal than checking the length.
1 parent 56fbda1 commit de90726

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

newrelic/api/log.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,11 @@ def log_record_to_dict(cls, record):
8989
output.update(get_linking_metadata())
9090

9191
DEFAULT_LOG_RECORD_KEYS = cls.DEFAULT_LOG_RECORD_KEYS
92-
if len(record.__dict__) > len(DEFAULT_LOG_RECORD_KEYS):
93-
for key in record.__dict__:
94-
if key not in DEFAULT_LOG_RECORD_KEYS:
95-
output["extra." + key] = getattr(record, key)
92+
# If any keys are present in record that aren't in the default,
93+
# add them to the output record.
94+
keys_to_add = set(record.__dict__.keys()) - DEFAULT_LOG_RECORD_KEYS
95+
for key in keys_to_add:
96+
output["extra." + key] = getattr(record, key)
9697

9798
if record.exc_info:
9899
output.update(format_exc_info(record.exc_info))

tests/agent_features/test_logs_in_context.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,48 @@ def __str__(self):
6161
__repr__ = __str__
6262

6363

64+
def test_newrelic_logger_min_extra_keys_no_error(log_buffer):
65+
extra = {
66+
"string": "foo",
67+
}
68+
_logger.info("Hello %s", "World", extra=extra)
69+
70+
log_buffer.seek(0)
71+
message = json.load(log_buffer)
72+
73+
timestamp = message.pop("timestamp")
74+
thread_id = message.pop("thread.id")
75+
process_id = message.pop("process.id")
76+
filename = message.pop("file.name")
77+
line_number = message.pop("line.number")
78+
79+
assert isinstance(timestamp, int)
80+
assert isinstance(thread_id, int)
81+
assert isinstance(process_id, int)
82+
assert filename.endswith("/test_logs_in_context.py")
83+
assert isinstance(line_number, int)
84+
85+
expected = {
86+
"entity.name": "Python Agent Test (agent_features)",
87+
"entity.type": "SERVICE",
88+
"message": "Hello World",
89+
"log.level": "INFO",
90+
"logger.name": "test_logs_in_context",
91+
"thread.name": "MainThread",
92+
"process.name": "MainProcess",
93+
"extra.string": "foo",
94+
}
95+
expected_extra_txn_keys = (
96+
"entity.guid",
97+
"hostname",
98+
)
99+
100+
for k, v in expected.items():
101+
assert message.pop(k) == v
102+
103+
assert set(message.keys()) == set(expected_extra_txn_keys)
104+
105+
64106
def test_newrelic_logger_no_error(log_buffer):
65107
extra = {
66108
"string": "foo",

0 commit comments

Comments
 (0)