Skip to content

Commit 5d698a2

Browse files
committed
Merge branch 'feat/stack-locals' of https://github.com/timfish/sentry-javascript into feat/stack-locals
2 parents 815a1d6 + 65ea442 commit 5d698a2

File tree

3 files changed

+39
-77
lines changed

3 files changed

+39
-77
lines changed

packages/node/src/integrations/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { Modules } from './modules';
77
export { ContextLines } from './contextlines';
88
export { Context } from './context';
99
export { RequestData } from './requestdata';
10+
export { LocalVariables } from './localvariables';

packages/node/src/integrations/localvariables.ts

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
import { parseSemver } from '@sentry/utils';
2-
3-
const nodeVersion = parseSemver(process.versions.node);
4-
5-
if ((nodeVersion.major || 0) < 14) {
6-
throw new Error('The LocalVariables integration requires node.js >= v14');
7-
}
8-
9-
import { Event, EventProcessor, Hub, Integration, StackFrame, StackParser } from '@sentry/types';
1+
import { getCurrentHub } from '@sentry/core';
2+
import { Event, EventProcessor, Integration, StackFrame, StackParser } from '@sentry/types';
103
import { Debugger, InspectorNotification, Runtime, Session } from 'inspector';
114
import { LRUMap } from 'lru_map';
125

6+
import { NodeClient } from '../client';
7+
138
/**
149
* Promise API is available as `Experimental` and in Node 19 only.
1510
*
@@ -67,24 +62,6 @@ function hashFrames(frames: StackFrame[] | undefined): string | undefined {
6762
return frames.reduce((acc, frame) => `${acc},${frame.function},${frame.lineno},${frame.colno}`, '');
6863
}
6964

70-
type HashFromStackFn = (stack: string | undefined) => string | undefined;
71-
72-
/**
73-
* Creates a function used to hash stack strings
74-
*
75-
* We use the stack parser to create a unique hash from the exception stack trace
76-
* This is used to lookup vars when the exception passes through the event processor
77-
*/
78-
function createHashFn(stackParser: StackParser | undefined): HashFromStackFn {
79-
return (stack: string | undefined) => {
80-
if (stackParser === undefined || stack === undefined) {
81-
return undefined;
82-
}
83-
84-
return hashFrames(stackParser(stack, 1));
85-
};
86-
}
87-
8865
interface FrameVariables {
8966
function: string;
9067
vars?: Record<string, unknown>;
@@ -100,29 +77,38 @@ export class LocalVariables implements Integration {
10077

10178
private readonly _session: AsyncSession = new AsyncSession();
10279
private readonly _cachedFrames: LRUMap<string, Promise<FrameVariables[]>> = new LRUMap(50);
103-
104-
public constructor() {
105-
this._session.connect();
106-
this._session.on('Debugger.paused', this._handlePaused.bind(this));
107-
this._session.post('Debugger.enable');
108-
// We only want to pause on uncaught exceptions
109-
this._session.post('Debugger.setPauseOnExceptions', { state: 'uncaught' });
110-
}
80+
private _stackParser: StackParser | undefined;
11181

11282
/**
11383
* @inheritDoc
11484
*/
115-
public setupOnce(addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
116-
this._stackHasher = createHashFn(getCurrentHub().getClient()?.getOptions().stackParser);
85+
public setupOnce(addGlobalEventProcessor: (callback: EventProcessor) => void): void {
86+
const options = getCurrentHub().getClient<NodeClient>()?.getOptions();
87+
88+
if (options?.includeStackLocals) {
89+
this._stackParser = options.stackParser;
11790

118-
addGlobalEventProcessor(async event => this._addLocalVariables(event));
91+
this._session.connect();
92+
this._session.on('Debugger.paused', this._handlePaused.bind(this));
93+
this._session.post('Debugger.enable');
94+
// We only want to pause on uncaught exceptions
95+
this._session.post('Debugger.setPauseOnExceptions', { state: 'uncaught' });
96+
97+
addGlobalEventProcessor(async event => this._addLocalVariables(event));
98+
}
11999
}
120100

121101
/**
122102
* We use the stack parser to create a unique hash from the exception stack trace
123-
* This is used to lookup vars when
103+
* This is used to lookup vars when the exception passes through the event processor
124104
*/
125-
private _stackHasher: HashFromStackFn = _ => undefined;
105+
private _hashFromStack(stack: string | undefined): string | undefined {
106+
if (this._stackParser === undefined || stack === undefined) {
107+
return undefined;
108+
}
109+
110+
return hashFrames(this._stackParser(stack, 1));
111+
}
126112

127113
/**
128114
* Handle the pause event
@@ -135,7 +121,7 @@ export class LocalVariables implements Integration {
135121
}
136122

137123
// data.description contains the original error.stack
138-
const exceptionHash = this._stackHasher(data?.description);
124+
const exceptionHash = this._hashFromStack(data?.description);
139125

140126
if (exceptionHash == undefined) {
141127
return;
@@ -223,7 +209,7 @@ export class LocalVariables implements Integration {
223209
const frameCount = event?.exception?.values?.[0]?.stacktrace?.frames?.length || 0;
224210

225211
for (let i = 0; i < frameCount; i++) {
226-
// Sentry frames are already in reverse order
212+
// Sentry frames are in reverse order
227213
const frameIndex = frameCount - i - 1;
228214

229215
// Drop out if we run out of frames to match up

packages/node/src/sdk.ts

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@ import {
77
Integrations as CoreIntegrations,
88
setHubOnCarrier,
99
} from '@sentry/core';
10-
import { Integration, SessionStatus, StackParser } from '@sentry/types';
10+
import { SessionStatus, StackParser } from '@sentry/types';
1111
import {
1212
createStackParser,
13-
dynamicRequire,
1413
GLOBAL_OBJ,
1514
logger,
1615
nodeStackLineParser,
17-
parseSemver,
1816
stackParserFromStackParserOptions,
1917
} from '@sentry/utils';
2018
import * as domain from 'domain';
@@ -26,6 +24,7 @@ import {
2624
ContextLines,
2725
Http,
2826
LinkedErrors,
27+
LocalVariables,
2928
Modules,
3029
OnUncaughtException,
3130
OnUnhandledRejection,
@@ -52,6 +51,7 @@ export const defaultIntegrations = [
5251
new RequestData(),
5352
// Misc
5453
new LinkedErrors(),
54+
new LocalVariables(),
5555
];
5656

5757
/**
@@ -114,15 +114,13 @@ export function init(options: NodeOptions = {}): void {
114114
const carrier = getMainCarrier();
115115
const autoloadedIntegrations = carrier.__SENTRY__?.integrations || [];
116116

117-
options.defaultIntegrations = getDefaultIntegrations(options, autoloadedIntegrations);
118-
119-
const nodeVersion = parseSemver(process.versions.node);
120-
121-
if (options.includeStackLocals && (nodeVersion.major || 0) >= 14) {
122-
// eslint-disable-next-line @typescript-eslint/no-var-requires
123-
const { LocalVariables } = require('./integrations/localvariables');
124-
options.defaultIntegrations.push(new LocalVariables());
125-
}
117+
options.defaultIntegrations =
118+
options.defaultIntegrations === false
119+
? []
120+
: [
121+
...(Array.isArray(options.defaultIntegrations) ? options.defaultIntegrations : defaultIntegrations),
122+
...autoloadedIntegrations,
123+
];
126124

127125
if (options.dsn === undefined && process.env.SENTRY_DSN) {
128126
options.dsn = process.env.SENTRY_DSN;
@@ -177,29 +175,6 @@ export function init(options: NodeOptions = {}): void {
177175
}
178176
}
179177

180-
function getDefaultIntegrations(options: NodeOptions, autoloadedIntegrations: Integration[]): Integration[] {
181-
const integrations =
182-
options.defaultIntegrations === false
183-
? []
184-
: [
185-
...(Array.isArray(options.defaultIntegrations) ? options.defaultIntegrations : defaultIntegrations),
186-
...autoloadedIntegrations,
187-
];
188-
189-
const nodeVersion = parseSemver(process.versions.node);
190-
191-
if (options.includeStackLocals && (nodeVersion.major || 0) >= 14) {
192-
const { LocalVariables } = dynamicRequire(
193-
module,
194-
'./integrations/localvariables',
195-
) as typeof import('./integrations/localvariables');
196-
197-
integrations.push(new LocalVariables());
198-
}
199-
200-
return integrations;
201-
}
202-
203178
/**
204179
* This is the getter for lastEventId.
205180
*

0 commit comments

Comments
 (0)