Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Further optimize debug ID parsing #14365

Merged
merged 8 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 type { Contexts, Event, EventHint, Integration, IntegrationFn, ScopeData } from '@sentry/types';
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
63 changes: 40 additions & 23 deletions packages/utils/src/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
Loading