Skip to content

feat: Use existing Debug IDs from bundles #722

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

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
21 changes: 12 additions & 9 deletions packages/bundler-plugin-core/src/debug-id-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { promisify } from "util";
import SentryCli from "@sentry/cli";
import { dynamicSamplingContextToSentryBaggageHeader } from "@sentry/utils";
import { safeFlushTelemetry } from "./sentry/telemetry";
import { stripQueryAndHashFromPath } from "./utils";
import { getDebugIdFromMagicComment, stripQueryAndHashFromPath } from "./utils";
import { setMeasurement, spanToTraceHeader, startSpan } from "@sentry/core";
import { getDynamicSamplingContextFromSpan, Scope } from "@sentry/core";
import { Client } from "@sentry/types";
Expand Down Expand Up @@ -223,7 +223,8 @@ export async function prepareBundleForDebugIdUpload(
return;
}

const debugId = determineDebugIdFromBundleSource(bundleContent);
const debugIdFromMagicComment = getDebugIdFromMagicComment(bundleContent);
const debugId = debugIdFromMagicComment || getDebugIdFromPolyfill(bundleContent);
if (debugId === undefined) {
logger.debug(
`Could not determine debug ID from bundle. This can happen if you did not clean your output folder before installing the Sentry plugin. File will not be source mapped: ${bundleFilePath}`
Expand All @@ -233,12 +234,14 @@ export async function prepareBundleForDebugIdUpload(

const uniqueUploadName = `${debugId}-${chunkIndex}`;

bundleContent += `\n//# debugId=${debugId}`;
const writeSourceFilePromise = fs.promises.writeFile(
path.join(uploadFolder, `${uniqueUploadName}.js`),
bundleContent,
"utf-8"
);
// Only add the debug ID magic comment if source file does not already contain it
const writeSourceFilePromise = debugIdFromMagicComment
? Promise.resolve()
: fs.promises.writeFile(
path.join(uploadFolder, `${uniqueUploadName}.js`),
bundleContent + `\n//# debugId=${debugId}`,
"utf-8"
);

const writeSourceMapFilePromise = determineSourceMapPathFromBundle(
bundleFilePath,
Expand Down Expand Up @@ -266,7 +269,7 @@ export async function prepareBundleForDebugIdUpload(
*
* The string pattern is injected via the debug ID injection snipped.
*/
function determineDebugIdFromBundleSource(code: string): string | undefined {
function getDebugIdFromPolyfill(code: string): string | undefined {
const match = code.match(
/sentry-dbid-([0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12})/
);
Expand Down
9 changes: 5 additions & 4 deletions packages/bundler-plugin-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
generateGlobalInjectorCode,
generateModuleMetadataInjectorCode,
getDependencies,
getDebugIdForCode,
getPackageJson,
parseMajorVersion,
replaceBooleanFlagsInCode,
stringToUUID,
stripQueryAndHashFromPath,
} from "./utils";
import * as dotenv from "dotenv";
Expand Down Expand Up @@ -588,8 +588,9 @@ export function createRollupDebugIdInjectionHooks() {
stripQueryAndHashFromPath(chunk.fileName).endsWith(ending)
)
) {
const debugId = stringToUUID(code); // generate a deterministic debug ID
const codeToInject = getDebugIdSnippet(debugId);
// Gets an existing debug ID or generates a deterministic debug ID
const debugId = getDebugIdForCode(code);
const codeToInject = getDebugIdPolyfillSnippet(debugId);

const ms = new MagicString(code, { filename: chunk.fileName });

Expand Down Expand Up @@ -740,7 +741,7 @@ export function createComponentNameAnnotateHooks(ignoredComponents?: string[]) {
};
}

export function getDebugIdSnippet(debugId: string): string {
export function getDebugIdPolyfillSnippet(debugId: string): string {
return `;{try{let e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}};`;
}

Expand Down
20 changes: 20 additions & 0 deletions packages/bundler-plugin-core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,26 @@ function lookupPackageJson(cwd: string, stopAt: string): PackageJson | undefined
return lookupPackageJson(newCwd, stopAt);
}

const DEBUG_ID_REGEX = /\/\/# debugId=([a-fA-F0-9-]+)(?![\s\S]*\/\/# debugId=)/m;

/**
* Returns a debug ID if one can be found in a magic comment
*/
export function getDebugIdFromMagicComment(code: string): string | undefined {
const match = code.match(DEBUG_ID_REGEX);
return match?.[1];
}

/**
* Gets a debug ID for the passed source code.
*
* If the source already contains a debug ID magic comment, that existing debug
* ID is used, otherwise a debug ID is created via hashing
*/
export function getDebugIdForCode(code: string): string {
return getDebugIdFromMagicComment(code) || stringToUUID(code);
}

/**
* Deterministically hashes a string and turns the hash into a uuid.
*/
Expand Down
6 changes: 3 additions & 3 deletions packages/bundler-plugin-core/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { getDebugIdSnippet } from "../src";
import { getDebugIdPolyfillSnippet } from "../src";

describe("getDebugIdSnippet", () => {
describe("getDebugIdPolyfillSnippet", () => {
it("returns the debugId injection snippet for a passed debugId", () => {
const snippet = getDebugIdSnippet("1234");
const snippet = getDebugIdPolyfillSnippet("1234");
expect(snippet).toMatchInlineSnapshot(
`";{try{let e=\\"undefined\\"!=typeof window?window:\\"undefined\\"!=typeof global?global:\\"undefined\\"!=typeof globalThis?globalThis:\\"undefined\\"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]=\\"1234\\",e._sentryDebugIdIdentifier=\\"sentry-dbid-1234\\")}catch(e){}};"`
);
Expand Down
4 changes: 2 additions & 2 deletions packages/esbuild-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
sentryUnpluginFactory,
Options,
getDebugIdSnippet,
getDebugIdPolyfillSnippet,
SentrySDKBuildFlags,
} from "@sentry/bundler-plugin-core";
import type { Logger } from "@sentry/bundler-plugin-core";
Expand Down Expand Up @@ -125,7 +125,7 @@ function esbuildDebugIdInjectionPlugin(logger: Logger): UnpluginOptions {
return {
loader: "js",
pluginName,
contents: getDebugIdSnippet(uuidv4()),
contents: getDebugIdPolyfillSnippet(uuidv4()),
};
});
},
Expand Down
4 changes: 2 additions & 2 deletions packages/webpack-plugin/src/webpack4and5.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
getDebugIdSnippet,
getDebugIdPolyfillSnippet,
Options,
sentryUnpluginFactory,
stringToUUID,
Expand Down Expand Up @@ -123,7 +123,7 @@ function webpackDebugIdInjectionPlugin(
banner: (arg?: BannerPluginCallbackArg) => {
const hash = arg?.chunk?.contentHash?.javascript ?? arg?.chunk?.hash;
const debugId = hash ? stringToUUID(hash) : uuidv4();
return getDebugIdSnippet(debugId);
return getDebugIdPolyfillSnippet(debugId);
},
})
);
Expand Down
Loading