Skip to content

Commit 995194c

Browse files
shashjarandrewshie-sentry
authored andcommitted
fix(issue details): Add exhaustive(-ish) platform support for raw stack traces (#98620)
**When formatting raw stack trace indents, switched over from `\t` to 4 spaces (better formatting in the browser)** Before: <img width="852" height="268" alt="image" src="https://github.com/user-attachments/assets/df285546-ee58-44b7-88dc-db96954d199e" /> After: <img width="851" height="267" alt="image" src="https://github.com/user-attachments/assets/1c54d66c-7a70-431e-9cd0-fd0a39da6d1c" /> **Modified Python raw stack trace formatting to match default Python behavior** (fixes [ID-744](https://linear.app/getsentry/issue/ID-744/improve-readability-of-raw-stacktrace-output-in-sentry-for-python)) Before: <img width="984" height="745" alt="image" src="https://github.com/user-attachments/assets/75c9b725-f8fa-4444-bfc0-41e5c232ba91" /> After: <img width="985" height="750" alt="image" src="https://github.com/user-attachments/assets/cea0f10d-9e9f-44d5-a8be-2d6987123d05" /> **Added explicit handling when generating raw stack traces for platforms: `node`, `go`, `csharp`, `elixir`** (fixes [ID-908](https://linear.app/getsentry/issue/ID-908/platform-handling-while-generating-raw-stack-traces-is-not-exhaustive)) The full list of issue platforms is [here](#59075) under "Full list of platform values for groups and events". Based on Datadog metrics for group creation rate, the four chosen platforms are the most important to add support for. The others will continue to fall into default raw stack trace formatting (`getDefaultFrame`). **Updated the logic for reversing/structuring the stack trace frames** Updated options to `rawTrace` and `newestFirst` (both default to `true`). If `rawTrace` is `true`, we ignore the value of `newestFirst` - we simply do whatever is default behavior for that `platform`. The default behavior for `Python` is `most recent call last`, and for all other platforms it is `most recent call first`. If `rawTrace` is `false`, then we decide whether to reverse or not based on the value of `newestFirst`. The `issueDiff` logic passes `rawTrace = false` and `newestFirst` based on the user setting.
1 parent 460c1ae commit 995194c

File tree

5 files changed

+283
-49
lines changed

5 files changed

+283
-49
lines changed

static/app/components/events/interfaces/crashContent/stackTrace/rawContent.spec.tsx

Lines changed: 169 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import {ExceptionValueFixture} from 'sentry-fixture/exceptionValue';
22
import {FrameFixture} from 'sentry-fixture/frame';
33

44
import displayRawContent, {
5+
getJavaExceptionSummary,
56
getJavaFrame,
6-
getJavaPreamble,
77
} from 'sentry/components/events/interfaces/crashContent/stackTrace/rawContent';
88
import type {StacktraceType} from 'sentry/types/stacktrace';
99

@@ -21,7 +21,7 @@ describe('RawStacktraceContent', () => {
2121
true
2222
)
2323
).toBe(
24-
'\tat org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)'
24+
' at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)'
2525
);
2626

2727
// without line number
@@ -35,7 +35,7 @@ describe('RawStacktraceContent', () => {
3535
true
3636
)
3737
).toBe(
38-
'\tat org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java)'
38+
' at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java)'
3939
);
4040

4141
// without line number and filename
@@ -49,15 +49,15 @@ describe('RawStacktraceContent', () => {
4949
true
5050
)
5151
).toBe(
52-
'\tat org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java)'
52+
' at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java)'
5353
);
5454
});
5555
});
5656

57-
describe('getJavaPreamble()', () => {
57+
describe('getJavaExceptionSummary()', () => {
5858
it('takes a type and value', () => {
5959
expect(
60-
getJavaPreamble(
60+
getJavaExceptionSummary(
6161
ExceptionValueFixture({
6262
type: 'Baz',
6363
value: 'message',
@@ -69,7 +69,7 @@ describe('RawStacktraceContent', () => {
6969

7070
it('takes a module name', () => {
7171
expect(
72-
getJavaPreamble(
72+
getJavaExceptionSummary(
7373
ExceptionValueFixture({
7474
module: 'foo.bar',
7575
type: 'Baz',
@@ -130,20 +130,78 @@ describe('RawStacktraceContent', () => {
130130
it('renders javascript example', () => {
131131
expect(displayRawContent(data, 'javascript', exception)).toBe(
132132
`Error: an error occurred
133-
\tat doThing3 (example.application:12:24)
134-
\tat ? (src/application.code:1:6)
135-
\tat doThing1 (src/application.code:5:9)
136-
\tat main (src/application.code:1:14)`
133+
at doThing3 (example.application:12:24)
134+
at ? (src/application.code:1:6)
135+
at doThing1 (src/application.code:5:9)
136+
at main (src/application.code:1:14)`
137+
);
138+
});
139+
140+
it('renders javascript example - rawTrace, newestFirst', () => {
141+
expect(
142+
displayRawContent(data, 'javascript', exception, false, true, true, true)
143+
).toBe(
144+
`Error: an error occurred
145+
at doThing3 (example.application:12:24)
146+
at ? (src/application.code:1:6)
147+
at doThing1 (src/application.code:5:9)
148+
at main (src/application.code:1:14)`
149+
);
150+
});
151+
152+
it('renders javascript example - !rawTrace, newestFirst', () => {
153+
expect(
154+
displayRawContent(data, 'javascript', exception, false, true, false, true)
155+
).toBe(
156+
`Error: an error occurred
157+
at doThing3 (example.application:12:24)
158+
at ? (src/application.code:1:6)
159+
at doThing1 (src/application.code:5:9)
160+
at main (src/application.code:1:14)`
161+
);
162+
});
163+
164+
it('renders javascript example - rawTrace, !newestFirst', () => {
165+
expect(
166+
displayRawContent(data, 'javascript', exception, false, true, true, false)
167+
).toBe(
168+
`Error: an error occurred
169+
at doThing3 (example.application:12:24)
170+
at ? (src/application.code:1:6)
171+
at doThing1 (src/application.code:5:9)
172+
at main (src/application.code:1:14)`
173+
);
174+
});
175+
176+
it('renders javascript example - !rawTrace, !newestFirst', () => {
177+
expect(
178+
displayRawContent(data, 'javascript', exception, false, true, false, false)
179+
).toBe(
180+
` at main (src/application.code:1:14)
181+
at doThing1 (src/application.code:5:9)
182+
at ? (src/application.code:1:6)
183+
at doThing3 (example.application:12:24)
184+
Error: an error occurred`
185+
);
186+
});
187+
188+
it('renders node example', () => {
189+
expect(displayRawContent(data, 'node', exception)).toBe(
190+
`Error: an error occurred
191+
at doThing3 (example.application:12:24)
192+
at ? (src/application.code:1:6)
193+
at doThing1 (src/application.code:5:9)
194+
at main (src/application.code:1:14)`
137195
);
138196
});
139197

140198
it('renders ruby example', () => {
141199
expect(displayRawContent(data, 'ruby', exception)).toBe(
142200
`Error: an error occurred
143-
\tfrom (example.application):12:in 'doThing3'
144-
\tfrom src/application.code:1
145-
\tfrom src/application.code:5:in 'doThing1'
146-
\tfrom src/application.code:1:in 'main'`
201+
from (example.application):12:in 'doThing3'
202+
from src/application.code:1
203+
from src/application.code:5:in 'doThing1'
204+
from src/application.code:1:in 'main'`
147205
);
148206
});
149207

@@ -159,21 +217,102 @@ describe('RawStacktraceContent', () => {
159217

160218
it('renders python example', () => {
161219
expect(displayRawContent(data, 'python', exception)).toBe(
162-
`Error: an error occurred
220+
`Traceback (most recent call last):
221+
File "src/application.code", line 1, in main
222+
File "src/application.code", line 5, in doThing1
223+
File "src/application.code", line 1
224+
Module "example.application", line 12, in doThing3
225+
Error: an error occurred`
226+
);
227+
});
228+
229+
it('renders python example - rawTrace, newestFirst', () => {
230+
expect(displayRawContent(data, 'python', exception, false, true, true, true)).toBe(
231+
`Traceback (most recent call last):
163232
File "src/application.code", line 1, in main
164233
File "src/application.code", line 5, in doThing1
165234
File "src/application.code", line 1
166-
Module "example.application", line 12, in doThing3`
235+
Module "example.application", line 12, in doThing3
236+
Error: an error occurred`
237+
);
238+
});
239+
240+
it('renders python example - !rawTrace, newestFirst', () => {
241+
expect(displayRawContent(data, 'python', exception, false, true, false, true)).toBe(
242+
`Traceback (most recent call first):
243+
Error: an error occurred
244+
Module "example.application", line 12, in doThing3
245+
File "src/application.code", line 1
246+
File "src/application.code", line 5, in doThing1
247+
File "src/application.code", line 1, in main`
248+
);
249+
});
250+
251+
it('renders python example - rawTrace, !newestFirst', () => {
252+
expect(displayRawContent(data, 'python', exception, false, true, true, false)).toBe(
253+
`Traceback (most recent call last):
254+
File "src/application.code", line 1, in main
255+
File "src/application.code", line 5, in doThing1
256+
File "src/application.code", line 1
257+
Module "example.application", line 12, in doThing3
258+
Error: an error occurred`
259+
);
260+
});
261+
262+
it('renders python example - !rawTrace, !newestFirst', () => {
263+
expect(
264+
displayRawContent(data, 'python', exception, false, true, false, false)
265+
).toBe(
266+
`Traceback (most recent call last):
267+
File "src/application.code", line 1, in main
268+
File "src/application.code", line 5, in doThing1
269+
File "src/application.code", line 1
270+
Module "example.application", line 12, in doThing3
271+
Error: an error occurred`
167272
);
168273
});
169274

170275
it('renders java example', () => {
171276
expect(displayRawContent(data, 'java', exception)).toBe(
172277
`example.application.Error: an error occurred
173-
\tat example.application.doThing3
174-
\tat example.application.(src/application.code:1)
175-
\tat doThing1(src/application.code:5)
176-
\tat example.application.main(src/application.code:1)`
278+
at example.application.doThing3
279+
at example.application.(src/application.code:1)
280+
at doThing1(src/application.code:5)
281+
at example.application.main(src/application.code:1)`
282+
);
283+
});
284+
285+
it('renders go example', () => {
286+
expect(displayRawContent(data, 'go', exception)).toBe(
287+
`Error: an error occurred
288+
doThing3()
289+
example.application:12
290+
?()
291+
src/application.code:1
292+
doThing1()
293+
src/application.code:5
294+
main()
295+
src/application.code:1`
296+
);
297+
});
298+
299+
it('renders csharp example', () => {
300+
expect(displayRawContent(data, 'csharp', exception)).toBe(
301+
`Error: an error occurred
302+
at example.application.doThing3():line 12
303+
at example.application.?() in src/application.code:line 1
304+
at doThing1() in src/application.code:line 5
305+
at example.application.main() in src/application.code:line 1`
306+
);
307+
});
308+
309+
it('renders elixir example', () => {
310+
expect(displayRawContent(data, 'elixir', exception)).toBe(
311+
`Error: an error occurred
312+
?:12: example.application.doThing3
313+
src/application.code:1: example.application.?
314+
src/application.code:5: doThing1
315+
src/application.code:1: example.application.main`
177316
);
178317
});
179318

@@ -259,9 +398,10 @@ describe('RawStacktraceContent', () => {
259398
'renders all frames when similarity flag is off, in-app or not',
260399
stacktrace => {
261400
expect(displayRawContent(stacktrace, 'python', exception)).toBe(
262-
`Error: an error occurred
401+
`Traceback (most recent call last):
263402
File "application", line 1, in main
264-
File "application", line 2, in doThing`
403+
File "application", line 2, in doThing
404+
Error: an error occurred`
265405
);
266406
}
267407
);
@@ -277,17 +417,19 @@ describe('RawStacktraceContent', () => {
277417
similarityFeatureEnabled
278418
)
279419
).toBe(
280-
`Error: an error occurred
420+
`Traceback (most recent call last):
281421
File "application", line 1, in main
282-
File "application", line 2, in doThing`
422+
File "application", line 2, in doThing
423+
Error: an error occurred`
283424
);
284425
}
285426
);
286427

287428
it('renders only in-app frames when they exist and hasSimilarityEmbeddingsFeature is on', () => {
288429
expect(displayRawContent(mixedFrames, 'python', exception, true)).toBe(
289-
`Error: an error occurred
290-
File "application", line 1, in main`
430+
`Traceback (most recent call last):
431+
File "application", line 1, in main
432+
Error: an error occurred`
291433
);
292434
});
293435
});

0 commit comments

Comments
 (0)