@@ -3,7 +3,7 @@ import { addContextToFrame } from '@sentry/utils';
33import { readFile } from 'fs' ;
44import { LRUMap } from 'lru_map' ;
55
6- const FILE_CONTENT_CACHE = new LRUMap < string , string | null > ( 100 ) ;
6+ const FILE_CONTENT_CACHE = new LRUMap < string , string [ ] | null > ( 100 ) ;
77const DEFAULT_LINES_OF_CONTEXT = 7 ;
88
99// TODO: Replace with promisify when minimum supported node >= v8
@@ -64,7 +64,7 @@ export class ContextLines implements Integration {
6464 public async addSourceContext ( event : Event ) : Promise < Event > {
6565 if ( this . _contextLines > 0 && event . exception ?. values ) {
6666 for ( const exception of event . exception . values ) {
67- if ( exception . stacktrace ? .frames ) {
67+ if ( exception . stacktrace && exception . stacktrace . frames ) {
6868 await this . addSourceContextToFrames ( exception . stacktrace . frames ) ;
6969 }
7070 }
@@ -80,12 +80,11 @@ export class ContextLines implements Integration {
8080 for ( const frame of frames ) {
8181 // Only add context if we have a filename and it hasn't already been added
8282 if ( frame . filename && frame . context_line === undefined ) {
83- const sourceFile = await _readSourceFile ( frame . filename ) ;
83+ const sourceFileLines = await _readSourceFile ( frame . filename ) ;
8484
85- if ( sourceFile ) {
85+ if ( sourceFileLines ) {
8686 try {
87- const lines = sourceFile . split ( '\n' ) ;
88- addContextToFrame ( lines , frame , contextLines ) ;
87+ addContextToFrame ( sourceFileLines , frame , contextLines ) ;
8988 } catch ( e ) {
9089 // anomaly, being defensive in case
9190 // unlikely to ever happen in practice but can definitely happen in theory
@@ -98,21 +97,30 @@ export class ContextLines implements Integration {
9897
9998/**
10099 * Reads file contents and caches them in a global LRU cache.
100+ * If reading fails, mark the file as null in the cache so we don't try again.
101101 *
102102 * @param filename filepath to read content from.
103103 */
104- async function _readSourceFile ( filename : string ) : Promise < string | null > {
104+ async function _readSourceFile ( filename : string ) : Promise < string [ ] | null > {
105105 const cachedFile = FILE_CONTENT_CACHE . get ( filename ) ;
106- // We have a cache hit
106+
107+ // We have already attempted to read this file and failed, do not try again
108+ if ( cachedFile === null ) {
109+ return null ;
110+ }
111+
112+ // We have a cache hit, return it
107113 if ( cachedFile !== undefined ) {
108114 return cachedFile ;
109115 }
110116
111- let content : string | null = null ;
117+ // File is neither in cache nor marked as failed, attempt to read it
118+ let content : string [ ] | null = null ;
112119 try {
113- content = await readTextFileAsync ( filename ) ;
120+ const rawFileContents = await readTextFileAsync ( filename ) ;
121+ content = rawFileContents . split ( '\n' ) ;
114122 } catch ( _ ) {
115- //
123+ // if we fail, we will mark the file as null in the cache and short circuit next time we try to read it
116124 }
117125
118126 FILE_CONTENT_CACHE . set ( filename , content ) ;
0 commit comments