@@ -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