11import pytest
22import requests
33import requests_mock
4+ from inline_snapshot import snapshot
45
6+ import logfire ._internal .stack_info
57from logfire ._internal .utils import UnexpectedResponse , handle_internal_errors
8+ from tests .import_used_for_tests .internal_error_handling import internal_logfire_code_example , user_code_example
69
710
811def test_raise_for_status () -> None :
@@ -21,3 +24,94 @@ def test_reraise_internal_exception():
2124 with pytest .raises (ZeroDivisionError ):
2225 with handle_internal_errors ():
2326 str (1 / 0 )
27+
28+
29+ def test_internal_exception_tb (caplog : pytest .LogCaptureFixture ):
30+ # Pretend that `internal_logfire_code_example` is a module within logfire,
31+ # so all frames from it should be included.
32+ logfire ._internal .stack_info .NON_USER_CODE_PREFIXES += (internal_logfire_code_example .__file__ ,)
33+
34+ user_code_example .user1 ()
35+
36+ tracebacks = [
37+ r .exc_text .replace ( # type: ignore
38+ user_code_example .__file__ ,
39+ 'user_code_example.py' ,
40+ ).replace (
41+ internal_logfire_code_example .__file__ ,
42+ 'internal_logfire_code_example.py' ,
43+ )
44+ for r in caplog .records
45+ ]
46+
47+ # Important notes about these tracebacks:
48+ # - They should look very similar to each other, regardless of how log_internal_error was called.
49+ # - They should include all frames from internal_logfire_code_example.py.
50+ # - They should include exactly 3 frames from user_code_example.py.
51+ # - They should look seamless, with each frame pointing to the next one.
52+ # - There should be no sign of logfire's internal error handling code.
53+ # - The two files should be isolated and stable so that the exact traceback contents can be asserted.
54+ assert tracebacks == snapshot (
55+ [
56+ """\
57+ Traceback (most recent call last):
58+ File "user_code_example.py", line 22, in user4
59+ user5()
60+ File "user_code_example.py", line 26, in user5
61+ user6()
62+ File "user_code_example.py", line 30, in user6
63+ outer2(using_decorator)
64+ File "internal_logfire_code_example.py", line 36, in outer2
65+ outer1(func)
66+ File "internal_logfire_code_example.py", line 32, in outer1
67+ func()
68+ File "internal_logfire_code_example.py", line 16, in using_decorator
69+ inner2()
70+ File "internal_logfire_code_example.py", line 11, in inner2
71+ inner1()
72+ File "internal_logfire_code_example.py", line 7, in inner1
73+ raise ValueError('inner1')
74+ ValueError: inner1\
75+ """ ,
76+ """\
77+ Traceback (most recent call last):
78+ File "user_code_example.py", line 22, in user4
79+ user5()
80+ File "user_code_example.py", line 26, in user5
81+ user6()
82+ File "user_code_example.py", line 31, in user6
83+ outer2(using_context_manager)
84+ File "internal_logfire_code_example.py", line 36, in outer2
85+ outer1(func)
86+ File "internal_logfire_code_example.py", line 32, in outer1
87+ func()
88+ File "internal_logfire_code_example.py", line 21, in using_context_manager
89+ inner2()
90+ File "internal_logfire_code_example.py", line 11, in inner2
91+ inner1()
92+ File "internal_logfire_code_example.py", line 7, in inner1
93+ raise ValueError('inner1')
94+ ValueError: inner1\
95+ """ ,
96+ """\
97+ Traceback (most recent call last):
98+ File "user_code_example.py", line 22, in user4
99+ user5()
100+ File "user_code_example.py", line 26, in user5
101+ user6()
102+ File "user_code_example.py", line 32, in user6
103+ outer2(using_try_except)
104+ File "internal_logfire_code_example.py", line 36, in outer2
105+ outer1(func)
106+ File "internal_logfire_code_example.py", line 32, in outer1
107+ func()
108+ File "internal_logfire_code_example.py", line 26, in using_try_except
109+ inner2()
110+ File "internal_logfire_code_example.py", line 11, in inner2
111+ inner1()
112+ File "internal_logfire_code_example.py", line 7, in inner1
113+ raise ValueError('inner1')
114+ ValueError: inner1\
115+ """ ,
116+ ]
117+ )
0 commit comments