Skip to content

Commit f71d223

Browse files
authored
feat(logs): Add support for dict args (#4478)
resolves #4477 This PR adds support for dict log arguments and adds (cursor generated) tests accordingly.
1 parent 0e21fa2 commit f71d223

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

sentry_sdk/integrations/logging.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,13 @@ def _capture_log_from_record(self, client, record):
367367
if isinstance(arg, (str, float, int, bool))
368368
else safe_repr(arg)
369369
)
370+
elif isinstance(record.args, dict):
371+
for key, value in record.args.items():
372+
attrs[f"sentry.message.parameter.{key}"] = (
373+
value
374+
if isinstance(value, (str, float, int, bool))
375+
else safe_repr(value)
376+
)
370377
if record.lineno:
371378
attrs["code.line.number"] = record.lineno
372379
if record.pathname:

tests/integrations/logging/test_logging.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,82 @@ def test_logger_with_all_attributes(sentry_init, capture_envelopes):
492492
"sentry.severity_number": 13,
493493
"sentry.severity_text": "warn",
494494
}
495+
496+
497+
def test_sentry_logs_named_parameters(sentry_init, capture_envelopes):
498+
"""
499+
The python logger module should capture named parameters from dictionary arguments in Sentry logs.
500+
"""
501+
sentry_init(_experiments={"enable_logs": True})
502+
envelopes = capture_envelopes()
503+
504+
python_logger = logging.Logger("test-logger")
505+
python_logger.info(
506+
"%(source)s call completed, %(input_tk)i input tk, %(output_tk)i output tk (model %(model)s, cost $%(cost).4f)",
507+
{
508+
"source": "test_source",
509+
"input_tk": 100,
510+
"output_tk": 50,
511+
"model": "gpt-4",
512+
"cost": 0.0234,
513+
},
514+
)
515+
516+
get_client().flush()
517+
logs = envelopes_to_logs(envelopes)
518+
519+
assert len(logs) == 1
520+
attrs = logs[0]["attributes"]
521+
522+
# Check that the template is captured
523+
assert (
524+
attrs["sentry.message.template"]
525+
== "%(source)s call completed, %(input_tk)i input tk, %(output_tk)i output tk (model %(model)s, cost $%(cost).4f)"
526+
)
527+
528+
# Check that dictionary arguments are captured as named parameters
529+
assert attrs["sentry.message.parameter.source"] == "test_source"
530+
assert attrs["sentry.message.parameter.input_tk"] == 100
531+
assert attrs["sentry.message.parameter.output_tk"] == 50
532+
assert attrs["sentry.message.parameter.model"] == "gpt-4"
533+
assert attrs["sentry.message.parameter.cost"] == 0.0234
534+
535+
# Check other standard attributes
536+
assert attrs["logger.name"] == "test-logger"
537+
assert attrs["sentry.origin"] == "auto.logger.log"
538+
assert logs[0]["severity_number"] == 9 # info level
539+
assert logs[0]["severity_text"] == "info"
540+
541+
542+
def test_sentry_logs_named_parameters_complex_values(sentry_init, capture_envelopes):
543+
"""
544+
The python logger module should handle complex values in named parameters using safe_repr.
545+
"""
546+
sentry_init(_experiments={"enable_logs": True})
547+
envelopes = capture_envelopes()
548+
549+
python_logger = logging.Logger("test-logger")
550+
complex_object = {"nested": {"data": [1, 2, 3]}, "tuple": (4, 5, 6)}
551+
python_logger.warning(
552+
"Processing %(simple)s with %(complex)s data",
553+
{
554+
"simple": "simple_value",
555+
"complex": complex_object,
556+
},
557+
)
558+
559+
get_client().flush()
560+
logs = envelopes_to_logs(envelopes)
561+
562+
assert len(logs) == 1
563+
attrs = logs[0]["attributes"]
564+
565+
# Check that simple values are kept as-is
566+
assert attrs["sentry.message.parameter.simple"] == "simple_value"
567+
568+
# Check that complex values are converted using safe_repr
569+
assert "sentry.message.parameter.complex" in attrs
570+
complex_param = attrs["sentry.message.parameter.complex"]
571+
assert isinstance(complex_param, str)
572+
assert "nested" in complex_param
573+
assert "data" in complex_param

0 commit comments

Comments
 (0)