Skip to content

Commit 51d2219

Browse files
authored
fix: exclude large source code from backtrace (#1440)
1 parent 0d6f92a commit 51d2219

File tree

2 files changed

+134
-4
lines changed

2 files changed

+134
-4
lines changed

packages/core/src/util.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ export async function getSourceForBacktrace(backtrace: BacktraceFrame[],
151151
while (backtrace.length) {
152152
const trace = backtrace.splice(0)[index]
153153

154-
const fileContent = await getSourceFileHandler(trace.file)
155-
result[index] = getSourceCodeSnippet(fileContent, trace.number)
154+
const fileContent = await getSourceFileHandler(trace.file)
155+
result[index] = getSourceCodeSnippet(fileContent, trace.number, trace.column, 2)
156+
156157
index++
157158
}
158159
return result
@@ -542,13 +543,39 @@ export function clone<T>(obj: T): T {
542543
return JSON.parse(JSON.stringify(obj))
543544
}
544545

545-
function getSourceCodeSnippet(fileData: string, lineNumber: number, sourceRadius = 2): Record<string, string> {
546+
const THRESHOLD_COLUMN_NUMBER = 10000
547+
const THRESHOLD_LINE_LENGTH = 10000
548+
const THRESHOLD_FILE_SIZE = 200000 // 200KB threshold
549+
550+
function getThresholdExceededSnippet(lineNumber: number) {
551+
return { [lineNumber]: 'SOURCE_SIZE_TOO_LARGE' }
552+
}
553+
554+
function getSourceCodeSnippet(fileData: string, lineNumber: number, columnNumber: number, sourceRadius = 2): Record<string, string> | null {
546555
if (!fileData) {
547556
return null
548557
}
558+
559+
// If column number is provided and very high, it's likely a bundled/minified file
560+
if (columnNumber && columnNumber > THRESHOLD_COLUMN_NUMBER) {
561+
return getThresholdExceededSnippet(lineNumber)
562+
}
563+
564+
// If file is very large, it's likely bundled
565+
if (fileData.length > THRESHOLD_FILE_SIZE) {
566+
return getThresholdExceededSnippet(lineNumber)
567+
}
568+
549569
const lines = fileData.split('\n')
550570
// add one empty line because array index starts from 0, but error line number is counted from 1
551571
lines.unshift('')
572+
573+
// Check if the target line is extremely long
574+
const targetLine = lines[lineNumber]
575+
if (targetLine && targetLine.length > THRESHOLD_LINE_LENGTH) {
576+
return getThresholdExceededSnippet(lineNumber)
577+
}
578+
552579
const start = lineNumber - sourceRadius
553580
const end = lineNumber + sourceRadius
554581
const result = {}

packages/core/test/util.test.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
logger,
1111
filter,
1212
filterUrl,
13-
logDeprecatedMethod
13+
logDeprecatedMethod,
14+
getSourceForBacktrace
1415
} from '../src/util'
1516
import { nullLogger, TestClient, TestTransport } from './helpers'
1617

@@ -348,4 +349,106 @@ describe('utils', function () {
348349
expect(warnSpy).toHaveBeenCalledTimes(2)
349350
})
350351
})
352+
353+
describe('getSourceForBacktrace minified/bundled detection', function () {
354+
it('excludes files with high column numbers (bundled/minified)', async function () {
355+
const mockGetSourceFile = async (_path: string): Promise<string> => {
356+
return 'normal source code content'
357+
}
358+
359+
const backtrace = [{
360+
file: '/path/to/bundled.js',
361+
method: 'someFunction',
362+
number: 1,
363+
column: 141907
364+
}]
365+
366+
const result = await getSourceForBacktrace(backtrace, mockGetSourceFile)
367+
expect(result[0]['1']).toBe('SOURCE_SIZE_TOO_LARGE')
368+
})
369+
370+
it('includes normal source files with reasonable column numbers', async function () {
371+
const mockGetSourceFile = async (_path: string): Promise<string> => {
372+
const normalSource = [
373+
'function example() {',
374+
' const someVariable = "this is a normal line"',
375+
' return someVariable',
376+
'}',
377+
'// This is a comment',
378+
'console.log("test")'
379+
].join('\n')
380+
return normalSource
381+
}
382+
383+
const backtrace = [{
384+
file: '/path/to/normal.js',
385+
method: 'example',
386+
number: 2,
387+
column: 10
388+
}]
389+
390+
const result = await getSourceForBacktrace(backtrace, mockGetSourceFile)
391+
expect(result[0]).not.toBeNull()
392+
expect(result[0]['1']).toBe('function example() {')
393+
expect(result[0]['2']).toBe(' const someVariable = "this is a normal line"')
394+
expect(result[0]['3']).toBe(' return someVariable')
395+
})
396+
397+
it('handles empty or null file content gracefully', async function () {
398+
const mockGetSourceFile = async (_path: string): Promise<string> => {
399+
return null
400+
}
401+
402+
const backtrace = [{
403+
file: '/path/to/missing.js',
404+
method: 'someFunction',
405+
number: 1,
406+
column: 1
407+
}]
408+
409+
const result = await getSourceForBacktrace(backtrace, mockGetSourceFile)
410+
expect(result[0]).toBeNull()
411+
})
412+
413+
it('detects large bundled files and excludes them', async function () {
414+
const mockGetSourceFile = async (_path: string): Promise<string> => {
415+
const largeContent = 'console.log("test");\n'.repeat(50000)
416+
return largeContent
417+
}
418+
419+
const backtrace = [{
420+
file: '/path/to/large-bundle.js',
421+
method: 'someFunction',
422+
number: 1000,
423+
column: 10
424+
}]
425+
426+
const result = await getSourceForBacktrace(backtrace, mockGetSourceFile)
427+
expect(result[0]['1000']).toBe('SOURCE_SIZE_TOO_LARGE')
428+
})
429+
430+
it('detects files with very long lines and excludes them', async function () {
431+
const mockGetSourceFile = async (_path: string): Promise<string> => {
432+
const longLine = 'a'.repeat(10100)
433+
const content = [
434+
'function test() {',
435+
` const x = "${longLine}"`,
436+
' return x',
437+
'}'
438+
].join('\n')
439+
return content
440+
}
441+
442+
const backtrace = [{
443+
file: '/path/to/long-line.js',
444+
method: 'test',
445+
number: 2,
446+
column: 10
447+
}]
448+
449+
const result = await getSourceForBacktrace(backtrace, mockGetSourceFile)
450+
expect(result[0]['2']).toBe('SOURCE_SIZE_TOO_LARGE')
451+
})
452+
453+
})
351454
})

0 commit comments

Comments
 (0)