@@ -593,6 +593,76 @@ def test_logger_cannot_be_disabled(self):
593
593
self .logger .handle (record )
594
594
mock_call_handlers .assert_called_once ()
595
595
596
+ def test_find_caller_respects_stacklevel (self ):
597
+ self .set_up_mock_frames ()
598
+ self .logger .register_frame_to_skip ('myfile.py' , 'Method1' )
599
+ # Frame 0 is filtered out due to being in the logging file.
600
+ # Frame 1 is filtered out due to being registered to be skipped.
601
+ # Frame 2 is the topmost unfiltered frame on the stack.
602
+ self .assertEqual (
603
+ self .logger .findCaller (stacklevel = 1 ),
604
+ ('myfile.py' , 125 , 'Method2' , None ),
605
+ )
606
+ self .assertEqual (
607
+ self .logger .findCaller (stacklevel = 2 ),
608
+ ('myfile.py' , 125 , 'Method3' , None ),
609
+ )
610
+ self .assertEqual (
611
+ self .logger .findCaller (stacklevel = 3 ),
612
+ ('myfile.py' , 249 , 'Method2' , None ),
613
+ )
614
+
615
+ def test_find_caller_handles_skipped_bottom_of_stack (self ):
616
+ self .set_up_mock_frames ()
617
+ self .logger .register_frame_to_skip ('myfile.py' , 'Method2' )
618
+ # Frame 0 is filtered out due to being in the logging file.
619
+ # Frame 1 is unfiltered.
620
+ # Frame 2 is filtered due to regiser_frame_to_skip.
621
+ # Frame 3 is unfiltered.
622
+ # Frame 4 is filtered due to regiser_frame_to_skip.
623
+ self .assertEqual (
624
+ self .logger .findCaller (stacklevel = 1 ),
625
+ ('myfile.py' , 125 , 'Method1' , None ),
626
+ )
627
+ self .assertEqual (
628
+ self .logger .findCaller (stacklevel = 2 ),
629
+ ('myfile.py' , 125 , 'Method3' , None ),
630
+ )
631
+ # 3 exceeds the unfiltered stack depth, so it returns the bottom unfiltered frame.
632
+ self .assertEqual (
633
+ self .logger .findCaller (stacklevel = 3 ),
634
+ ('myfile.py' , 125 , 'Method3' , None ),
635
+ )
636
+
637
+ def test_log_respects_stacklevel (self ):
638
+ self .set_up_mock_frames ()
639
+ original_logger_class = std_logging .getLoggerClass ()
640
+ std_logging .setLoggerClass (logging .ABSLLogger )
641
+ absl_logger = std_logging .getLogger ('absl' )
642
+ with self .assertLogs () as cm :
643
+ absl_logger .info ('lol' , stacklevel = 2 )
644
+ std_logging .setLoggerClass (original_logger_class )
645
+ self .assertLen (cm .records , 1 )
646
+ self .assertEqual (cm .records [0 ].lineno , 125 )
647
+ self .assertEqual (cm .records [0 ].funcName , 'Method2' )
648
+ self .assertEqual (cm .records [0 ].filename , 'myfile.py' )
649
+
650
+ def test_handles_negative_stacklevel (self ):
651
+ """If stacklevel is negative, return the top unfiltered frame."""
652
+ self .set_up_mock_frames ()
653
+ self .assertEqual (
654
+ self .logger .findCaller (stacklevel = - 1 ),
655
+ ('myfile.py' , 125 , 'Method1' , None ),
656
+ )
657
+
658
+ def test_handles_excess_stacklevel (self ):
659
+ """If stacklevel exceeds the stack depth, return the bottom frame."""
660
+ self .set_up_mock_frames ()
661
+ self .assertEqual (
662
+ self .logger .findCaller (stacklevel = 1000 ),
663
+ ('myfile.py' , 249 , 'Method2' , None ),
664
+ )
665
+
596
666
597
667
class ABSLLogPrefixTest (parameterized .TestCase ):
598
668
0 commit comments