@@ -62,10 +62,46 @@ export class ContextLines implements Integration {
6262
6363  /** Processes an event and adds context lines */ 
6464  public  async  addSourceContext ( event : Event ) : Promise < Event >  { 
65+     // keep a lookup map of which files we've already enqueued to read, 
66+     // so we don't enqueue the same file multiple times which would cause multiple i/o reads 
67+     const  enqueuedReadSourceFileTasks : Record < string ,  number >  =  { } ; 
68+     const  readSourceFileTasks : Promise < string  |  null > [ ]  =  [ ] ; 
69+ 
70+     if  ( this . _contextLines  >  0  &&  event . exception ?. values )  { 
71+       for  ( const  exception  of  event . exception . values )  { 
72+         if  ( ! exception . stacktrace ?. frames )  { 
73+           continue ; 
74+         } 
75+ 
76+         // We want to iterate in reverse order as calling cache.get will bump the file in our LRU cache. 
77+         // This ends up prioritizes source context for frames at the top of the stack instead of the bottom. 
78+         for  ( let  i  =  exception . stacktrace . frames . length  -  1 ;  i  >=  0 ;  i -- )  { 
79+           const  frame  =  exception . stacktrace . frames [ i ] ; 
80+           // Call cache.get to bump the file to the top of the cache and ensure we have not already 
81+           // enqueued a read operation for this filename 
82+           if  ( 
83+             frame . filename  && 
84+             ! enqueuedReadSourceFileTasks [ frame . filename ]  && 
85+             ! FILE_CONTENT_CACHE . get ( frame . filename ) 
86+           )  { 
87+             readSourceFileTasks . push ( _readSourceFile ( frame . filename ) ) ; 
88+             enqueuedReadSourceFileTasks [ frame . filename ]  =  1 ; 
89+           } 
90+         } 
91+       } 
92+     } 
93+ 
94+     // check if files to read > 0, if so, await all of them to be read before adding source contexts 
95+     if  ( readSourceFileTasks . length  >  0 )  { 
96+       await  Promise . all ( readSourceFileTasks ) ; 
97+     } 
98+ 
99+     // Perform the same loop as above, but this time we can assume all files are in the cache 
100+     // and attempt to add source context to frames. 
65101    if  ( this . _contextLines  >  0  &&  event . exception ?. values )  { 
66102      for  ( const  exception  of  event . exception . values )  { 
67103        if  ( exception . stacktrace ?. frames )  { 
68-           await   this . addSourceContextToFrames ( exception . stacktrace . frames ) ; 
104+           this . addSourceContextToFrames ( exception . stacktrace . frames ) ; 
69105        } 
70106      } 
71107    } 
@@ -74,18 +110,16 @@ export class ContextLines implements Integration {
74110  } 
75111
76112  /** Adds context lines to frames */ 
77-   public  async  addSourceContextToFrames ( frames : StackFrame [ ] ) : Promise < void >  { 
78-     const  contextLines  =  this . _contextLines ; 
79- 
113+   public  addSourceContextToFrames ( frames : StackFrame [ ] ) : void { 
80114    for  ( const  frame  of  frames )  { 
81115      // Only add context if we have a filename and it hasn't already been added 
82116      if  ( frame . filename  &&  frame . context_line  ===  undefined )  { 
83-         const  sourceFile  =  await   _readSourceFile ( frame . filename ) ; 
117+         const  sourceFile  =  FILE_CONTENT_CACHE . get ( frame . filename ) ; 
84118
85119        if  ( sourceFile )  { 
86120          try  { 
87121            const  lines  =  sourceFile . split ( '\n' ) ; 
88-             addContextToFrame ( lines ,  frame ,  contextLines ) ; 
122+             addContextToFrame ( lines ,  frame ,  this . _contextLines ) ; 
89123          }  catch  ( e )  { 
90124            // anomaly, being defensive in case 
91125            // unlikely to ever happen in practice but can definitely happen in theory 
0 commit comments