Skip to content

Commit 3544608

Browse files
authored
Fix logging integrations with non-string messages (#179)
1 parent 01b1158 commit 3544608

File tree

6 files changed

+77
-9
lines changed

6 files changed

+77
-9
lines changed

logfire/_internal/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,11 @@ def log(
564564
# Only do this if extra_attrs is not empty since the copy of `attributes` might be expensive.
565565
# We update both because attributes_json_schema_properties looks at `attributes`.
566566
attributes = {**attributes, **extra_attrs}
567+
else:
568+
# The message has already been filled in, presumably by a logging integration.
569+
# Make sure it's a string.
570+
msg = merged_attributes[ATTRIBUTES_MESSAGE_KEY] = str(msg)
571+
msg_template = str(msg_template)
567572

568573
otlp_attributes = user_attributes(merged_attributes)
569574
otlp_attributes = {

logfire/integrations/loguru.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def fill_attributes(self, record: LogRecord) -> dict[str, Any]:
3838
while frame: # pragma: no branch
3939
if frame.f_code is _LOG_METHOD_CODE:
4040
msg_template = frame.f_locals.get('message')
41-
if isinstance(msg_template, str):
41+
if msg_template is not None:
4242
attributes[ATTRIBUTES_MESSAGE_TEMPLATE_KEY] = msg_template
4343
else: # pragma: no cover
4444
_warn_inspection_failure()

logfire/integrations/structlog.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import logfire
66

7+
from .._internal.constants import ATTRIBUTES_MESSAGE_KEY
78
from .logging import RESERVED_ATTRS as LOGGING_RESERVED_ATTRS
89

910
RESERVED_ATTRS = LOGGING_RESERVED_ATTRS | {'level', 'event', 'timestamp'}
@@ -21,10 +22,10 @@ def __call__(self, logger: WrappedLogger, name: str, event_dict: EventDict) -> E
2122
attributes = {k: v for k, v in event_dict.items() if k not in RESERVED_ATTRS}
2223
level = event_dict.get('level', 'info').lower()
2324
# NOTE: An event can be `None` in structlog. We may want to create a default msg in those cases.
24-
msg_template = event_dict.get('event') or 'structlog event'
25+
attributes[ATTRIBUTES_MESSAGE_KEY] = message = event_dict.get('event') or 'structlog event'
2526
logfire.log(
2627
level=level, # type: ignore
27-
msg_template=msg_template,
28+
msg_template=message,
2829
attributes=attributes,
2930
console_log=self.console_log,
3031
custom_scope_suffix='structlog',

tests/test_loguru.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ def test_loguru(exporter: TestExporter) -> None:
2222

2323
try:
2424
raise ValueError('This is a test exception')
25-
except ValueError:
25+
except ValueError as e:
2626
logger.exception('An exception was raised: {foo}', foo='bar')
27+
# Test logging a non-string message.
28+
logger.warning(e)
2729

2830
assert exporter.exported_spans_as_dict(fixed_line_number=None) == snapshot(
2931
[
@@ -93,5 +95,21 @@ def test_loguru(exporter: TestExporter) -> None:
9395
}
9496
],
9597
},
98+
{
99+
'name': 'This is a test exception',
100+
'context': {'trace_id': 4, 'span_id': 4, 'is_remote': False},
101+
'parent': None,
102+
'start_time': 5000000000,
103+
'end_time': 5000000000,
104+
'attributes': {
105+
'logfire.span_type': 'log',
106+
'logfire.level_num': 13,
107+
'logfire.msg_template': 'This is a test exception',
108+
'logfire.msg': 'This is a test exception',
109+
'code.filepath': 'test_loguru.py',
110+
'code.function': 'test_loguru',
111+
'code.lineno': 28,
112+
},
113+
},
96114
]
97115
)

tests/test_stdlib_logging.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,28 @@ def test_logging_from_opentelemetry(exporter: TestExporter) -> None:
277277
},
278278
]
279279
)
280+
281+
282+
def test_logging_non_string(exporter: TestExporter, logger: Logger):
283+
logger.error(123)
284+
285+
assert exporter.exported_spans_as_dict() == snapshot(
286+
[
287+
{
288+
'name': '123',
289+
'context': {'trace_id': 1, 'span_id': 1, 'is_remote': False},
290+
'parent': None,
291+
'start_time': 1000000000,
292+
'end_time': 1000000000,
293+
'attributes': {
294+
'logfire.span_type': 'log',
295+
'logfire.level_num': 17,
296+
'logfire.msg_template': '123',
297+
'logfire.msg': '123',
298+
'code.filepath': 'test_stdlib_logging.py',
299+
'code.function': 'test_logging_non_string',
300+
'code.lineno': 123,
301+
},
302+
}
303+
]
304+
)

tests/test_structlog.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,44 @@ def logger() -> Any:
3030

3131

3232
def test_structlog(exporter: TestExporter, logger: Logger) -> None:
33-
logger.info('This is now being logged.')
33+
logger.info('This is now being logged: %s', 123)
34+
logger.error(456)
35+
3436
assert exporter.exported_spans_as_dict(fixed_line_number=None) == snapshot(
3537
[
3638
{
37-
'name': 'This is now being logged.',
39+
'name': 'This is now being logged: 123',
3840
'context': {'trace_id': 1, 'span_id': 1, 'is_remote': False},
3941
'parent': None,
4042
'start_time': 1000000000,
4143
'end_time': 1000000000,
4244
'attributes': {
4345
'logfire.span_type': 'log',
4446
'logfire.level_num': 9,
45-
'logfire.msg_template': 'This is now being logged.',
46-
'logfire.msg': 'This is now being logged.',
47+
'logfire.msg_template': 'This is now being logged: 123',
48+
'logfire.msg': 'This is now being logged: 123',
4749
'code.filepath': 'test_structlog.py',
4850
'code.function': 'test_structlog',
4951
'code.lineno': 33,
5052
'logfire.disable_console_log': True,
5153
},
52-
}
54+
},
55+
{
56+
'name': '456',
57+
'context': {'trace_id': 2, 'span_id': 2, 'is_remote': False},
58+
'parent': None,
59+
'start_time': 2000000000,
60+
'end_time': 2000000000,
61+
'attributes': {
62+
'logfire.span_type': 'log',
63+
'logfire.level_num': 17,
64+
'logfire.msg_template': '456',
65+
'logfire.msg': '456',
66+
'code.filepath': 'test_structlog.py',
67+
'code.function': 'test_structlog',
68+
'code.lineno': 34,
69+
'logfire.disable_console_log': True,
70+
},
71+
},
5372
]
5473
)

0 commit comments

Comments
 (0)