Skip to content

Commit 904ac69

Browse files
committed
Add support for default key/value pairs; Fix duplicate keys issue
1 parent 8a87cdb commit 904ac69

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,25 @@ logging.basicConfig(handlers=[handler])
208208
logging.error({"example": True}) # at=ERROR example=yes
209209
```
210210

211+
### Default Key/Value Pairs
212+
213+
Instead of providing key/value pairs at each log call, you can override
214+
the log record factory to provide defaults:
215+
216+
```py
217+
_record_factory = logging.getLogRecordFactory()
218+
219+
def record_factory(*args, **kwargs):
220+
record = _record_factory(*args, **kwargs)
221+
record.trace_id = 123
222+
return record
223+
224+
logging.setLogRecordFactory(record_factory)
225+
```
226+
227+
This will cause all logs to have the `trace_id=123` pair regardless of including
228+
`trace_id` in keys or manually adding `trace_id` to the `extra` parameter or the `msg` object.
229+
211230
## Development
212231

213232
### Required Software

src/logfmter/formatter.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,9 @@ def format(self, record: logging.LogRecord) -> str:
161161
self.normalize_key(key): value for key, value in record.msg.items()
162162
}
163163
else:
164-
extra = self.get_extra(record)
165-
params = {"msg": record.getMessage(), **extra}
164+
params = {"msg": record.getMessage()}
165+
166+
params.update(self.get_extra(record))
166167

167168
tokens = []
168169

@@ -181,6 +182,11 @@ def format(self, record: logging.LogRecord) -> str:
181182
if key in self.mapping:
182183
attribute = self.mapping[key]
183184

185+
# If this key is in params, then skip it, because it was manually passed in
186+
# will be added via the params system.
187+
if attribute in params:
188+
continue
189+
184190
# If the attribute doesn't exist on the log record, then skip it.
185191
if not hasattr(record, attribute):
186192
continue

tests/test_formatter.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,24 @@ def test_format_datefmt():
245245

246246
asctime = re.search(r'asctime="(.*)"', value).group(1)
247247
datetime.strptime(asctime, " %H ")
248+
249+
250+
@pytest.mark.parametrize(
251+
"record",
252+
[
253+
{"msg": "alpha", "levelname": "INFO"},
254+
{"msg": {"msg": "alpha"}, "levelname": "INFO"},
255+
],
256+
)
257+
def test_extra_keys(record):
258+
"""
259+
When attributes are added directly to the `logging.LogRecord` object, they should
260+
be included in the output and not be duplicated, regardless of a str or dict based
261+
msg object.
262+
"""
263+
record = logging.makeLogRecord(record)
264+
record.attr = "value"
265+
266+
assert (
267+
Logfmter(keys=["at", "attr"]).format(record) == "at=INFO msg=alpha attr=value"
268+
)

0 commit comments

Comments
 (0)