@@ -22,6 +22,14 @@ interface ContextLinesOptions {
2222 * Set to 0 to disable loading and inclusion of source files.
2323 **/
2424 frameContextLines ?: number ;
25+
26+ /**
27+ * If error stacktraces are already sourcemapped.
28+ * In this case, we can skip the sourcemap lookup for certain cases.
29+ * This is the case e.g. if the node process is run with `node --enable-source-maps`.
30+ * If this is undefined, the SDK tries to infer it from the environment.
31+ */
32+ hasSourceMaps ?: boolean ;
2533}
2634
2735/**
@@ -62,6 +70,19 @@ function shouldSkipContextLinesForFile(path: string): boolean {
6270 return false ;
6371}
6472
73+ /**
74+ * Skip frames that we determine to already have been sourcemapped.
75+ */
76+ function shouldSkipContextLinesThatAreAlreadySourceMapped ( path : string , frame : StackFrame ) : boolean {
77+ // For non-in-app frames, we skip context lines when we are reasonably certain that the path is already sourcemapped.
78+ // For now, we only consider .ts files because they can never appear otherwise in a stackframe, if not already sourcemapped.
79+ if ( frame . in_app === false && path . endsWith ( '.ts' ) ) {
80+ return true ;
81+ }
82+
83+ return false ;
84+ }
85+
6586/**
6687 * Determines if we should skip contextlines based off the max lineno and colno values.
6788 */
@@ -164,10 +185,11 @@ function getContextLinesFromFile(path: string, ranges: ReadlineRange[], output:
164185
165186 // We use this inside Promise.all, so we need to resolve the promise even if there is an error
166187 // to prevent Promise.all from short circuiting the rest.
167- function onStreamError ( e : Error ) : void {
188+ function onStreamError ( ) : void {
168189 // Mark file path as failed to read and prevent multiple read attempts.
169190 LRU_FILE_CONTENTS_FS_READ_FAILED . set ( path , 1 ) ;
170- DEBUG_BUILD && debug . error ( `Failed to read file: ${ path } . Error: ${ e } ` ) ;
191+ DEBUG_BUILD &&
192+ debug . warn ( `ContextLines: Failed to read file: ${ path } . Skipping context line extraction for this file.` ) ;
171193 lineReaded . close ( ) ;
172194 lineReaded . removeAllListeners ( ) ;
173195 destroyStreamAndResolve ( ) ;
@@ -215,7 +237,10 @@ function getContextLinesFromFile(path: string, ranges: ReadlineRange[], output:
215237 * failing reads from happening.
216238 */
217239/* eslint-disable complexity */
218- async function addSourceContext ( event : Event , contextLines : number ) : Promise < Event > {
240+ async function addSourceContext (
241+ event : Event ,
242+ { contextLines, hasSourceMaps } : { contextLines : number ; hasSourceMaps : boolean } ,
243+ ) : Promise < Event > {
219244 // keep a lookup map of which files we've already enqueued to read,
220245 // so we don't enqueue the same file multiple times which would cause multiple i/o reads
221246 const filesToLines : Record < string , number [ ] > = { } ;
@@ -242,6 +267,10 @@ async function addSourceContext(event: Event, contextLines: number): Promise<Eve
242267 continue ;
243268 }
244269
270+ if ( hasSourceMaps && shouldSkipContextLinesThatAreAlreadySourceMapped ( filename , frame ) ) {
271+ continue ;
272+ }
273+
245274 const filesToLinesOutput = filesToLines [ filename ] ;
246275 if ( ! filesToLinesOutput ) filesToLines [ filename ] = [ ] ;
247276 // @ts -expect-error this is defined above
@@ -399,11 +428,12 @@ function makeContextRange(line: number, linecontext: number): [start: number, en
399428/** Exported only for tests, as a type-safe variant. */
400429export const _contextLinesIntegration = ( ( options : ContextLinesOptions = { } ) => {
401430 const contextLines = options . frameContextLines !== undefined ? options . frameContextLines : DEFAULT_LINES_OF_CONTEXT ;
431+ const hasSourceMaps = options . hasSourceMaps ?? inferHasSourceMaps ( ) ;
402432
403433 return {
404434 name : INTEGRATION_NAME ,
405435 processEvent ( event ) {
406- return addSourceContext ( event , contextLines ) ;
436+ return addSourceContext ( event , { contextLines, hasSourceMaps } ) ;
407437 } ,
408438 } ;
409439} ) satisfies IntegrationFn ;
@@ -412,3 +442,10 @@ export const _contextLinesIntegration = ((options: ContextLinesOptions = {}) =>
412442 * Capture the lines before and after the frame's context.
413443 */
414444export const contextLinesIntegration = defineIntegration ( _contextLinesIntegration ) ;
445+
446+ function inferHasSourceMaps ( ) : boolean {
447+ return (
448+ ( process . env . NODE_OPTIONS ?. includes ( '--enable-source-maps' ) || process . argv . includes ( '--enable-source-maps' ) ) ??
449+ false
450+ ) ;
451+ }
0 commit comments