Skip to content

Commit

Permalink
feat(core): Further optimize debug ID parsing (#14365)
Browse files Browse the repository at this point in the history
  • Loading branch information
timfish authored Nov 27, 2024
1 parent 09a31d1 commit de65590
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 39 deletions.
63 changes: 40 additions & 23 deletions packages/core/src/utils-hoist/debug-ids.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { DebugImage, StackFrame, StackParser } from '@sentry/types';
import type { DebugImage, StackParser } from '@sentry/types';
import { GLOBAL_OBJ } from './worldwide';

const debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();
type StackString = string;
type CachedResult = [string, string];

let parsedStackResults: Record<StackString, CachedResult> | undefined;
let lastKeysCount: number | undefined;
let cachedFilenameDebugIds: Record<string, string> | undefined;

/**
* Returns a map of filenames to debug identifiers.
Expand All @@ -12,38 +17,46 @@ export function getFilenameToDebugIdMap(stackParser: StackParser): Record<string
return {};
}

let debugIdStackFramesCache: Map<string, StackFrame[]>;
const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
if (cachedDebugIdStackFrameCache) {
debugIdStackFramesCache = cachedDebugIdStackFrameCache;
} else {
debugIdStackFramesCache = new Map<string, StackFrame[]>();
debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
const debugIdKeys = Object.keys(debugIdMap);

// If the count of registered globals hasn't changed since the last call, we
// can just return the cached result.
if (cachedFilenameDebugIds && debugIdKeys.length === lastKeysCount) {
return cachedFilenameDebugIds;
}

lastKeysCount = debugIdKeys.length;

// Build a map of filename -> debug_id.
return Object.keys(debugIdMap).reduce<Record<string, string>>((acc, debugIdStackTrace) => {
let parsedStack: StackFrame[];
cachedFilenameDebugIds = debugIdKeys.reduce<Record<string, string>>((acc, stackKey) => {
if (!parsedStackResults) {
parsedStackResults = {};
}

const result = parsedStackResults[stackKey];

const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);
if (cachedParsedStack) {
parsedStack = cachedParsedStack;
if (result) {
acc[result[0]] = result[1];
} else {
parsedStack = stackParser(debugIdStackTrace);
debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
}
const parsedStack = stackParser(stackKey);

for (let i = parsedStack.length - 1; i >= 0; i--) {
const stackFrame = parsedStack[i];
const file = stackFrame && stackFrame.filename;
for (let i = parsedStack.length - 1; i >= 0; i--) {
const stackFrame = parsedStack[i];
const filename = stackFrame && stackFrame.filename;
const debugId = debugIdMap[stackKey];

if (stackFrame && file) {
acc[file] = debugIdMap[debugIdStackTrace] as string;
break;
if (filename && debugId) {
acc[filename] = debugId;
parsedStackResults[stackKey] = [filename, debugId];
break;
}
}
}

return acc;
}, {});

return cachedFilenameDebugIds;
}

/**
Expand All @@ -55,6 +68,10 @@ export function getDebugImagesForResources(
): DebugImage[] {
const filenameDebugIdMap = getFilenameToDebugIdMap(stackParser);

if (!filenameDebugIdMap) {
return [];
}

const images: DebugImage[] = [];
for (const path of resource_paths) {
if (path && filenameDebugIdMap[path]) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/utils/prepareEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export function applyDebugIds(event: Event, stackParser: StackParser): void {
event!.exception!.values!.forEach(exception => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
exception.stacktrace!.frames!.forEach(frame => {
if (frame.filename) {
if (filenameDebugIdMap && frame.filename) {
frame.debug_id = filenameDebugIdMap[frame.filename];
}
});
Expand Down
16 changes: 1 addition & 15 deletions packages/node/src/integrations/anr/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as diagnosticsChannel from 'node:diagnostics_channel';
import { Worker } from 'node:worker_threads';
import { defineIntegration, getCurrentScope, getGlobalScope, getIsolationScope, mergeScopeData } from '@sentry/core';
import { GLOBAL_OBJ, getFilenameToDebugIdMap, logger } from '@sentry/core';
Expand Down Expand Up @@ -101,13 +100,6 @@ type AnrReturn = (options?: Partial<AnrIntegrationOptions>) => Integration & Anr

export const anrIntegration = defineIntegration(_anrIntegration) as AnrReturn;

function onModuleLoad(callback: () => void): void {
// eslint-disable-next-line deprecation/deprecation
diagnosticsChannel.channel('module.require.end').subscribe(() => callback());
// eslint-disable-next-line deprecation/deprecation
diagnosticsChannel.channel('module.import.asyncEnd').subscribe(() => callback());
}

/**
* Starts the ANR worker thread
*
Expand Down Expand Up @@ -161,12 +153,6 @@ async function _startWorker(
}
}

let debugImages: Record<string, string> = getFilenameToDebugIdMap(initOptions.stackParser);

onModuleLoad(() => {
debugImages = getFilenameToDebugIdMap(initOptions.stackParser);
});

const worker = new Worker(new URL(`data:application/javascript;base64,${base64WorkerScript}`), {
workerData: options,
// We don't want any Node args to be passed to the worker
Expand All @@ -185,7 +171,7 @@ async function _startWorker(
// serialized without making it a SerializedSession
const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;
// message the worker to tell it the main event loop is still running
worker.postMessage({ session, debugImages });
worker.postMessage({ session, debugImages: getFilenameToDebugIdMap(initOptions.stackParser) });
} catch (_) {
//
}
Expand Down

0 comments on commit de65590

Please sign in to comment.