1
1
import { getCurrentHub } from '@sentry/core' ;
2
- import { Event , EventProcessor , Integration , StackFrame , StackParser } from '@sentry/types' ;
2
+ import { Event , EventProcessor , Exception , Integration , StackFrame , StackParser } from '@sentry/types' ;
3
3
import { Debugger , InspectorNotification , Runtime , Session } from 'inspector' ;
4
4
import { LRUMap } from 'lru_map' ;
5
5
6
- import { NodeClient } from '../client' ;
7
-
8
6
/**
9
7
* Promise API is available as `Experimental` and in Node 19 only.
10
8
*
@@ -15,7 +13,7 @@ import { NodeClient } from '../client';
15
13
* https://nodejs.org/docs/latest-v14.x/api/inspector.html
16
14
*/
17
15
class AsyncSession extends Session {
18
- public async getProperties ( objectId : string ) : Promise < Runtime . PropertyDescriptor [ ] > {
16
+ public getProperties ( objectId : string ) : Promise < Runtime . PropertyDescriptor [ ] > {
19
17
return new Promise ( ( resolve , reject ) => {
20
18
this . post (
21
19
'Runtime.getProperties' ,
@@ -59,7 +57,8 @@ function hashFrames(frames: StackFrame[] | undefined): string | undefined {
59
57
return ;
60
58
}
61
59
62
- return frames . reduce ( ( acc , frame ) => `${ acc } ,${ frame . function } ,${ frame . lineno } ,${ frame . colno } ` , '' ) ;
60
+ // Only hash the 10 most recent frames (ie. the last 10)
61
+ return frames . slice ( - 10 ) . reduce ( ( acc , frame ) => `${ acc } ,${ frame . function } ,${ frame . lineno } ,${ frame . colno } ` , '' ) ;
63
62
}
64
63
65
64
interface FrameVariables {
@@ -76,14 +75,14 @@ export class LocalVariables implements Integration {
76
75
public readonly name : string = LocalVariables . id ;
77
76
78
77
private readonly _session : AsyncSession = new AsyncSession ( ) ;
79
- private readonly _cachedFrames : LRUMap < string , Promise < FrameVariables [ ] > > = new LRUMap ( 50 ) ;
78
+ private readonly _cachedFrames : LRUMap < string , Promise < FrameVariables [ ] > > = new LRUMap ( 20 ) ;
80
79
private _stackParser : StackParser | undefined ;
81
80
82
81
/**
83
82
* @inheritDoc
84
83
*/
85
84
public setupOnce ( addGlobalEventProcessor : ( callback : EventProcessor ) => void ) : void {
86
- const options = getCurrentHub ( ) . getClient < NodeClient > ( ) ?. getOptions ( ) ;
85
+ const options = getCurrentHub ( ) . getClient ( ) ?. getOptions ( ) ;
87
86
88
87
if ( options ?. _experiments ?. includeStackLocals ) {
89
88
this . _stackParser = options . stackParser ;
@@ -130,7 +129,7 @@ export class LocalVariables implements Integration {
130
129
const framePromises = callFrames . map ( async ( { scopeChain, functionName, this : obj } ) => {
131
130
const localScope = scopeChain . find ( scope => scope . type === 'local' ) ;
132
131
133
- const fn = obj . className !== 'global' ? `${ obj . className } .${ functionName } ` : functionName ;
132
+ const fn = obj . className === 'global' ? functionName : `${ obj . className } .${ functionName } ` ;
134
133
135
134
if ( localScope ?. object . objectId === undefined ) {
136
135
return { function : fn } ;
@@ -190,47 +189,58 @@ export class LocalVariables implements Integration {
190
189
}
191
190
192
191
/**
193
- * Adds local variables to the exception stack trace frames.
192
+ * Adds local variables event stack frames.
194
193
*/
195
194
private async _addLocalVariables ( event : Event ) : Promise < Event > {
196
- const hash = hashFrames ( event ?. exception ?. values ?. [ 0 ] ?. stacktrace ?. frames ) ;
195
+ for ( const exception of event ?. exception ?. values || [ ] ) {
196
+ await this . _addLocalVariablesToException ( exception ) ;
197
+ }
198
+
199
+ return event ;
200
+ }
201
+
202
+ /**
203
+ * Adds local variables to the exception stack frames.
204
+ */
205
+ private async _addLocalVariablesToException ( exception : Exception ) : Promise < void > {
206
+ const hash = hashFrames ( exception ?. stacktrace ?. frames ) ;
197
207
198
208
if ( hash === undefined ) {
199
- return event ;
209
+ return ;
200
210
}
201
211
202
212
// Check if we have local variables for an exception that matches the hash
203
213
const cachedFrames = await this . _cachedFrames . get ( hash ) ;
204
214
205
215
if ( cachedFrames === undefined ) {
206
- return event ;
216
+ return ;
207
217
}
208
218
209
- const frameCount = event ?. exception ?. values ?. [ 0 ] ?. stacktrace ?. frames ?. length || 0 ;
219
+ await this . _cachedFrames . delete ( hash ) ;
220
+
221
+ const frameCount = exception . stacktrace ?. frames ?. length || 0 ;
210
222
211
223
for ( let i = 0 ; i < frameCount ; i ++ ) {
212
224
// Sentry frames are in reverse order
213
225
const frameIndex = frameCount - i - 1 ;
214
226
215
227
// Drop out if we run out of frames to match up
216
- if ( ! event ?. exception ?. values ?. [ 0 ] ?. stacktrace ?. frames ?. [ frameIndex ] || ! cachedFrames [ i ] ) {
228
+ if ( ! exception ?. stacktrace ?. frames ?. [ frameIndex ] || ! cachedFrames [ i ] ) {
217
229
break ;
218
230
}
219
231
220
232
if (
221
233
// We need to have vars to add
222
234
cachedFrames [ i ] . vars === undefined ||
223
235
// We're not interested in frames that are not in_app because the vars are not relevant
224
- event . exception . values [ 0 ] . stacktrace . frames [ frameIndex ] . in_app === false ||
236
+ exception . stacktrace . frames [ frameIndex ] . in_app === false ||
225
237
// The function names need to match
226
- ! functionNamesMatch ( event . exception . values [ 0 ] . stacktrace . frames [ frameIndex ] . function , cachedFrames [ i ] . function )
238
+ ! functionNamesMatch ( exception . stacktrace . frames [ frameIndex ] . function , cachedFrames [ i ] . function )
227
239
) {
228
240
continue ;
229
241
}
230
242
231
- event . exception . values [ 0 ] . stacktrace . frames [ frameIndex ] . vars = cachedFrames [ i ] . vars ;
243
+ exception . stacktrace . frames [ frameIndex ] . vars = cachedFrames [ i ] . vars ;
232
244
}
233
-
234
- return event ;
235
245
}
236
246
}
0 commit comments