From 97e6ff36523934b6631965f9a22a4b5403068be8 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:11:49 -0400 Subject: [PATCH 01/20] [v7] feat: Remove references to @sentry/apm (#4845) Removes all references to `@sentry/apm`, a deprecated package we do not use anymore. --- packages/integrations/src/vue.ts | 58 ++++---------------- packages/react/src/profiler.tsx | 90 +++----------------------------- 2 files changed, 16 insertions(+), 132 deletions(-) diff --git a/packages/integrations/src/vue.ts b/packages/integrations/src/vue.ts index 1b1cf3caa63a..12c55f53df32 100644 --- a/packages/integrations/src/vue.ts +++ b/packages/integrations/src/vue.ts @@ -5,15 +5,6 @@ import { basename, getGlobalObject, logger, timestampWithMs } from '@sentry/util import { IS_DEBUG_BUILD } from './flags'; -/** - * Used to extract Tracing integration from the current client, - * without the need to import `Tracing` itself from the @sentry/apm package. - * @deprecated as @sentry/tracing should be used over @sentry/apm. - */ -const TRACING_GETTER = { - id: 'Tracing', -} as any as IntegrationClass; - /** * Used to extract BrowserTracing integration from @sentry/tracing */ @@ -150,7 +141,6 @@ export class Vue implements Integration { private readonly _componentsCache: { [key: string]: string } = {}; private _rootSpan?: Span; private _rootSpanTimer?: ReturnType; - private _tracingActivity?: number; /** * @inheritDoc @@ -260,30 +250,12 @@ export class Vue implements Integration { vm.$once(`hook:${hook}`, () => { // Create an activity on the first event call. There'll be no second call, as rootSpan will be in place, // thus new event handler won't be attached. - - // We do this whole dance with `TRACING_GETTER` to prevent `@sentry/apm` from becoming a peerDependency. - // We also need to ask for the `.constructor`, as `pushActivity` and `popActivity` are static, not instance methods. - /* eslint-disable @typescript-eslint/no-unsafe-member-access */ - // eslint-disable-next-line deprecation/deprecation - const tracingIntegration = getCurrentHub().getIntegration(TRACING_GETTER); - if (tracingIntegration) { - this._tracingActivity = (tracingIntegration as any).constructor.pushActivity('Vue Application Render'); - const transaction = (tracingIntegration as any).constructor.getTransaction(); - if (transaction) { - this._rootSpan = transaction.startChild({ - description: 'Application Render', - op: VUE_OP, - }); - } - // Use functionality from @sentry/tracing - } else { - const activeTransaction = getActiveTransaction(getCurrentHub()); - if (activeTransaction) { - this._rootSpan = activeTransaction.startChild({ - description: 'Application Render', - op: VUE_OP, - }); - } + const activeTransaction = getActiveTransaction(getCurrentHub()); + if (activeTransaction) { + this._rootSpan = activeTransaction.startChild({ + description: 'Application Render', + op: VUE_OP, + }); } /* eslint-enable @typescript-eslint/no-unsafe-member-access */ }); @@ -349,24 +321,13 @@ export class Vue implements Integration { }; /** Finish top-level span and activity with a debounce configured using `timeout` option */ - private _finishRootSpan(timestamp: number, getCurrentHub: () => Hub): void { + private _finishRootSpan(timestamp: number, _getCurrentHub: () => Hub): void { if (this._rootSpanTimer) { clearTimeout(this._rootSpanTimer); } this._rootSpanTimer = setTimeout(() => { - if (this._tracingActivity) { - // We do this whole dance with `TRACING_GETTER` to prevent `@sentry/apm` from becoming a peerDependency. - // We also need to ask for the `.constructor`, as `pushActivity` and `popActivity` are static, not instance methods. - // eslint-disable-next-line deprecation/deprecation - const tracingIntegration = getCurrentHub().getIntegration(TRACING_GETTER); - if (tracingIntegration) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - (tracingIntegration as any).constructor.popActivity(this._tracingActivity); - } - } - - // We should always finish the span, only should pop activity if using @sentry/apm + // We should always finish the span if (this._rootSpan) { this._rootSpan.finish(timestamp); } @@ -379,8 +340,7 @@ export class Vue implements Integration { this._options.Vue.mixin({ beforeCreate(this: ViewModel): void { - // eslint-disable-next-line deprecation/deprecation - if (getCurrentHub().getIntegration(TRACING_GETTER) || getCurrentHub().getIntegration(BROWSER_TRACING_GETTER)) { + if (getCurrentHub().getIntegration(BROWSER_TRACING_GETTER)) { // `this` points to currently rendered component applyTracingHooks(this, getCurrentHub); } else { diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx index acf764347c69..c52d503eb92b 100644 --- a/packages/react/src/profiler.tsx +++ b/packages/react/src/profiler.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { getCurrentHub, Hub } from '@sentry/browser'; -import { Integration, IntegrationClass, Span, Transaction } from '@sentry/types'; +import { Span, Transaction } from '@sentry/types'; import { timestampWithMs } from '@sentry/utils'; import hoistNonReactStatics from 'hoist-non-react-statics'; import * as React from 'react'; @@ -10,66 +10,6 @@ import { REACT_MOUNT_OP, REACT_RENDER_OP, REACT_UPDATE_OP } from './constants'; export const UNKNOWN_COMPONENT = 'unknown'; -const TRACING_GETTER = ({ - id: 'Tracing', -} as any) as IntegrationClass; - -let globalTracingIntegration: Integration | null = null; -/** @deprecated remove when @sentry/apm no longer used */ -const getTracingIntegration = (): Integration | null => { - if (globalTracingIntegration) { - return globalTracingIntegration; - } - - globalTracingIntegration = getCurrentHub().getIntegration(TRACING_GETTER); - return globalTracingIntegration; -}; - -/** - * pushActivity creates an new react activity. - * Is a no-op if Tracing integration is not valid - * @param name displayName of component that started activity - * @deprecated remove when @sentry/apm no longer used - */ -function pushActivity(name: string, op: string): number | null { - if (globalTracingIntegration === null) { - return null; - } - - return (globalTracingIntegration as any).constructor.pushActivity(name, { - description: `<${name}>`, - op, - }); -} - -/** - * popActivity removes a React activity. - * Is a no-op if Tracing integration is not valid. - * @param activity id of activity that is being popped - * @deprecated remove when @sentry/apm no longer used - */ -function popActivity(activity: number | null): void { - if (activity === null || globalTracingIntegration === null) { - return; - } - - (globalTracingIntegration as any).constructor.popActivity(activity); -} - -/** - * Obtain a span given an activity id. - * Is a no-op if Tracing integration is not valid. - * @param activity activity id associated with obtained span - * @deprecated remove when @sentry/apm no longer used - */ -function getActivitySpan(activity: number | null): Span | undefined { - if (activity === null || globalTracingIntegration === null) { - return undefined; - } - - return (globalTracingIntegration as any).constructor.getActivitySpan(activity) as Span | undefined; -} - export type ProfilerProps = { // The name of the component being profiled. name: string; @@ -95,9 +35,6 @@ class Profiler extends React.Component { */ protected _mountSpan: Span | undefined = undefined; - // The activity representing how long it takes to mount a component. - private _mountActivity: number | null = null; - // eslint-disable-next-line @typescript-eslint/member-ordering public static defaultProps: Partial = { disabled: false, @@ -113,19 +50,12 @@ class Profiler extends React.Component { return; } - // If they are using @sentry/apm, we need to push/pop activities - // eslint-disable-next-line deprecation/deprecation - if (getTracingIntegration()) { - // eslint-disable-next-line deprecation/deprecation - this._mountActivity = pushActivity(name, REACT_MOUNT_OP); - } else { - const activeTransaction = getActiveTransaction(); - if (activeTransaction) { - this._mountSpan = activeTransaction.startChild({ - description: `<${name}>`, - op: REACT_MOUNT_OP, - }); - } + const activeTransaction = getActiveTransaction(); + if (activeTransaction) { + this._mountSpan = activeTransaction.startChild({ + description: `<${name}>`, + op: REACT_MOUNT_OP, + }); } } @@ -133,12 +63,6 @@ class Profiler extends React.Component { public componentDidMount(): void { if (this._mountSpan) { this._mountSpan.finish(); - } else { - // eslint-disable-next-line deprecation/deprecation - this._mountSpan = getActivitySpan(this._mountActivity); - // eslint-disable-next-line deprecation/deprecation - popActivity(this._mountActivity); - this._mountActivity = null; } } From 57d37c29249d5c71eac486c86e5bb91a4c3c4159 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:12:47 -0400 Subject: [PATCH 02/20] [v7] feat(core): Delete API class (#4848) Removes the deprecated `API` class. --- packages/core/src/api.ts | 69 +----------------------------- packages/core/src/index.ts | 2 - packages/core/test/lib/api.test.ts | 39 +++++++++++------ 3 files changed, 26 insertions(+), 84 deletions(-) diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts index bace0ad07591..8d76cb135400 100644 --- a/packages/core/src/api.ts +++ b/packages/core/src/api.ts @@ -17,73 +17,6 @@ export interface APIDetails { readonly tunnel?: string; } -/** - * Helper class to provide urls, headers and metadata that can be used to form - * different types of requests to Sentry endpoints. - * Supports both envelopes and regular event requests. - * - * @deprecated Please use APIDetails - **/ -export class API { - /** The DSN as passed to Sentry.init() */ - public dsn: DsnLike; - - /** Metadata about the SDK (name, version, etc) for inclusion in envelope headers */ - public metadata: SdkMetadata; - - /** The internally used Dsn object. */ - private readonly _dsnObject: DsnComponents; - - /** The envelope tunnel to use. */ - private readonly _tunnel?: string; - - /** Create a new instance of API */ - public constructor(dsn: DsnLike, metadata: SdkMetadata = {}, tunnel?: string) { - this.dsn = dsn; - this._dsnObject = makeDsn(dsn); - this.metadata = metadata; - this._tunnel = tunnel; - } - - /** Returns the Dsn object. */ - public getDsn(): DsnComponents { - return this._dsnObject; - } - - /** Does this transport force envelopes? */ - public forceEnvelope(): boolean { - return !!this._tunnel; - } - - /** Returns the prefix to construct Sentry ingestion API endpoints. */ - public getBaseApiEndpoint(): string { - return getBaseApiEndpoint(this._dsnObject); - } - - /** Returns the store endpoint URL. */ - public getStoreEndpoint(): string { - return getStoreEndpoint(this._dsnObject); - } - - /** - * Returns the store endpoint URL with auth in the query string. - * - * Sending auth as part of the query string and not as custom HTTP headers avoids CORS preflight requests. - */ - public getStoreEndpointWithUrlEncodedAuth(): string { - return getStoreEndpointWithUrlEncodedAuth(this._dsnObject); - } - - /** - * Returns the envelope endpoint URL with auth in the query string. - * - * Sending auth as part of the query string and not as custom HTTP headers avoids CORS preflight requests. - */ - public getEnvelopeEndpointWithUrlEncodedAuth(): string { - return getEnvelopeEndpointWithUrlEncodedAuth(this._dsnObject, this._tunnel); - } -} - /** Initializes API Details */ export function initAPIDetails(dsn: DsnLike, metadata?: SdkMetadata, tunnel?: string): APIDetails { return { @@ -117,7 +50,7 @@ function _encodedAuth(dsn: DsnComponents): string { } /** Returns the store endpoint URL. */ -function getStoreEndpoint(dsn: DsnComponents): string { +export function getStoreEndpoint(dsn: DsnComponents): string { return _getIngestEndpoint(dsn, 'store'); } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index f09d804d3bed..b066724ce099 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -15,8 +15,6 @@ export { } from '@sentry/minimal'; export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, makeMain, Scope, Session } from '@sentry/hub'; export { - // eslint-disable-next-line deprecation/deprecation - API, APIDetails, getEnvelopeEndpointWithUrlEncodedAuth, getStoreEndpointWithUrlEncodedAuth, diff --git a/packages/core/test/lib/api.test.ts b/packages/core/test/lib/api.test.ts index 14b44aed9602..af3a7bfb8ca3 100644 --- a/packages/core/test/lib/api.test.ts +++ b/packages/core/test/lib/api.test.ts @@ -1,27 +1,38 @@ /* eslint-disable deprecation/deprecation */ import { makeDsn } from '@sentry/utils'; -import { API, getReportDialogEndpoint, getRequestHeaders } from '../../src/api'; +import { + getEnvelopeEndpointWithUrlEncodedAuth, + getReportDialogEndpoint, + getRequestHeaders, + getStoreEndpoint, + getStoreEndpointWithUrlEncodedAuth, + initAPIDetails, +} from '../../src/api'; const ingestDsn = 'https://abc@xxxx.ingest.sentry.io:1234/subpath/123'; const dsnPublic = 'https://abc@sentry.io:1234/subpath/123'; const legacyDsn = 'https://abc:123@sentry.io:1234/subpath/123'; const tunnel = 'https://hello.com/world'; +const ingestDsnAPI = initAPIDetails(ingestDsn); +const dsnPublicAPI = initAPIDetails(dsnPublic); + describe('API', () => { test('getStoreEndpoint', () => { - expect(new API(dsnPublic).getStoreEndpointWithUrlEncodedAuth()).toEqual( + expect(getStoreEndpointWithUrlEncodedAuth(dsnPublicAPI.dsn)).toEqual( 'https://sentry.io:1234/subpath/api/123/store/?sentry_key=abc&sentry_version=7', ); - expect(new API(dsnPublic).getStoreEndpoint()).toEqual('https://sentry.io:1234/subpath/api/123/store/'); - expect(new API(ingestDsn).getStoreEndpoint()).toEqual('https://xxxx.ingest.sentry.io:1234/subpath/api/123/store/'); + expect(getStoreEndpoint(dsnPublicAPI.dsn)).toEqual('https://sentry.io:1234/subpath/api/123/store/'); + expect(getStoreEndpoint(ingestDsnAPI.dsn)).toEqual('https://xxxx.ingest.sentry.io:1234/subpath/api/123/store/'); }); test('getEnvelopeEndpoint', () => { - expect(new API(dsnPublic).getEnvelopeEndpointWithUrlEncodedAuth()).toEqual( + expect(getEnvelopeEndpointWithUrlEncodedAuth(dsnPublicAPI.dsn)).toEqual( 'https://sentry.io:1234/subpath/api/123/envelope/?sentry_key=abc&sentry_version=7', ); - expect(new API(dsnPublic, {}, tunnel).getEnvelopeEndpointWithUrlEncodedAuth()).toEqual(tunnel); + const dsnPublicAPIWithTunnel = initAPIDetails(dsnPublic, {}, tunnel); + expect(getEnvelopeEndpointWithUrlEncodedAuth(dsnPublicAPIWithTunnel.dsn, tunnel)).toEqual(tunnel); }); test('getRequestHeaders', () => { @@ -118,13 +129,13 @@ describe('API', () => { ); }); - test('getDsn', () => { - expect(new API(dsnPublic).getDsn().host).toEqual(makeDsn(dsnPublic).host); - expect(new API(dsnPublic).getDsn().path).toEqual(makeDsn(dsnPublic).path); - expect(new API(dsnPublic).getDsn().pass).toEqual(makeDsn(dsnPublic).pass); - expect(new API(dsnPublic).getDsn().port).toEqual(makeDsn(dsnPublic).port); - expect(new API(dsnPublic).getDsn().protocol).toEqual(makeDsn(dsnPublic).protocol); - expect(new API(dsnPublic).getDsn().projectId).toEqual(makeDsn(dsnPublic).projectId); - expect(new API(dsnPublic).getDsn().publicKey).toEqual(makeDsn(dsnPublic).publicKey); + test('initAPIDetails dsn', () => { + expect(dsnPublicAPI.dsn.host).toEqual(makeDsn(dsnPublic).host); + expect(dsnPublicAPI.dsn.path).toEqual(makeDsn(dsnPublic).path); + expect(dsnPublicAPI.dsn.pass).toEqual(makeDsn(dsnPublic).pass); + expect(dsnPublicAPI.dsn.port).toEqual(makeDsn(dsnPublic).port); + expect(dsnPublicAPI.dsn.protocol).toEqual(makeDsn(dsnPublic).protocol); + expect(dsnPublicAPI.dsn.projectId).toEqual(makeDsn(dsnPublic).projectId); + expect(dsnPublicAPI.dsn.publicKey).toEqual(makeDsn(dsnPublic).publicKey); }); }); From 424df271f1b58de8b67d50cff2129de87aa861c1 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:13:38 -0400 Subject: [PATCH 03/20] [v7] feat: Delete deprecated `startSpan` and `child` methods (#4849) Remove deprecated methods `startSpan` and `child`. These deprecated methods were removed in favour of `span.startChild`. --- packages/hub/src/hub.ts | 9 --------- packages/tracing/src/span.ts | 10 ---------- packages/types/src/hub.ts | 6 ------ packages/types/src/span.ts | 8 -------- 4 files changed, 33 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index 67761953abfa..b6ebffc74866 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -14,8 +14,6 @@ import { Primitive, SessionContext, Severity, - Span, - SpanContext, Transaction, TransactionContext, User, @@ -385,13 +383,6 @@ export class Hub implements HubInterface { } } - /** - * @inheritDoc - */ - public startSpan(context: SpanContext): Span { - return this._callExtensionMethod('startSpan', context); - } - /** * @inheritDoc */ diff --git a/packages/tracing/src/span.ts b/packages/tracing/src/span.ts index 990f56ce981c..baece680f52c 100644 --- a/packages/tracing/src/span.ts +++ b/packages/tracing/src/span.ts @@ -149,16 +149,6 @@ export class Span implements SpanInterface { } } - /** - * @inheritDoc - * @deprecated - */ - public child( - spanContext?: Pick>, - ): Span { - return this.startChild(spanContext); - } - /** * @inheritDoc */ diff --git a/packages/types/src/hub.ts b/packages/types/src/hub.ts index c80ea1b51686..49452266fe9f 100644 --- a/packages/types/src/hub.ts +++ b/packages/types/src/hub.ts @@ -7,7 +7,6 @@ import { Primitive } from './misc'; import { Scope } from './scope'; import { Session, SessionContext } from './session'; import { Severity } from './severity'; -import { Span, SpanContext } from './span'; import { CustomSamplingContext, Transaction, TransactionContext } from './transaction'; import { User } from './user'; @@ -180,11 +179,6 @@ export interface Hub { /** Returns all trace headers that are currently on the top scope. */ traceHeaders(): { [key: string]: string }; - /** - * @deprecated No longer does anything. Use use {@link Transaction.startChild} instead. - */ - startSpan(context: SpanContext): Span; - /** * Starts a new `Transaction` and returns it. This is the entry point to manual tracing instrumentation. * diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 09b69454835e..d26887a93f2a 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -128,14 +128,6 @@ export interface Span extends SpanContext { */ setHttpStatus(httpStatus: number): this; - /** - * Use {@link startChild} - * @deprecated - */ - child( - spanContext?: Pick>, - ): Span; - /** * Creates a new `Span` while setting the current `Span.id` as `parentSpanId`. * Also the `sampled` decision will be inherited. From 5a7f1450a38f045b974233e514fd6d26da2a5c64 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:14:07 -0400 Subject: [PATCH 04/20] feat(core): Remove whitelistUrls/blacklistUrls (#4850) --- packages/browser/src/backend.ts | 6 ----- .../core/src/integrations/inboundfilters.ts | 23 ++----------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/packages/browser/src/backend.ts b/packages/browser/src/backend.ts index 4cdef3d11047..89cf843d48ae 100644 --- a/packages/browser/src/backend.ts +++ b/packages/browser/src/backend.ts @@ -23,12 +23,6 @@ export interface BrowserOptions extends Options { * By default, all errors will be sent. */ denyUrls?: Array; - - /** @deprecated use {@link Options.allowUrls} instead. */ - whitelistUrls?: Array; - - /** @deprecated use {@link Options.denyUrls} instead. */ - blacklistUrls?: Array; } /** diff --git a/packages/core/src/integrations/inboundfilters.ts b/packages/core/src/integrations/inboundfilters.ts index ff6c616c442d..83d635ff3256 100644 --- a/packages/core/src/integrations/inboundfilters.ts +++ b/packages/core/src/integrations/inboundfilters.ts @@ -13,11 +13,6 @@ export interface InboundFiltersOptions { denyUrls: Array; ignoreErrors: Array; ignoreInternal: boolean; - - /** @deprecated use {@link InboundFiltersOptions.allowUrls} instead. */ - whitelistUrls: Array; - /** @deprecated use {@link InboundFiltersOptions.denyUrls} instead. */ - blacklistUrls: Array; } /** Inbound filters configurable by the user */ @@ -60,22 +55,8 @@ export function _mergeOptions( clientOptions: Partial = {}, ): Partial { return { - allowUrls: [ - // eslint-disable-next-line deprecation/deprecation - ...(internalOptions.whitelistUrls || []), - ...(internalOptions.allowUrls || []), - // eslint-disable-next-line deprecation/deprecation - ...(clientOptions.whitelistUrls || []), - ...(clientOptions.allowUrls || []), - ], - denyUrls: [ - // eslint-disable-next-line deprecation/deprecation - ...(internalOptions.blacklistUrls || []), - ...(internalOptions.denyUrls || []), - // eslint-disable-next-line deprecation/deprecation - ...(clientOptions.blacklistUrls || []), - ...(clientOptions.denyUrls || []), - ], + allowUrls: [...(internalOptions.allowUrls || []), ...(clientOptions.allowUrls || [])], + denyUrls: [...(internalOptions.denyUrls || []), ...(clientOptions.denyUrls || [])], ignoreErrors: [ ...(internalOptions.ignoreErrors || []), ...(clientOptions.ignoreErrors || []), From f855260c904f939b712b9fb7044a3528a51d73b4 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:14:50 -0400 Subject: [PATCH 05/20] feat(gatsby): Remove Sentry from window (#4857) --- packages/gatsby/gatsby-browser.js | 8 +++----- packages/gatsby/test/gatsby-browser.test.ts | 10 ---------- packages/gatsby/test/integration.test.tsx | 3 ++- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/packages/gatsby/gatsby-browser.js b/packages/gatsby/gatsby-browser.js index 5cf1e3d26f80..598ce44ade08 100644 --- a/packages/gatsby/gatsby-browser.js +++ b/packages/gatsby/gatsby-browser.js @@ -6,12 +6,11 @@ exports.onClientEntry = function (_, pluginParams) { const areOptionsDefined = areSentryOptionsDefined(pluginParams); if (isIntialized) { - window.Sentry = Sentry; // For backwards compatibility if (areOptionsDefined) { console.warn( 'Sentry Logger [Warn]: The SDK was initialized in the Sentry config file, but options were found in the Gatsby config. ' + - 'These have been ignored, merge them to the Sentry config if you want to use them.\n' + - 'Learn more about the Gatsby SDK on https://docs.sentry.io/platforms/javascript/guides/gatsby/', + 'These have been ignored, merge them to the Sentry config if you want to use them.\n' + + 'Learn more about the Gatsby SDK on https://docs.sentry.io/platforms/javascript/guides/gatsby/', ); } return; @@ -20,7 +19,7 @@ exports.onClientEntry = function (_, pluginParams) { if (!areOptionsDefined) { console.error( 'Sentry Logger [Error]: No config for the Gatsby SDK was found.\n' + - 'Learn how to configure it on https://docs.sentry.io/platforms/javascript/guides/gatsby/', + 'Learn how to configure it on https://docs.sentry.io/platforms/javascript/guides/gatsby/', ); return; } @@ -32,7 +31,6 @@ exports.onClientEntry = function (_, pluginParams) { dsn: __SENTRY_DSN__, ...pluginParams, }); - window.Sentry = Sentry; // For backwards compatibility }; function isSentryInitialized() { diff --git a/packages/gatsby/test/gatsby-browser.test.ts b/packages/gatsby/test/gatsby-browser.test.ts index a3c98524a2fd..a2044dd2c8a9 100644 --- a/packages/gatsby/test/gatsby-browser.test.ts +++ b/packages/gatsby/test/gatsby-browser.test.ts @@ -36,10 +36,6 @@ describe('onClientEntry', () => { tracingAddExtensionMethods = jest.fn(); }); - afterEach(() => { - (window as any).Sentry = undefined; - }); - it.each([ [{}, ['dsn', 'release']], [{ key: 'value' }, ['dsn', 'release', 'key']], @@ -54,7 +50,6 @@ describe('onClientEntry', () => { describe('inits Sentry once', () => { afterEach(() => { - delete (window as any).Sentry; delete (window as any).__SENTRY__; (global.console.warn as jest.Mock).mockClear(); (global.console.error as jest.Mock).mockClear(); @@ -78,7 +73,6 @@ describe('onClientEntry', () => { // eslint-disable-next-line no-console expect(console.error).not.toHaveBeenCalled(); expect(sentryInit).not.toHaveBeenCalled(); - expect((window as any).Sentry).toBeDefined(); }); it('initialized in injected config, with pluginParams', () => { @@ -94,7 +88,6 @@ describe('onClientEntry', () => { // eslint-disable-next-line no-console expect(console.error).not.toHaveBeenCalled(); expect(sentryInit).not.toHaveBeenCalled(); - expect((window as any).Sentry).toBeDefined(); }); it('not initialized in injected config, without pluginParams', () => { @@ -108,7 +101,6 @@ describe('onClientEntry', () => { Learn how to configure it on https://docs.sentry.io/platforms/javascript/guides/gatsby/", ] `); - expect((window as any).Sentry).not.toBeDefined(); }); it('not initialized in injected config, with pluginParams', () => { @@ -125,7 +117,6 @@ describe('onClientEntry', () => { "release": "release", } `); - expect((window as any).Sentry).toBeDefined(); }); }); @@ -164,7 +155,6 @@ describe('onClientEntry', () => { it('does not run if plugin params are undefined', () => { onClientEntry(); expect(sentryInit).toHaveBeenCalledTimes(0); - expect((window as any).Sentry).toBeUndefined(); expect(tracingAddExtensionMethods).toHaveBeenCalledTimes(0); }); }); diff --git a/packages/gatsby/test/integration.test.tsx b/packages/gatsby/test/integration.test.tsx index e758aa90a79d..18c738ba2ac2 100644 --- a/packages/gatsby/test/integration.test.tsx +++ b/packages/gatsby/test/integration.test.tsx @@ -5,6 +5,7 @@ import { useEffect } from 'react'; import * as React from 'react'; import { onClientEntry } from '../gatsby-browser'; +import * as Sentry from '../src'; beforeAll(() => { (global as any).__SENTRY_RELEASE__ = '683f3a6ab819d47d23abfca9a914c81f0524d35b'; @@ -28,7 +29,7 @@ describe('useEffect', () => { function TestComponent() { useEffect(() => { const error = new Error('testing 123'); - (window as any).Sentry.captureException(error); + Sentry.captureException(error); }); return
Hello
; From f1e9da28e9c8dbd9e6ecf1bd446437f8cd04700e Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:15:35 -0400 Subject: [PATCH 06/20] feat(hub): Remove getActiveDomain (#4858) Removes `getActiveDomain` function and corresponding type. --- packages/hub/src/hub.ts | 23 ----------------------- packages/hub/src/index.ts | 4 ---- 2 files changed, 27 deletions(-) diff --git a/packages/hub/src/hub.ts b/packages/hub/src/hub.ts index b6ebffc74866..94c8e3ea91fe 100644 --- a/packages/hub/src/hub.ts +++ b/packages/hub/src/hub.ts @@ -80,15 +80,6 @@ export interface Carrier { }; } -/** - * @hidden - * @deprecated Can be removed once `Hub.getActiveDomain` is removed. - */ -export interface DomainAsCarrier extends Carrier { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - members: { [key: string]: any }[]; -} - /** * @inheritDoc */ @@ -559,20 +550,6 @@ export function getCurrentHub(): Hub { return getHubFromCarrier(registry); } -/** - * Returns the active domain, if one exists - * @deprecated No longer used; remove in v7 - * @returns The domain, or undefined if there is no active domain - */ -// eslint-disable-next-line deprecation/deprecation -export function getActiveDomain(): DomainAsCarrier | undefined { - IS_DEBUG_BUILD && logger.warn('Function `getActiveDomain` is deprecated and will be removed in a future version.'); - - const sentry = getMainCarrier().__SENTRY__; - - return sentry && sentry.extensions && sentry.extensions.domain && sentry.extensions.domain.active; -} - /** * Try to read the hub from an active domain, and fallback to the registry if one doesn't exist * @returns discovered hub diff --git a/packages/hub/src/index.ts b/packages/hub/src/index.ts index 9c0a77625dc2..3d3b97fa239b 100644 --- a/packages/hub/src/index.ts +++ b/packages/hub/src/index.ts @@ -2,8 +2,6 @@ export { addGlobalEventProcessor, Scope } from './scope'; export { Session } from './session'; export { SessionFlusher } from './sessionflusher'; export { - // eslint-disable-next-line deprecation/deprecation - getActiveDomain, getCurrentHub, getHubFromCarrier, getMainCarrier, @@ -11,7 +9,5 @@ export { makeMain, setHubOnCarrier, Carrier, - // eslint-disable-next-line deprecation/deprecation - DomainAsCarrier, Layer, } from './hub'; From 55b057049fc7f02876e724c3f5d6b68949357b03 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:17:36 -0400 Subject: [PATCH 07/20] feat(types): Remove deprecated user dsn field (#4864) The `user` dsn component was renamed to `publicKey`. This PR removes that from the dsn field. --- packages/types/src/dsn.ts | 2 -- packages/utils/src/dsn.ts | 6 ------ 2 files changed, 8 deletions(-) diff --git a/packages/types/src/dsn.ts b/packages/types/src/dsn.ts index b21130802903..761c52889caf 100644 --- a/packages/types/src/dsn.ts +++ b/packages/types/src/dsn.ts @@ -5,8 +5,6 @@ export type DsnProtocol = 'http' | 'https'; export interface DsnComponents { /** Protocol used to connect to Sentry. */ protocol: DsnProtocol; - /** Public authorization key (deprecated, renamed to publicKey). */ - user?: string; /** Public authorization key. */ publicKey?: string; /** Private authorization key (deprecated, optional). */ diff --git a/packages/utils/src/dsn.ts b/packages/utils/src/dsn.ts index 0b58a7974821..5c500c5ec654 100644 --- a/packages/utils/src/dsn.ts +++ b/packages/utils/src/dsn.ts @@ -55,13 +55,7 @@ function dsnFromString(str: string): DsnComponents { } function dsnFromComponents(components: DsnComponents): DsnComponents { - // TODO this is for backwards compatibility, and can be removed in a future version - if ('user' in components && !('publicKey' in components)) { - components.publicKey = components.user; - } - return { - user: components.publicKey || '', protocol: components.protocol, publicKey: components.publicKey || '', pass: components.pass || '', From 2fc13c6398e540a41ff929595f94572b516e7489 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:18:08 -0400 Subject: [PATCH 08/20] feat(hub): Remove setTransaction scope method (#4865) --- packages/hub/src/scope.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/hub/src/scope.ts b/packages/hub/src/scope.ts index 9243cd409b66..09dd244734ee 100644 --- a/packages/hub/src/scope.ts +++ b/packages/hub/src/scope.ts @@ -223,14 +223,6 @@ export class Scope implements ScopeInterface { return this; } - /** - * Can be removed in major version. - * @deprecated in favor of {@link this.setTransactionName} - */ - public setTransaction(name?: string): this { - return this.setTransactionName(name); - } - /** * @inheritDoc */ From 20c777399ee5afc58c148919274192ff9cef1869 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:19:14 -0400 Subject: [PATCH 09/20] [v7] feat: Drop support for Node 6 (#4851) --- .github/workflows/build.yml | 2 +- packages/angular/package.json | 2 +- packages/browser/package.json | 2 +- packages/core/package.json | 2 +- packages/eslint-config-sdk/package.json | 2 +- packages/eslint-plugin-sdk/package.json | 2 +- packages/gatsby/package.json | 2 +- packages/hub/package.json | 2 +- packages/integrations/package.json | 2 +- packages/minimal/package.json | 2 +- packages/nextjs/package.json | 2 +- packages/node/package.json | 2 +- packages/node/test/integrations/http.test.ts | 4 +--- packages/react/package.json | 2 +- packages/tracing/package.json | 2 +- packages/types/package.json | 2 +- packages/utils/package.json | 2 +- packages/vue/package.json | 2 +- packages/wasm/package.json | 2 +- scripts/test.ts | 16 +--------------- 20 files changed, 20 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8f026b2729f..368412a4515c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -217,7 +217,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [6, 8, 10, 12, 14, 16] + node: [8, 10, 12, 14, 16] steps: - name: Check out current commit (${{ env.HEAD_COMMIT }}) uses: actions/checkout@v2 diff --git a/packages/angular/package.json b/packages/angular/package.json index e8745aa6621e..319a3942e10b 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "dist/index.js", "module": "esm/index.js", diff --git a/packages/browser/package.json b/packages/browser/package.json index ca4a18f2bbc4..7161a66e6197 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/npm/dist/index.js", "module": "build/npm/esm/index.js", diff --git a/packages/core/package.json b/packages/core/package.json index 2dd008baa23e..71b42e232391 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/eslint-config-sdk/package.json b/packages/eslint-config-sdk/package.json index babde25d977f..d2ec6952d893 100644 --- a/packages/eslint-config-sdk/package.json +++ b/packages/eslint-config-sdk/package.json @@ -12,7 +12,7 @@ "sentry" ], "engines": { - "node": ">=6" + "node": ">=8" }, "main": "src/index.js", "publishConfig": { diff --git a/packages/eslint-plugin-sdk/package.json b/packages/eslint-plugin-sdk/package.json index ba6d9e327475..dfcbd8a7d0cb 100644 --- a/packages/eslint-plugin-sdk/package.json +++ b/packages/eslint-plugin-sdk/package.json @@ -12,7 +12,7 @@ "sentry" ], "engines": { - "node": ">=6" + "node": ">=8" }, "main": "src/index.js", "publishConfig": { diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index d72cad81bd39..381e8c774136 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -11,7 +11,7 @@ "gatsby-plugin" ], "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/hub/package.json b/packages/hub/package.json index 140b0eab4041..ad5be53d5b5b 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 65e951c262cb..26537b9e586d 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "publishConfig": { "access": "public" diff --git a/packages/minimal/package.json b/packages/minimal/package.json index 94f621ee8d77..1906267520fe 100644 --- a/packages/minimal/package.json +++ b/packages/minimal/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 099b2e539b38..0469ec7704ce 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.server.js", "module": "build/esm/index.server.js", diff --git a/packages/node/package.json b/packages/node/package.json index 94b658305fea..b6d1b47f4997 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/node/test/integrations/http.test.ts b/packages/node/test/integrations/http.test.ts index c7a9c3e0a621..bc71b994c7a5 100644 --- a/packages/node/test/integrations/http.test.ts +++ b/packages/node/test/integrations/http.test.ts @@ -44,9 +44,7 @@ describe('tracing', () => { http.get('http://dogs.are.great/'); - // TODO: For some reason in node 6 two request spans are appearing. Once we stop testing against it, this can go - // back to being `toEqual()`. - expect(spans.length).toBeGreaterThanOrEqual(2); + expect(spans.length).toEqual(2); // our span is at index 1 because the transaction itself is at index 0 expect(spans[1].description).toEqual('GET http://dogs.are.great/'); diff --git a/packages/react/package.json b/packages/react/package.json index e95c942d65d7..2051ed2f6154 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/tracing/package.json b/packages/tracing/package.json index fcf443c1a579..ec117ee72942 100644 --- a/packages/tracing/package.json +++ b/packages/tracing/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/npm/dist/index.js", "module": "build/npm/esm/index.js", diff --git a/packages/types/package.json b/packages/types/package.json index f776f8ae2484..5d43a4c33237 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/utils/package.json b/packages/utils/package.json index 590a3c0626be..1a5cab8cc85b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/vue/package.json b/packages/vue/package.json index dda682c3d545..6ce89beb7eff 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/dist/index.js", "module": "build/esm/index.js", diff --git a/packages/wasm/package.json b/packages/wasm/package.json index 3602b4dc87f5..8ae7c44a8b93 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" }, "main": "build/npm/dist/index.js", "module": "build/npm/esm/index.js", diff --git a/scripts/test.ts b/scripts/test.ts index 6c2efd8a1b68..51a1dc06245e 100644 --- a/scripts/test.ts +++ b/scripts/test.ts @@ -11,21 +11,7 @@ function run(cmd: string, cwd: string = '') { const nodeMajorVersion = parseInt(process.version.split('.')[0].replace('v', ''), 10); -// control which packages we test on each version of node -if (nodeMajorVersion <= 6) { - // install legacy versions of packages whose current versions don't support node 6 - // ignoring engines and scripts lets us get away with having incompatible things installed for packages we're not testing - run('yarn add --dev --ignore-engines --ignore-scripts nock@10.x', 'packages/node'); - run('yarn add --dev --ignore-engines --ignore-scripts jsdom@11.x', 'packages/tracing'); - run('yarn add --dev --ignore-engines --ignore-scripts jsdom@11.x', 'packages/utils'); - - // only test against @sentry/node and its dependencies - node 6 is too old for anything else to work - const scope = ['@sentry/core', '@sentry/hub', '@sentry/minimal', '@sentry/node', '@sentry/utils', '@sentry/tracing'] - .map(dep => `--scope="${dep}"`) - .join(' '); - - run(`yarn test ${scope}`); -} else if (nodeMajorVersion <= 8) { +if (nodeMajorVersion <= 8) { // install legacy versions of packages whose current versions don't support node 8 // ignoring engines and scripts lets us get away with having incompatible things installed for packages we're not testing run('yarn add --dev --ignore-engines --ignore-scripts jsdom@15.x', 'packages/tracing'); From 244eb0e217998f3f4fce3ab8d778be4c80ea9eed Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 6 Apr 2022 21:16:08 -0400 Subject: [PATCH 10/20] [v7] feat(tracing): Rename registerRequestInstrumentation -> instrumentOutgoingRequests (#4859) --- packages/tracing/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/tracing/src/index.ts b/packages/tracing/src/index.ts index 89e3b3ba92d5..dcfea00f422a 100644 --- a/packages/tracing/src/index.ts +++ b/packages/tracing/src/index.ts @@ -26,8 +26,7 @@ export { Span, SpanStatusType, spanStatusfromHttpCode } from './span'; export { SpanStatus } from './spanstatus'; export { Transaction } from './transaction'; export { - // TODO deprecate old name in v7 - instrumentOutgoingRequests as registerRequestInstrumentation, + instrumentOutgoingRequests, RequestInstrumentationOptions, defaultRequestInstrumentationOptions, } from './browser'; From 285ca26a45894f90c51f5a5ec8c50666a089d8a7 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 7 Apr 2022 14:26:42 +0200 Subject: [PATCH 11/20] fix(test): Increase MongoMemoryServer creation timeout (#4881) Increases the creation timeout of `MongoMemoryServer` to temporarily fix Node integration test flakiness --- .../suites/tracing/auto-instrument/mongodb/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node-integration-tests/suites/tracing/auto-instrument/mongodb/test.ts b/packages/node-integration-tests/suites/tracing/auto-instrument/mongodb/test.ts index d118a03261a5..dd5f88f860ca 100644 --- a/packages/node-integration-tests/suites/tracing/auto-instrument/mongodb/test.ts +++ b/packages/node-integration-tests/suites/tracing/auto-instrument/mongodb/test.ts @@ -8,7 +8,7 @@ conditionalTest({ min: 12 })('MongoDB Test', () => { beforeAll(async () => { mongoServer = await MongoMemoryServer.create(); process.env.MONGO_URL = mongoServer.getUri(); - }, 30000); + }, 40000); afterAll(async () => { await mongoServer.stop(); From fb1b74f4ba6c8ef3923ecb41c376b05973cb90c6 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Thu, 7 Apr 2022 16:01:27 +0100 Subject: [PATCH 12/20] [v7] feat(node): Remove deprecated `frameContextLines` (#4884) This PR removes the previously deprecated `frameContextLines` from `NodeOptions`. --- packages/node/src/integrations/contextlines.ts | 13 ------------- packages/node/src/types.ts | 15 --------------- 2 files changed, 28 deletions(-) diff --git a/packages/node/src/integrations/contextlines.ts b/packages/node/src/integrations/contextlines.ts index e18768b2fe3d..cad196342f28 100644 --- a/packages/node/src/integrations/contextlines.ts +++ b/packages/node/src/integrations/contextlines.ts @@ -1,11 +1,8 @@ -import { getCurrentHub } from '@sentry/core'; import { Event, EventProcessor, Integration, StackFrame } from '@sentry/types'; import { addContextToFrame } from '@sentry/utils'; import { readFile } from 'fs'; import { LRUMap } from 'lru_map'; -import { NodeClient } from '../client'; - const FILE_CONTENT_CACHE = new LRUMap(100); const DEFAULT_LINES_OF_CONTEXT = 7; @@ -53,16 +50,6 @@ export class ContextLines implements Integration { /** Get's the number of context lines to add */ private get _contextLines(): number { - // This is only here to copy frameContextLines from init options if it hasn't - // been set via this integrations constructor. - // - // TODO: Remove on next major! - if (this._options.frameContextLines === undefined) { - const initOptions = getCurrentHub().getClient()?.getOptions(); - // eslint-disable-next-line deprecation/deprecation - this._options.frameContextLines = initOptions?.frameContextLines; - } - return this._options.frameContextLines !== undefined ? this._options.frameContextLines : DEFAULT_LINES_OF_CONTEXT; } diff --git a/packages/node/src/types.ts b/packages/node/src/types.ts index 6c6651bc7b88..055006a47e9e 100644 --- a/packages/node/src/types.ts +++ b/packages/node/src/types.ts @@ -20,21 +20,6 @@ export interface NodeOptions extends Options { /** HTTPS proxy certificates path */ caCerts?: string; - /** - * Sets the number of context lines for each frame when loading a file. - * - * @deprecated Context lines configuration has moved to the `ContextLines` integration, and can be used like this: - * - * ``` - * init({ - * dsn: '__DSN__', - * integrations: [new ContextLines({ frameContextLines: 10 })] - * }) - * ``` - * - * */ - frameContextLines?: number; - /** Callback that is executed when a fatal global error occurs. */ onFatalError?(error: Error): void; } From 81b10fbc1fd40e21b02a50d1dc4b26e4c206af67 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Thu, 7 Apr 2022 17:17:31 +0100 Subject: [PATCH 13/20] [v7] feat(browser): Remove top level eventbuilder exports (#4887) These exports were historically used in `@sentry/electron`, but are no longer being used by the Electron SDK or the React Native SDK, so they can be removed. --- packages/browser/src/exports.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/browser/src/exports.ts b/packages/browser/src/exports.ts index 86ace0abbdd5..b4dd4374a7b3 100644 --- a/packages/browser/src/exports.ts +++ b/packages/browser/src/exports.ts @@ -44,6 +44,5 @@ export { export { BrowserOptions } from './backend'; export { BrowserClient } from './client'; export { injectReportDialog, ReportDialogOptions } from './helpers'; -export { eventFromException, eventFromMessage } from './eventbuilder'; export { defaultIntegrations, forceLoad, init, lastEventId, onLoad, showReportDialog, flush, close, wrap } from './sdk'; export { SDK_NAME } from './version'; From 79084f29cf9e2bc7e3b3e5238d6b2f26d1687446 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 8 Apr 2022 12:53:44 +0100 Subject: [PATCH 14/20] Mostly working --- packages/browser/src/backend.ts | 18 +++++- packages/browser/src/eventbuilder.ts | 64 +++++++++---------- packages/browser/src/exports.ts | 9 +++ .../src/integrations/globalhandlers.ts | 21 +++--- .../browser/src/integrations/linkederrors.ts | 30 +++++++-- packages/browser/src/sdk.ts | 4 ++ packages/browser/src/stack-parsers.ts | 8 +++ .../unit/integrations/linkederrors.test.ts | 22 ++++--- .../test/unit/tracekit/chromium.test.ts | 28 ++++---- .../test/unit/tracekit/firefox.test.ts | 22 ++++--- .../browser/test/unit/tracekit/ie.test.ts | 10 ++- .../browser/test/unit/tracekit/misc.test.ts | 6 +- .../browser/test/unit/tracekit/opera.test.ts | 12 ++-- .../test/unit/tracekit/react-native.test.ts | 14 ++-- .../browser/test/unit/tracekit/react.test.ts | 10 ++- .../browser/test/unit/tracekit/safari.test.ts | 24 ++++--- packages/utils/src/stacktrace.ts | 23 +++++++ 17 files changed, 218 insertions(+), 107 deletions(-) diff --git a/packages/browser/src/backend.ts b/packages/browser/src/backend.ts index 89cf843d48ae..18d2f5d5756a 100644 --- a/packages/browser/src/backend.ts +++ b/packages/browser/src/backend.ts @@ -1,6 +1,6 @@ import { BaseBackend, getEnvelopeEndpointWithUrlEncodedAuth, initAPIDetails } from '@sentry/core'; import { Event, EventHint, Options, Severity, Transport, TransportOptions } from '@sentry/types'; -import { supportsFetch } from '@sentry/utils'; +import { StackLineParser, StackParser, stackParserFromOptions, supportsFetch } from '@sentry/utils'; import { eventFromException, eventFromMessage } from './eventbuilder'; import { FetchTransport, makeNewFetchTransport, makeNewXHRTransport, XHRTransport } from './transports'; @@ -23,6 +23,12 @@ export interface BrowserOptions extends Options { * By default, all errors will be sent. */ denyUrls?: Array; + + /** + * A stack parser implementation or an array of stack line parsers + * By default, a stack parser is supplied for all supported browsers + */ + stackParser?: StackParser | StackLineParser[]; } /** @@ -34,13 +40,19 @@ export class BrowserBackend extends BaseBackend { * @inheritDoc */ public eventFromException(exception: unknown, hint?: EventHint): PromiseLike { - return eventFromException(exception, hint, this._options.attachStacktrace); + return eventFromException(stackParserFromOptions(this._options), exception, hint, this._options.attachStacktrace); } /** * @inheritDoc */ public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): PromiseLike { - return eventFromMessage(message, level, hint, this._options.attachStacktrace); + return eventFromMessage( + stackParserFromOptions(this._options), + message, + level, + hint, + this._options.attachStacktrace, + ); } /** diff --git a/packages/browser/src/eventbuilder.ts b/packages/browser/src/eventbuilder.ts index f999eb2854ca..eff2bc46095d 100644 --- a/packages/browser/src/eventbuilder.ts +++ b/packages/browser/src/eventbuilder.ts @@ -2,7 +2,6 @@ import { Event, EventHint, Exception, Severity, StackFrame } from '@sentry/types import { addExceptionMechanism, addExceptionTypeValue, - createStackParser, extractExceptionKeysForMessage, isDOMError, isDOMException, @@ -12,24 +11,15 @@ import { isPlainObject, normalizeToSize, resolvedSyncPromise, + StackParser, } from '@sentry/utils'; -import { - chromeStackParser, - geckoStackParser, - opera10StackParser, - opera11StackParser, - winjsStackParser, -} from './stack-parsers'; - /** * This function creates an exception from an TraceKitStackTrace - * @param stacktrace TraceKitStackTrace that will be converted to an exception - * @hidden */ -export function exceptionFromError(ex: Error): Exception { +export function exceptionFromError(stackParser: StackParser, ex: Error): Exception { // Get the frames first since Opera can lose the stack if we touch anything else first - const frames = parseStackFrames(ex); + const frames = parseStackFrames(stackParser, ex); const exception: Exception = { type: ex && ex.name, @@ -51,6 +41,7 @@ export function exceptionFromError(ex: Error): Exception { * @hidden */ export function eventFromPlainObject( + stackParser: StackParser, exception: Record, syntheticException?: Error, isUnhandledRejection?: boolean, @@ -72,7 +63,7 @@ export function eventFromPlainObject( }; if (syntheticException) { - const frames = parseStackFrames(syntheticException); + const frames = parseStackFrames(stackParser, syntheticException); if (frames.length) { event.stacktrace = { frames }; } @@ -84,16 +75,19 @@ export function eventFromPlainObject( /** * @hidden */ -export function eventFromError(ex: Error): Event { +export function eventFromError(stackParser: StackParser, ex: Error): Event { return { exception: { - values: [exceptionFromError(ex)], + values: [exceptionFromError(stackParser, ex)], }, }; } /** Parses stack frames from an error */ -export function parseStackFrames(ex: Error & { framesToPop?: number; stacktrace?: string }): StackFrame[] { +export function parseStackFrames( + stackParser: StackParser, + ex: Error & { framesToPop?: number; stacktrace?: string }, +): StackFrame[] { // Access and store the stacktrace property before doing ANYTHING // else to it because Opera is not very good at providing it // reliably in other circumstances. @@ -102,13 +96,7 @@ export function parseStackFrames(ex: Error & { framesToPop?: number; stacktrace? const popSize = getPopSize(ex); try { - return createStackParser( - opera10StackParser, - opera11StackParser, - chromeStackParser, - winjsStackParser, - geckoStackParser, - )(stacktrace, popSize); + return stackParser(stacktrace, popSize); } catch (e) { // no-empty } @@ -154,12 +142,13 @@ function extractMessage(ex: Error & { message: { error?: Error } }): string { * @hidden */ export function eventFromException( + stackParser: StackParser, exception: unknown, hint?: EventHint, attachStacktrace?: boolean, ): PromiseLike { const syntheticException = (hint && hint.syntheticException) || undefined; - const event = eventFromUnknownInput(exception, syntheticException, attachStacktrace); + const event = eventFromUnknownInput(stackParser, exception, syntheticException, attachStacktrace); addExceptionMechanism(event); // defaults to { type: 'generic', handled: true } event.level = Severity.Error; if (hint && hint.event_id) { @@ -173,13 +162,14 @@ export function eventFromException( * @hidden */ export function eventFromMessage( + stackParser: StackParser, message: string, level: Severity = Severity.Info, hint?: EventHint, attachStacktrace?: boolean, ): PromiseLike { const syntheticException = (hint && hint.syntheticException) || undefined; - const event = eventFromString(message, syntheticException, attachStacktrace); + const event = eventFromString(stackParser, message, syntheticException, attachStacktrace); event.level = level; if (hint && hint.event_id) { event.event_id = hint.event_id; @@ -191,6 +181,7 @@ export function eventFromMessage( * @hidden */ export function eventFromUnknownInput( + stackParser: StackParser, exception: unknown, syntheticException?: Error, attachStacktrace?: boolean, @@ -201,7 +192,7 @@ export function eventFromUnknownInput( if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) { // If it is an ErrorEvent with `error` property, extract it to get actual Error const errorEvent = exception as ErrorEvent; - return eventFromError(errorEvent.error as Error); + return eventFromError(stackParser, errorEvent.error as Error); } // If it is a `DOMError` (which is a legacy API, but still supported in some browsers) then we just extract the name @@ -215,11 +206,11 @@ export function eventFromUnknownInput( const domException = exception as DOMException; if ('stack' in (exception as Error)) { - event = eventFromError(exception as Error); + event = eventFromError(stackParser, exception as Error); } else { const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException'); const message = domException.message ? `${name}: ${domException.message}` : name; - event = eventFromString(message, syntheticException, attachStacktrace); + event = eventFromString(stackParser, message, syntheticException, attachStacktrace); addExceptionTypeValue(event, message); } if ('code' in domException) { @@ -230,14 +221,14 @@ export function eventFromUnknownInput( } if (isError(exception)) { // we have a real Error object, do nothing - return eventFromError(exception); + return eventFromError(stackParser, exception); } if (isPlainObject(exception) || isEvent(exception)) { // If it's a plain object or an instance of `Event` (the built-in JS kind, not this SDK's `Event` type), serialize // it manually. This will allow us to group events based on top-level keys which is much better than creating a new // group on any key/value change. const objectException = exception as Record; - event = eventFromPlainObject(objectException, syntheticException, isUnhandledRejection); + event = eventFromPlainObject(stackParser, objectException, syntheticException, isUnhandledRejection); addExceptionMechanism(event, { synthetic: true, }); @@ -253,7 +244,7 @@ export function eventFromUnknownInput( // - a plain Object // // So bail out and capture it as a simple message: - event = eventFromString(exception as string, syntheticException, attachStacktrace); + event = eventFromString(stackParser, exception as string, syntheticException, attachStacktrace); addExceptionTypeValue(event, `${exception}`, undefined); addExceptionMechanism(event, { synthetic: true, @@ -265,13 +256,18 @@ export function eventFromUnknownInput( /** * @hidden */ -export function eventFromString(input: string, syntheticException?: Error, attachStacktrace?: boolean): Event { +export function eventFromString( + stackParser: StackParser, + input: string, + syntheticException?: Error, + attachStacktrace?: boolean, +): Event { const event: Event = { message: input, }; if (attachStacktrace && syntheticException) { - const frames = parseStackFrames(syntheticException); + const frames = parseStackFrames(stackParser, syntheticException); if (frames.length) { event.stacktrace = { frames }; } diff --git a/packages/browser/src/exports.ts b/packages/browser/src/exports.ts index b4dd4374a7b3..ad6c4891c3f9 100644 --- a/packages/browser/src/exports.ts +++ b/packages/browser/src/exports.ts @@ -41,6 +41,15 @@ export { withScope, } from '@sentry/core'; +export { + defaultStackParsers, + chromeStackParser, + geckoStackParser, + opera10StackParser, + opera11StackParser, + winjsStackParser, +} from './stack-parsers'; + export { BrowserOptions } from './backend'; export { BrowserClient } from './client'; export { injectReportDialog, ReportDialogOptions } from './helpers'; diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts index 19ee594afaf3..38257cf6a7aa 100644 --- a/packages/browser/src/integrations/globalhandlers.ts +++ b/packages/browser/src/integrations/globalhandlers.ts @@ -9,8 +9,11 @@ import { isPrimitive, isString, logger, + StackParser, + stackParserFromOptions, } from '@sentry/utils'; +import { BrowserClient } from '../client'; import { eventFromUnknownInput } from '../eventbuilder'; import { IS_DEBUG_BUILD } from '../flags'; import { shouldIgnoreOnError } from '../helpers'; @@ -79,7 +82,7 @@ function _installGlobalOnErrorHandler(): void { 'error', // eslint-disable-next-line @typescript-eslint/no-explicit-any (data: { msg: any; url: any; line: any; column: any; error: any }) => { - const [hub, attachStacktrace] = getHubAndAttachStacktrace(); + const [hub, stackParser, attachStacktrace] = getHubAndOptions(); if (!hub.getIntegration(GlobalHandlers)) { return; } @@ -92,7 +95,7 @@ function _installGlobalOnErrorHandler(): void { error === undefined && isString(msg) ? _eventFromIncompleteOnError(msg, url, line, column) : _enhanceEventWithInitialFrame( - eventFromUnknownInput(error || msg, undefined, attachStacktrace, false), + eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false), url, line, column, @@ -111,7 +114,7 @@ function _installGlobalOnUnhandledRejectionHandler(): void { 'unhandledrejection', // eslint-disable-next-line @typescript-eslint/no-explicit-any (e: any) => { - const [hub, attachStacktrace] = getHubAndAttachStacktrace(); + const [hub, stackParser, attachStacktrace] = getHubAndOptions(); if (!hub.getIntegration(GlobalHandlers)) { return; } @@ -142,7 +145,7 @@ function _installGlobalOnUnhandledRejectionHandler(): void { const event = isPrimitive(error) ? _eventFromRejectionWithPrimitive(error) - : eventFromUnknownInput(error, undefined, attachStacktrace, true); + : eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true); event.level = Severity.Error; @@ -250,9 +253,11 @@ function addMechanismAndCapture(hub: Hub, error: EventHint['originalException'], }); } -function getHubAndAttachStacktrace(): [Hub, boolean | undefined] { +function getHubAndOptions(): [Hub, StackParser, boolean | undefined] { const hub = getCurrentHub(); - const client = hub.getClient(); - const attachStacktrace = client && client.getOptions().attachStacktrace; - return [hub, attachStacktrace]; + const client = hub.getClient(); + const options = client?.getOptions(); + const parser = stackParserFromOptions(options); + const attachStacktrace = options?.attachStacktrace; + return [hub, parser, attachStacktrace]; } diff --git a/packages/browser/src/integrations/linkederrors.ts b/packages/browser/src/integrations/linkederrors.ts index fa197b48e681..2bd053db0c79 100644 --- a/packages/browser/src/integrations/linkederrors.ts +++ b/packages/browser/src/integrations/linkederrors.ts @@ -1,7 +1,8 @@ import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types'; -import { isInstanceOf } from '@sentry/utils'; +import { isInstanceOf, StackParser, stackParserFromOptions } from '@sentry/utils'; +import { BrowserClient } from '../client'; import { exceptionFromError } from '../eventbuilder'; const DEFAULT_KEY = 'cause'; @@ -46,9 +47,12 @@ export class LinkedErrors implements Integration { * @inheritDoc */ public setupOnce(): void { + const options = getCurrentHub().getClient()?.getOptions(); + const parser = stackParserFromOptions(options); + addGlobalEventProcessor((event: Event, hint?: EventHint) => { const self = getCurrentHub().getIntegration(LinkedErrors); - return self ? _handler(self._key, self._limit, event, hint) : event; + return self ? _handler(parser, self._key, self._limit, event, hint) : event; }); } } @@ -56,11 +60,17 @@ export class LinkedErrors implements Integration { /** * @inheritDoc */ -export function _handler(key: string, limit: number, event: Event, hint?: EventHint): Event | null { +export function _handler( + parser: StackParser, + key: string, + limit: number, + event: Event, + hint?: EventHint, +): Event | null { if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) { return event; } - const linkedErrors = _walkErrorTree(limit, hint.originalException as ExtendedError, key); + const linkedErrors = _walkErrorTree(parser, limit, hint.originalException as ExtendedError, key); event.exception.values = [...linkedErrors, ...event.exception.values]; return event; } @@ -68,10 +78,16 @@ export function _handler(key: string, limit: number, event: Event, hint?: EventH /** * JSDOC */ -export function _walkErrorTree(limit: number, error: ExtendedError, key: string, stack: Exception[] = []): Exception[] { +export function _walkErrorTree( + parser: StackParser, + limit: number, + error: ExtendedError, + key: string, + stack: Exception[] = [], +): Exception[] { if (!isInstanceOf(error[key], Error) || stack.length + 1 >= limit) { return stack; } - const exception = exceptionFromError(error[key]); - return _walkErrorTree(limit, error[key], key, [exception, ...stack]); + const exception = exceptionFromError(parser, error[key]); + return _walkErrorTree(parser, limit, error[key], key, [exception, ...stack]); } diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts index 3f05a646c96f..e09d6f7b2886 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -7,6 +7,7 @@ import { BrowserClient } from './client'; import { IS_DEBUG_BUILD } from './flags'; import { ReportDialogOptions, wrap as internalWrap } from './helpers'; import { Breadcrumbs, Dedupe, GlobalHandlers, LinkedErrors, TryCatch, UserAgent } from './integrations'; +import { defaultStackParsers } from './stack-parsers'; export const defaultIntegrations = [ new CoreIntegrations.InboundFilters(), @@ -93,6 +94,9 @@ export function init(options: BrowserOptions = {}): void { if (options.sendClientReports === undefined) { options.sendClientReports = true; } + if (options.stackParser === undefined) { + options.stackParser = defaultStackParsers; + } initAndBind(BrowserClient, options); diff --git a/packages/browser/src/stack-parsers.ts b/packages/browser/src/stack-parsers.ts index f54c1df803e9..7d9298fc24c6 100644 --- a/packages/browser/src/stack-parsers.ts +++ b/packages/browser/src/stack-parsers.ts @@ -131,6 +131,14 @@ const opera11: StackLineParserFn = line => { export const opera11StackParser: StackLineParser = [OPERA11_PRIORITY, opera11]; +export const defaultStackParsers = [ + chromeStackParser, + geckoStackParser, + opera10StackParser, + opera11StackParser, + winjsStackParser, +]; + /** * Safari web extensions, starting version unknown, can produce "frames-only" stacktraces. * What it means, is that instead of format like: diff --git a/packages/browser/test/unit/integrations/linkederrors.test.ts b/packages/browser/test/unit/integrations/linkederrors.test.ts index 1531aa6f77ed..25a7bee44fcb 100644 --- a/packages/browser/test/unit/integrations/linkederrors.test.ts +++ b/packages/browser/test/unit/integrations/linkederrors.test.ts @@ -1,15 +1,19 @@ import { ExtendedError } from '@sentry/types'; +import { createStackParser } from '@sentry/utils'; import { BrowserBackend } from '../../../src/backend'; +import { defaultStackParsers } from '../../../src/stack-parsers'; import * as LinkedErrorsModule from '../../../src/integrations/linkederrors'; +const parser = createStackParser(...defaultStackParsers); + describe('LinkedErrors', () => { describe('handler', () => { it('should bail out if event does not contain exception', () => { const event = { message: 'foo', }; - const result = LinkedErrorsModule._handler('cause', 5, event); + const result = LinkedErrorsModule._handler(parser, 'cause', 5, event); expect(result).toEqual(event); }); @@ -20,7 +24,7 @@ describe('LinkedErrors', () => { }, message: 'foo', }; - const result = LinkedErrorsModule._handler('cause', 5, event); + const result = LinkedErrorsModule._handler(parser, 'cause', 5, event); expect(result).toEqual(event); }); @@ -34,12 +38,14 @@ describe('LinkedErrors', () => { one.cause = two; const originalException = one; - const backend = new BrowserBackend({}); + const backend = new BrowserBackend({ stackParser: parser }); return backend.eventFromException(originalException).then(event => { - const result = LinkedErrorsModule._handler('cause', 5, event, { + const result = LinkedErrorsModule._handler(parser, 'cause', 5, event, { originalException, }); + console.log(result.exception.values); + // It shouldn't include root exception, as it's already processed in the event by the main error handler expect(result.exception.values.length).toBe(3); expect(result.exception.values[0].type).toBe('SyntaxError'); @@ -64,9 +70,9 @@ describe('LinkedErrors', () => { one.reason = two; const originalException = one; - const backend = new BrowserBackend({}); + const backend = new BrowserBackend({ stackParser: parser }); return backend.eventFromException(originalException).then(event => { - const result = LinkedErrorsModule._handler('reason', 5, event, { + const result = LinkedErrorsModule._handler(parser, 'reason', 5, event, { originalException, }); @@ -90,10 +96,10 @@ describe('LinkedErrors', () => { one.cause = two; two.cause = three; - const backend = new BrowserBackend({}); + const backend = new BrowserBackend({ stackParser: parser }); const originalException = one; return backend.eventFromException(originalException).then(event => { - const result = LinkedErrorsModule._handler('cause', 2, event, { + const result = LinkedErrorsModule._handler(parser, 'cause', 2, event, { originalException, }); diff --git a/packages/browser/test/unit/tracekit/chromium.test.ts b/packages/browser/test/unit/tracekit/chromium.test.ts index e40abffd8d1f..af522ef9bb5c 100644 --- a/packages/browser/test/unit/tracekit/chromium.test.ts +++ b/packages/browser/test/unit/tracekit/chromium.test.ts @@ -1,9 +1,13 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - Chrome Tests', () => { it('should parse Chrome error with no location', () => { const NO_LOCATION = { message: 'foo', name: 'bar', stack: 'error\n at Array.forEach (native)' }; - const ex = exceptionFromError(NO_LOCATION); + const ex = exceptionFromError(parser, NO_LOCATION); expect(ex).toEqual({ value: 'foo', @@ -25,7 +29,7 @@ describe('Tracekit - Chrome Tests', () => { ' at http://path/to/file.js:24:4', }; - const ex = exceptionFromError(CHROME_15); + const ex = exceptionFromError(parser, CHROME_15); expect(ex).toEqual({ value: "Object # has no method 'undef'", @@ -52,7 +56,7 @@ describe('Tracekit - Chrome Tests', () => { ' at I.e.fn.(anonymous function) [as index] (http://localhost:8080/file.js:10:3651)', }; - const ex = exceptionFromError(CHROME_36); + const ex = exceptionFromError(parser, CHROME_36); expect(ex).toEqual({ value: 'Default error', @@ -98,7 +102,7 @@ describe('Tracekit - Chrome Tests', () => { ' at TESTTESTTEST.proxiedMethod(webpack:///./~/react-proxy/modules/createPrototypeProxy.js?:44:30)', }; - const ex = exceptionFromError(CHROME_XX_WEBPACK); + const ex = exceptionFromError(parser, CHROME_XX_WEBPACK); expect(ex).toEqual({ value: "Cannot read property 'error' of undefined", @@ -151,7 +155,7 @@ describe('Tracekit - Chrome Tests', () => { 'at http://localhost:8080/file.js:31:13\n', }; - const ex = exceptionFromError(CHROME_48_EVAL); + const ex = exceptionFromError(parser, CHROME_48_EVAL); expect(ex).toEqual({ value: 'message string', @@ -183,7 +187,7 @@ describe('Tracekit - Chrome Tests', () => { ' at n.handle (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:7:2863)', }; - const ex = exceptionFromError(CHROME_48_BLOB); + const ex = exceptionFromError(parser, CHROME_48_BLOB); expect(ex).toEqual({ value: 'Error: test', @@ -246,7 +250,7 @@ describe('Tracekit - Chrome Tests', () => { at examplescheme://examplehost/cd351f7250857e22ceaa.worker.js:70179:15`, }; - const ex = exceptionFromError(CHROMIUM_EMBEDDED_FRAMEWORK_CUSTOM_SCHEME); + const ex = exceptionFromError(parser, CHROMIUM_EMBEDDED_FRAMEWORK_CUSTOM_SCHEME); expect(ex).toEqual({ value: 'message string', @@ -276,7 +280,7 @@ describe('Tracekit - Chrome Tests', () => { at http://localhost:5000/test:24:7`, }; - const ex = exceptionFromError(CHROME73_NATIVE_CODE_EXCEPTION); + const ex = exceptionFromError(parser, CHROME73_NATIVE_CODE_EXCEPTION); expect(ex).toEqual({ value: 'test', @@ -309,7 +313,7 @@ describe('Tracekit - Chrome Tests', () => { at http://localhost:5000/:50:19`, }; - const ex = exceptionFromError(CHROME73_EVAL_EXCEPTION); + const ex = exceptionFromError(parser, CHROME73_EVAL_EXCEPTION); expect(ex).toEqual({ value: 'bad', @@ -342,7 +346,7 @@ describe('Tracekit - Chrome Tests', () => { at Global code (http://localhost:5000/test:24:7)`, }; - const ex = exceptionFromError(EDGE44_NATIVE_CODE_EXCEPTION); + const ex = exceptionFromError(parser, EDGE44_NATIVE_CODE_EXCEPTION); expect(ex).toEqual({ value: 'test', @@ -375,7 +379,7 @@ describe('Tracekit - Chrome Tests', () => { at Anonymous function (http://localhost:5000/:50:8)`, }; - const ex = exceptionFromError(EDGE44_EVAL_EXCEPTION); + const ex = exceptionFromError(parser, EDGE44_EVAL_EXCEPTION); expect(ex).toEqual({ value: 'aha', @@ -411,7 +415,7 @@ describe('Tracekit - Chrome Tests', () => { at TESTTESTTEST.someMethod (C:\\Users\\user\\path\\to\\file.js:295:108)`, }; - const ex = exceptionFromError(CHROME_ELECTRON_RENDERER); + const ex = exceptionFromError(parser, CHROME_ELECTRON_RENDERER); expect(ex).toEqual({ value: "Cannot read property 'error' of undefined", diff --git a/packages/browser/test/unit/tracekit/firefox.test.ts b/packages/browser/test/unit/tracekit/firefox.test.ts index a14fae1e38cc..c0ea42b87e7a 100644 --- a/packages/browser/test/unit/tracekit/firefox.test.ts +++ b/packages/browser/test/unit/tracekit/firefox.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - Firefox Tests', () => { it('should parse Firefox 3 error', () => { @@ -18,7 +22,7 @@ describe('Tracekit - Firefox Tests', () => { '', }; - const ex = exceptionFromError(FIREFOX_3); + const ex = exceptionFromError(parser, FIREFOX_3); expect(ex).toEqual({ value: 'this.undef is not a function', @@ -54,7 +58,7 @@ describe('Tracekit - Firefox Tests', () => { '', }; - const ex = exceptionFromError(FIREFOX_7); + const ex = exceptionFromError(parser, FIREFOX_7); expect(ex).toEqual({ value: 'bar', @@ -86,7 +90,7 @@ describe('Tracekit - Firefox Tests', () => { lineNumber: 48, }; - const ex = exceptionFromError(FIREFOX_14); + const ex = exceptionFromError(parser, FIREFOX_14); expect(ex).toEqual({ value: 'x is null', @@ -115,7 +119,7 @@ describe('Tracekit - Firefox Tests', () => { columnNumber: 12, }; - const ex = exceptionFromError(FIREFOX_31); + const ex = exceptionFromError(parser, FIREFOX_31); expect(ex).toEqual({ value: 'Default error', @@ -150,7 +154,7 @@ describe('Tracekit - Firefox Tests', () => { result: 2147500037, }; - const ex = exceptionFromError(FIREFOX_44_NS_EXCEPTION); + const ex = exceptionFromError(parser, FIREFOX_44_NS_EXCEPTION); expect(ex).toEqual({ value: 'No error message', @@ -185,7 +189,7 @@ describe('Tracekit - Firefox Tests', () => { name: 'TypeError', }; - const ex = exceptionFromError(FIREFOX_50_RESOURCE_URL); + const ex = exceptionFromError(parser, FIREFOX_50_RESOURCE_URL); expect(ex).toEqual({ value: 'this.props.raw[this.state.dataSource].rows is undefined', @@ -233,7 +237,7 @@ describe('Tracekit - Firefox Tests', () => { '@http://localhost:8080/file.js:33:9', }; - const ex = exceptionFromError(FIREFOX_43_EVAL); + const ex = exceptionFromError(parser, FIREFOX_43_EVAL); expect(ex).toEqual({ value: 'message string', @@ -259,7 +263,7 @@ describe('Tracekit - Firefox Tests', () => { @http://localhost:5000/test:24:7`, }; - const stacktrace = exceptionFromError(FIREFOX66_NATIVE_CODE_EXCEPTION); + const stacktrace = exceptionFromError(parser, FIREFOX66_NATIVE_CODE_EXCEPTION); expect(stacktrace).toEqual({ value: 'test', @@ -289,7 +293,7 @@ describe('Tracekit - Firefox Tests', () => { @http://localhost:5000/:50:19`, }; - const stacktrace = exceptionFromError(FIREFOX66_EVAL_EXCEPTION); + const stacktrace = exceptionFromError(parser, FIREFOX66_EVAL_EXCEPTION); expect(stacktrace).toEqual({ value: 'aha', diff --git a/packages/browser/test/unit/tracekit/ie.test.ts b/packages/browser/test/unit/tracekit/ie.test.ts index cfd60ab2e6c4..730b4b4d8b24 100644 --- a/packages/browser/test/unit/tracekit/ie.test.ts +++ b/packages/browser/test/unit/tracekit/ie.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - IE Tests', () => { it('should parse IE 10 error', () => { @@ -14,7 +18,7 @@ describe('Tracekit - IE Tests', () => { number: -2146823281, }; - const ex = exceptionFromError(IE_10); + const ex = exceptionFromError(parser, IE_10); // TODO: func should be normalized expect(ex).toEqual({ @@ -43,7 +47,7 @@ describe('Tracekit - IE Tests', () => { number: -2146823281, }; - const ex = exceptionFromError(IE_11); + const ex = exceptionFromError(parser, IE_11); // TODO: func should be normalized expect(ex).toEqual({ @@ -72,7 +76,7 @@ describe('Tracekit - IE Tests', () => { number: -2146823279, }; - const ex = exceptionFromError(IE_11_EVAL); + const ex = exceptionFromError(parser, IE_11_EVAL); expect(ex).toEqual({ value: "'getExceptionProps' is undefined", diff --git a/packages/browser/test/unit/tracekit/misc.test.ts b/packages/browser/test/unit/tracekit/misc.test.ts index 3aa59754cc9a..281e18053749 100644 --- a/packages/browser/test/unit/tracekit/misc.test.ts +++ b/packages/browser/test/unit/tracekit/misc.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - Misc Tests', () => { it('should parse PhantomJS 1.19 error', () => { @@ -11,7 +15,7 @@ describe('Tracekit - Misc Tests', () => { ' at foo (http://path/to/file.js:4283)\n' + ' at http://path/to/file.js:4287', }; - const ex = exceptionFromError(PHANTOMJS_1_19); + const ex = exceptionFromError(parser, PHANTOMJS_1_19); expect(ex).toEqual({ value: 'bar', diff --git a/packages/browser/test/unit/tracekit/opera.test.ts b/packages/browser/test/unit/tracekit/opera.test.ts index 472c4a55e2ca..b1a32d755c98 100644 --- a/packages/browser/test/unit/tracekit/opera.test.ts +++ b/packages/browser/test/unit/tracekit/opera.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - Opera Tests', () => { it('should parse Opera 10 error', () => { @@ -24,7 +28,7 @@ describe('Tracekit - Opera Tests', () => { '', }; - const ex = exceptionFromError(OPERA_10); + const ex = exceptionFromError(parser, OPERA_10); expect(ex).toEqual({ value: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', @@ -70,7 +74,7 @@ describe('Tracekit - Opera Tests', () => { ' foo();', }; - const ex = exceptionFromError(OPERA_11); + const ex = exceptionFromError(parser, OPERA_11); expect(ex).toEqual({ value: "'this.undef' is not a function", @@ -107,7 +111,7 @@ describe('Tracekit - Opera Tests', () => { ' dumpException3();', }; - const ex = exceptionFromError(OPERA_12); + const ex = exceptionFromError(parser, OPERA_12); expect(ex).toEqual({ value: "Cannot convert 'x' to object", @@ -151,7 +155,7 @@ describe('Tracekit - Opera Tests', () => { ' at bar (http://path/to/file.js:108:168)', }; - const ex = exceptionFromError(OPERA_25); + const ex = exceptionFromError(parser, OPERA_25); expect(ex).toEqual({ value: "Cannot read property 'undef' of null", diff --git a/packages/browser/test/unit/tracekit/react-native.test.ts b/packages/browser/test/unit/tracekit/react-native.test.ts index 6935acd615fd..2b7246df73a5 100644 --- a/packages/browser/test/unit/tracekit/react-native.test.ts +++ b/packages/browser/test/unit/tracekit/react-native.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - React Native Tests', () => { it('should parse exceptions for react-native-v8', () => { @@ -14,7 +18,7 @@ describe('Tracekit - React Native Tests', () => { at Object.y(index.android.bundle:93:571) at P(index.android.bundle:93:714)`, }; - const stacktrace = exceptionFromError(REACT_NATIVE_V8_EXCEPTION); + const stacktrace = exceptionFromError(parser, REACT_NATIVE_V8_EXCEPTION); expect(stacktrace).toEqual({ value: 'Manually triggered crash to test Sentry reporting', @@ -61,7 +65,7 @@ describe('Tracekit - React Native Tests', () => { p@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:96:385 forEach@[native code]`, }; - const stacktrace = exceptionFromError(REACT_NATIVE_EXPO_EXCEPTION); + const stacktrace = exceptionFromError(parser, REACT_NATIVE_EXPO_EXCEPTION); expect(stacktrace).toEqual({ value: 'Test Error Expo', @@ -122,7 +126,7 @@ describe('Tracekit - React Native Tests', () => { 'at this(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js:74:41)\n', }; - const ex = exceptionFromError(ANDROID_REACT_NATIVE); + const ex = exceptionFromError(parser, ANDROID_REACT_NATIVE); expect(ex).toEqual({ value: 'Error: test', @@ -241,7 +245,7 @@ describe('Tracekit - React Native Tests', () => { '[native code]', }; - const ex = exceptionFromError(ANDROID_REACT_NATIVE_PROD); + const ex = exceptionFromError(parser, ANDROID_REACT_NATIVE_PROD); expect(ex).toEqual({ value: 'Error: test', @@ -352,7 +356,7 @@ describe('Tracekit - React Native Tests', () => { 'at value (address at index.android.bundle:1:32776)\n' + 'at value (address at index.android.bundle:1:31561)', }; - const ex = exceptionFromError(ANDROID_REACT_NATIVE_HERMES); + const ex = exceptionFromError(parser, ANDROID_REACT_NATIVE_HERMES); expect(ex).toEqual({ value: 'Error: lets throw!', diff --git a/packages/browser/test/unit/tracekit/react.test.ts b/packages/browser/test/unit/tracekit/react.test.ts index dba60cceab4f..b15659437a9e 100644 --- a/packages/browser/test/unit/tracekit/react.test.ts +++ b/packages/browser/test/unit/tracekit/react.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - React Tests', () => { it('should correctly parse Invariant Violation errors and use framesToPop to drop info message', () => { @@ -14,7 +18,7 @@ describe('Tracekit - React Tests', () => { at f (http://localhost:5000/:1:980)`, }; - const ex = exceptionFromError(REACT_INVARIANT_VIOLATION_EXCEPTION); + const ex = exceptionFromError(parser, REACT_INVARIANT_VIOLATION_EXCEPTION); expect(ex).toEqual({ value: @@ -61,7 +65,7 @@ describe('Tracekit - React Tests', () => { at f (http://localhost:5000/:1:980)`, }; - const ex = exceptionFromError(REACT_PRODUCTION_ERROR); + const ex = exceptionFromError(parser, REACT_PRODUCTION_ERROR); expect(ex).toEqual({ value: @@ -109,7 +113,7 @@ describe('Tracekit - React Tests', () => { at f (http://localhost:5000/:1:980)`, }; - const ex = exceptionFromError(REACT_PRODUCTION_ERROR); + const ex = exceptionFromError(parser, REACT_PRODUCTION_ERROR); expect(ex).toEqual({ value: diff --git a/packages/browser/test/unit/tracekit/safari.test.ts b/packages/browser/test/unit/tracekit/safari.test.ts index 6342899e1ca4..0c1b2b1a9127 100644 --- a/packages/browser/test/unit/tracekit/safari.test.ts +++ b/packages/browser/test/unit/tracekit/safari.test.ts @@ -1,4 +1,8 @@ +import { createStackParser } from '@sentry/utils'; import { exceptionFromError } from '../../../src/eventbuilder'; +import { defaultStackParsers } from '../../../src/stack-parsers'; + +const parser = createStackParser(...defaultStackParsers); describe('Tracekit - Safari Tests', () => { it('should parse Safari 6 error', () => { @@ -14,7 +18,7 @@ describe('Tracekit - Safari Tests', () => { sourceURL: 'http://path/to/file.js', }; - const stackFrames = exceptionFromError(SAFARI_6); + const stackFrames = exceptionFromError(parser, SAFARI_6); expect(stackFrames).toEqual({ value: "'null' is not an object (evaluating 'x.undef')", @@ -40,7 +44,7 @@ describe('Tracekit - Safari Tests', () => { sourceURL: 'http://path/to/file.js', }; - const stackFrames = exceptionFromError(SAFARI_7); + const stackFrames = exceptionFromError(parser, SAFARI_7); expect(stackFrames).toEqual({ value: "'null' is not an object (evaluating 'x.undef')", @@ -66,7 +70,7 @@ describe('Tracekit - Safari Tests', () => { sourceURL: 'http://path/to/file.js', }; - const stackFrames = exceptionFromError(SAFARI_8); + const stackFrames = exceptionFromError(parser, SAFARI_8); expect(stackFrames).toEqual({ value: "null is not an object (evaluating 'x.undef')", @@ -96,7 +100,7 @@ describe('Tracekit - Safari Tests', () => { column: 18, }; - const stackFrames = exceptionFromError(SAFARI_8_EVAL); + const stackFrames = exceptionFromError(parser, SAFARI_8_EVAL); expect(stackFrames).toEqual({ value: "Can't find variable: getExceptionProps", @@ -121,7 +125,7 @@ describe('Tracekit - Safari Tests', () => { at safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`, }; - const ex = exceptionFromError(SAFARI_EXTENSION_EXCEPTION); + const ex = exceptionFromError(parser, SAFARI_EXTENSION_EXCEPTION); expect(ex).toEqual({ value: 'wat', @@ -155,7 +159,7 @@ describe('Tracekit - Safari Tests', () => { safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:1588410 promiseReactionJob@[native code]`, }; - const ex = exceptionFromError(SAFARI_EXTENSION_EXCEPTION); + const ex = exceptionFromError(parser, SAFARI_EXTENSION_EXCEPTION); expect(ex).toEqual({ value: "undefined is not an object (evaluating 'e.groups.includes')", @@ -191,7 +195,7 @@ describe('Tracekit - Safari Tests', () => { at safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`, }; - const ex = exceptionFromError(SAFARI_WEB_EXTENSION_EXCEPTION); + const ex = exceptionFromError(parser, SAFARI_WEB_EXTENSION_EXCEPTION); expect(ex).toEqual({ value: 'wat', @@ -225,7 +229,7 @@ describe('Tracekit - Safari Tests', () => { safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:56027 promiseReactionJob@[native code]`, }; - const ex = exceptionFromError(SAFARI_EXTENSION_EXCEPTION); + const ex = exceptionFromError(parser, SAFARI_EXTENSION_EXCEPTION); expect(ex).toEqual({ value: "undefined is not an object (evaluating 'e.groups.includes')", @@ -263,7 +267,7 @@ describe('Tracekit - Safari Tests', () => { global code@http://localhost:5000/test:24:10`, }; - const ex = exceptionFromError(SAFARI12_NATIVE_CODE_EXCEPTION); + const ex = exceptionFromError(parser, SAFARI12_NATIVE_CODE_EXCEPTION); expect(ex).toEqual({ value: 'test', @@ -297,7 +301,7 @@ describe('Tracekit - Safari Tests', () => { http://localhost:5000/:50:29`, }; - const ex = exceptionFromError(SAFARI12_EVAL_EXCEPTION); + const ex = exceptionFromError(parser, SAFARI12_EVAL_EXCEPTION); expect(ex).toEqual({ value: 'aha', diff --git a/packages/utils/src/stacktrace.ts b/packages/utils/src/stacktrace.ts index 7c9dddeee298..acb66cf01618 100644 --- a/packages/utils/src/stacktrace.ts +++ b/packages/utils/src/stacktrace.ts @@ -34,6 +34,29 @@ export function createStackParser(...parsers: StackLineParser[]): StackParser { }; } +interface StackParserOptions { + stackParser?: StackParser | StackLineParser[]; +} + +/** + * Gets a stack parser implementation from options + * + * If options contains an array of line parsers, it is converted into a parser + */ +export function stackParserFromOptions(options: StackParserOptions | undefined): StackParser { + if (options) { + if (Array.isArray(options.stackParser)) { + options.stackParser = createStackParser(...options.stackParser); + } + + if (typeof options.stackParser === 'function') { + return options.stackParser; + } + } + + return _ => []; +} + /** * @hidden */ From 52047b6fdb284e429ffc953afd59a0dfc3e38c6b Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 8 Apr 2022 13:30:23 +0100 Subject: [PATCH 15/20] Lint --- packages/browser/test/unit/integrations/linkederrors.test.ts | 4 +--- packages/browser/test/unit/tracekit/chromium.test.ts | 1 + packages/browser/test/unit/tracekit/firefox.test.ts | 1 + packages/browser/test/unit/tracekit/ie.test.ts | 1 + packages/browser/test/unit/tracekit/misc.test.ts | 1 + packages/browser/test/unit/tracekit/opera.test.ts | 1 + packages/browser/test/unit/tracekit/react-native.test.ts | 1 + packages/browser/test/unit/tracekit/react.test.ts | 1 + packages/browser/test/unit/tracekit/safari.test.ts | 1 + 9 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/browser/test/unit/integrations/linkederrors.test.ts b/packages/browser/test/unit/integrations/linkederrors.test.ts index 25a7bee44fcb..7019d09c0605 100644 --- a/packages/browser/test/unit/integrations/linkederrors.test.ts +++ b/packages/browser/test/unit/integrations/linkederrors.test.ts @@ -2,8 +2,8 @@ import { ExtendedError } from '@sentry/types'; import { createStackParser } from '@sentry/utils'; import { BrowserBackend } from '../../../src/backend'; -import { defaultStackParsers } from '../../../src/stack-parsers'; import * as LinkedErrorsModule from '../../../src/integrations/linkederrors'; +import { defaultStackParsers } from '../../../src/stack-parsers'; const parser = createStackParser(...defaultStackParsers); @@ -44,8 +44,6 @@ describe('LinkedErrors', () => { originalException, }); - console.log(result.exception.values); - // It shouldn't include root exception, as it's already processed in the event by the main error handler expect(result.exception.values.length).toBe(3); expect(result.exception.values[0].type).toBe('SyntaxError'); diff --git a/packages/browser/test/unit/tracekit/chromium.test.ts b/packages/browser/test/unit/tracekit/chromium.test.ts index af522ef9bb5c..67189984563a 100644 --- a/packages/browser/test/unit/tracekit/chromium.test.ts +++ b/packages/browser/test/unit/tracekit/chromium.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/firefox.test.ts b/packages/browser/test/unit/tracekit/firefox.test.ts index c0ea42b87e7a..87929568c857 100644 --- a/packages/browser/test/unit/tracekit/firefox.test.ts +++ b/packages/browser/test/unit/tracekit/firefox.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/ie.test.ts b/packages/browser/test/unit/tracekit/ie.test.ts index 730b4b4d8b24..9a796060f1cc 100644 --- a/packages/browser/test/unit/tracekit/ie.test.ts +++ b/packages/browser/test/unit/tracekit/ie.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/misc.test.ts b/packages/browser/test/unit/tracekit/misc.test.ts index 281e18053749..976f39e2449e 100644 --- a/packages/browser/test/unit/tracekit/misc.test.ts +++ b/packages/browser/test/unit/tracekit/misc.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/opera.test.ts b/packages/browser/test/unit/tracekit/opera.test.ts index b1a32d755c98..a97675824e18 100644 --- a/packages/browser/test/unit/tracekit/opera.test.ts +++ b/packages/browser/test/unit/tracekit/opera.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/react-native.test.ts b/packages/browser/test/unit/tracekit/react-native.test.ts index 2b7246df73a5..ac469a92246a 100644 --- a/packages/browser/test/unit/tracekit/react-native.test.ts +++ b/packages/browser/test/unit/tracekit/react-native.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/react.test.ts b/packages/browser/test/unit/tracekit/react.test.ts index b15659437a9e..55229b333403 100644 --- a/packages/browser/test/unit/tracekit/react.test.ts +++ b/packages/browser/test/unit/tracekit/react.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; diff --git a/packages/browser/test/unit/tracekit/safari.test.ts b/packages/browser/test/unit/tracekit/safari.test.ts index 0c1b2b1a9127..beff492a6c1d 100644 --- a/packages/browser/test/unit/tracekit/safari.test.ts +++ b/packages/browser/test/unit/tracekit/safari.test.ts @@ -1,4 +1,5 @@ import { createStackParser } from '@sentry/utils'; + import { exceptionFromError } from '../../../src/eventbuilder'; import { defaultStackParsers } from '../../../src/stack-parsers'; From 14a10dc22395e817d13f6f00b0279945b6ca46b7 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 8 Apr 2022 16:06:46 +0100 Subject: [PATCH 16/20] make generic across all javascript --- packages/browser/src/backend.ts | 8 +---- packages/node/src/backend.ts | 8 +++-- packages/node/src/eventbuilder.ts | 20 +++++------ .../node/src/integrations/linkederrors.ts | 31 ++++++++++------- packages/node/src/sdk.ts | 5 +++ packages/node/src/stack-parser.ts | 3 +- packages/node/test/context-lines.test.ts | 12 ++++--- packages/node/test/index.test.ts | 13 ++++++++ .../test/integrations/linkederrors.test.ts | 26 ++++++++------- packages/node/test/stacktrace.test.ts | 33 +++++++++++-------- packages/types/src/index.ts | 2 +- packages/types/src/options.ts | 7 ++++ packages/types/src/stacktrace.ts | 4 +++ packages/utils/src/stacktrace.ts | 6 +--- 14 files changed, 110 insertions(+), 68 deletions(-) diff --git a/packages/browser/src/backend.ts b/packages/browser/src/backend.ts index 18d2f5d5756a..fe0b74c552d8 100644 --- a/packages/browser/src/backend.ts +++ b/packages/browser/src/backend.ts @@ -1,6 +1,6 @@ import { BaseBackend, getEnvelopeEndpointWithUrlEncodedAuth, initAPIDetails } from '@sentry/core'; import { Event, EventHint, Options, Severity, Transport, TransportOptions } from '@sentry/types'; -import { StackLineParser, StackParser, stackParserFromOptions, supportsFetch } from '@sentry/utils'; +import { stackParserFromOptions, supportsFetch } from '@sentry/utils'; import { eventFromException, eventFromMessage } from './eventbuilder'; import { FetchTransport, makeNewFetchTransport, makeNewXHRTransport, XHRTransport } from './transports'; @@ -23,12 +23,6 @@ export interface BrowserOptions extends Options { * By default, all errors will be sent. */ denyUrls?: Array; - - /** - * A stack parser implementation or an array of stack line parsers - * By default, a stack parser is supplied for all supported browsers - */ - stackParser?: StackParser | StackLineParser[]; } /** diff --git a/packages/node/src/backend.ts b/packages/node/src/backend.ts index f319673ebc18..d8d7bd749bd4 100644 --- a/packages/node/src/backend.ts +++ b/packages/node/src/backend.ts @@ -1,6 +1,6 @@ import { BaseBackend, getEnvelopeEndpointWithUrlEncodedAuth, initAPIDetails } from '@sentry/core'; import { Event, EventHint, Severity, Transport, TransportOptions } from '@sentry/types'; -import { makeDsn, resolvedSyncPromise } from '@sentry/utils'; +import { makeDsn, resolvedSyncPromise, stackParserFromOptions } from '@sentry/utils'; import { eventFromMessage, eventFromUnknownInput } from './eventbuilder'; import { HTTPSTransport, HTTPTransport, makeNodeTransport } from './transports'; @@ -16,14 +16,16 @@ export class NodeBackend extends BaseBackend { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types public eventFromException(exception: any, hint?: EventHint): PromiseLike { - return resolvedSyncPromise(eventFromUnknownInput(exception, hint)); + return resolvedSyncPromise(eventFromUnknownInput(stackParserFromOptions(this._options), exception, hint)); } /** * @inheritDoc */ public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): PromiseLike { - return resolvedSyncPromise(eventFromMessage(message, level, hint, this._options.attachStacktrace)); + return resolvedSyncPromise( + eventFromMessage(stackParserFromOptions(this._options), message, level, hint, this._options.attachStacktrace), + ); } /** diff --git a/packages/node/src/eventbuilder.ts b/packages/node/src/eventbuilder.ts index 0376f21a59c8..c5d2b47590a9 100644 --- a/packages/node/src/eventbuilder.ts +++ b/packages/node/src/eventbuilder.ts @@ -1,34 +1,31 @@ import { getCurrentHub } from '@sentry/hub'; -import { Event, EventHint, Exception, Mechanism, Severity, StackFrame } from '@sentry/types'; +import { Event, EventHint, Exception, Mechanism, Severity, StackFrame, StackParser } from '@sentry/types'; import { addExceptionMechanism, addExceptionTypeValue, - createStackParser, extractExceptionKeysForMessage, isError, isPlainObject, normalizeToSize, } from '@sentry/utils'; -import { nodeStackParser } from './stack-parser'; - /** * Extracts stack frames from the error.stack string */ -export function parseStackFrames(error: Error): StackFrame[] { - return createStackParser(nodeStackParser)(error.stack || '', 1); +export function parseStackFrames(stackParser: StackParser, error: Error): StackFrame[] { + return stackParser(error.stack || '', 1); } /** * Extracts stack frames from the error and builds a Sentry Exception */ -export function exceptionFromError(error: Error): Exception { +export function exceptionFromError(stackParser: StackParser, error: Error): Exception { const exception: Exception = { type: error.name || error.constructor.name, value: error.message, }; - const frames = parseStackFrames(error); + const frames = parseStackFrames(stackParser, error); if (frames.length) { exception.stacktrace = { frames }; } @@ -40,7 +37,7 @@ export function exceptionFromError(error: Error): Exception { * Builds and Event from a Exception * @hidden */ -export function eventFromUnknownInput(exception: unknown, hint?: EventHint): Event { +export function eventFromUnknownInput(stackParser: StackParser, exception: unknown, hint?: EventHint): Event { // eslint-disable-next-line @typescript-eslint/no-explicit-any let ex: unknown = exception; const providedMechanism: Mechanism | undefined = @@ -73,7 +70,7 @@ export function eventFromUnknownInput(exception: unknown, hint?: EventHint): Eve const event = { exception: { - values: [exceptionFromError(ex as Error)], + values: [exceptionFromError(stackParser, ex as Error)], }, }; @@ -91,6 +88,7 @@ export function eventFromUnknownInput(exception: unknown, hint?: EventHint): Eve * @hidden */ export function eventFromMessage( + stackParser: StackParser, message: string, level: Severity = Severity.Info, hint?: EventHint, @@ -103,7 +101,7 @@ export function eventFromMessage( }; if (attachStacktrace && hint && hint.syntheticException) { - const frames = parseStackFrames(hint.syntheticException); + const frames = parseStackFrames(stackParser, hint.syntheticException); if (frames.length) { event.stacktrace = { frames }; } diff --git a/packages/node/src/integrations/linkederrors.ts b/packages/node/src/integrations/linkederrors.ts index 701400594971..c1dfd285db84 100644 --- a/packages/node/src/integrations/linkederrors.ts +++ b/packages/node/src/integrations/linkederrors.ts @@ -1,7 +1,8 @@ import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; -import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types'; -import { isInstanceOf, resolvedSyncPromise, SyncPromise } from '@sentry/utils'; +import { Event, EventHint, Exception, ExtendedError, Integration, StackParser } from '@sentry/types'; +import { isInstanceOf, resolvedSyncPromise, stackParserFromOptions, SyncPromise } from '@sentry/utils'; +import { NodeClient } from '../client'; import { exceptionFromError } from '../eventbuilder'; import { ContextLines } from './contextlines'; @@ -42,12 +43,15 @@ export class LinkedErrors implements Integration { * @inheritDoc */ public setupOnce(): void { - addGlobalEventProcessor((event: Event, hint?: EventHint) => { - const self = getCurrentHub().getIntegration(LinkedErrors); + addGlobalEventProcessor(async (event: Event, hint?: EventHint) => { + const hub = getCurrentHub(); + const self = hub.getIntegration(LinkedErrors); + const stackParser = stackParserFromOptions(hub.getClient()?.getOptions()); + if (self) { - const handler = self._handler && self._handler.bind(self); - return typeof handler === 'function' ? handler(event, hint) : event; + await self._handler(stackParser, event, hint); } + return event; }); } @@ -55,13 +59,13 @@ export class LinkedErrors implements Integration { /** * @inheritDoc */ - private _handler(event: Event, hint?: EventHint): PromiseLike { + private _handler(stackParser: StackParser, event: Event, hint?: EventHint): PromiseLike { if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) { return resolvedSyncPromise(event); } return new SyncPromise(resolve => { - void this._walkErrorTree(hint.originalException as Error, this._key) + void this._walkErrorTree(stackParser, hint.originalException as Error, this._key) .then((linkedErrors: Exception[]) => { if (event && event.exception && event.exception.values) { event.exception.values = [...linkedErrors, ...event.exception.values]; @@ -77,12 +81,17 @@ export class LinkedErrors implements Integration { /** * @inheritDoc */ - private async _walkErrorTree(error: ExtendedError, key: string, stack: Exception[] = []): Promise { + private async _walkErrorTree( + stackParser: StackParser, + error: ExtendedError, + key: string, + stack: Exception[] = [], + ): Promise { if (!isInstanceOf(error[key], Error) || stack.length + 1 >= this._limit) { return Promise.resolve(stack); } - const exception = exceptionFromError(error[key]); + const exception = exceptionFromError(stackParser, error[key]); // If the ContextLines integration is enabled, we add source code context to linked errors // because we can't guarantee the order that integrations are run. @@ -92,7 +101,7 @@ export class LinkedErrors implements Integration { } return new Promise((resolve, reject) => { - void this._walkErrorTree(error[key], key, [exception, ...stack]) + void this._walkErrorTree(stackParser, error[key], key, [exception, ...stack]) .then(resolve) .then(null, () => { reject(); diff --git a/packages/node/src/sdk.ts b/packages/node/src/sdk.ts index 7dd660a44048..095bd3114144 100644 --- a/packages/node/src/sdk.ts +++ b/packages/node/src/sdk.ts @@ -7,6 +7,7 @@ import * as domain from 'domain'; import { NodeClient } from './client'; import { IS_DEBUG_BUILD } from './flags'; import { Console, ContextLines, Http, LinkedErrors, OnUncaughtException, OnUnhandledRejection } from './integrations'; +import { nodeStackParser } from './stack-parser'; import { NodeOptions } from './types'; export const defaultIntegrations = [ @@ -120,6 +121,10 @@ export function init(options: NodeOptions = {}): void { options.autoSessionTracking = true; } + if (options.stackParser === undefined) { + options.stackParser = [nodeStackParser]; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any if ((domain as any).active) { setHubOnCarrier(carrier, getCurrentHub()); diff --git a/packages/node/src/stack-parser.ts b/packages/node/src/stack-parser.ts index a37e38001da3..79a86e9018ee 100644 --- a/packages/node/src/stack-parser.ts +++ b/packages/node/src/stack-parser.ts @@ -1,4 +1,5 @@ -import { basename, dirname, StackLineParser, StackLineParserFn } from '@sentry/utils'; +import { StackLineParser, StackLineParserFn } from '@sentry/types'; +import { basename, dirname } from '@sentry/utils'; /** Gets the module */ function getModule(filename: string | undefined): string | undefined { diff --git a/packages/node/test/context-lines.test.ts b/packages/node/test/context-lines.test.ts index 821c95d7b6b0..55dce7be1615 100644 --- a/packages/node/test/context-lines.test.ts +++ b/packages/node/test/context-lines.test.ts @@ -1,10 +1,14 @@ import { StackFrame } from '@sentry/types'; +import { createStackParser } from '@sentry/utils'; import * as fs from 'fs'; import { parseStackFrames } from '../src/eventbuilder'; import { ContextLines, resetFileContentCache } from '../src/integrations/contextlines'; +import { nodeStackParser } from '../src/stack-parser'; import { getError } from './helper/error'; +const parser = createStackParser(nodeStackParser); + describe('ContextLines', () => { let readFileSpy: jest.SpyInstance; let contextLines: ContextLines; @@ -27,7 +31,7 @@ describe('ContextLines', () => { test('parseStack with same file', async () => { expect.assertions(1); - const frames = parseStackFrames(new Error('test')); + const frames = parseStackFrames(parser, new Error('test')); await addContext(Array.from(frames)); @@ -57,12 +61,12 @@ describe('ContextLines', () => { test('parseStack with adding different file', async () => { expect.assertions(1); - const frames = parseStackFrames(new Error('test')); + const frames = parseStackFrames(parser, new Error('test')); await addContext(frames); const numCalls = readFileSpy.mock.calls.length; - const parsedFrames = parseStackFrames(getError()); + const parsedFrames = parseStackFrames(parser, getError()); await addContext(parsedFrames); const newErrorCalls = readFileSpy.mock.calls.length; @@ -100,7 +104,7 @@ describe('ContextLines', () => { contextLines = new ContextLines({ frameContextLines: 0 }); expect.assertions(1); - const frames = parseStackFrames(new Error('test')); + const frames = parseStackFrames(parser, new Error('test')); await addContext(frames); expect(readFileSpy).toHaveBeenCalledTimes(0); diff --git a/packages/node/test/index.test.ts b/packages/node/test/index.test.ts index 0af38dae80fb..53312eba5ccd 100644 --- a/packages/node/test/index.test.ts +++ b/packages/node/test/index.test.ts @@ -1,6 +1,7 @@ import { initAndBind, SDK_VERSION } from '@sentry/core'; import { getMainCarrier } from '@sentry/hub'; import { Integration } from '@sentry/types'; +import { createStackParser } from '@sentry/utils'; import * as domain from 'domain'; import { @@ -17,6 +18,9 @@ import { } from '../src'; import { NodeBackend } from '../src/backend'; import { ContextLines, LinkedErrors } from '../src/integrations'; +import { nodeStackParser } from '../src/stack-parser'; + +const stackParser = createStackParser(nodeStackParser); jest.mock('@sentry/core', () => { const original = jest.requireActual('@sentry/core'); @@ -87,6 +91,7 @@ describe('SentryNode', () => { test('record auto breadcrumbs', done => { const client = new NodeClient({ + stackParser, beforeSend: (event: Event) => { // TODO: It should be 3, but we don't capture a breadcrumb // for our own captureMessage/captureException calls yet @@ -118,6 +123,7 @@ describe('SentryNode', () => { expect.assertions(6); getCurrentHub().bindClient( new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect(event.tags).toEqual({ test: '1' }); expect(event.exception).not.toBeUndefined(); @@ -145,6 +151,7 @@ describe('SentryNode', () => { expect.assertions(6); getCurrentHub().bindClient( new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect(event.tags).toEqual({ test: '1' }); expect(event.exception).not.toBeUndefined(); @@ -172,6 +179,7 @@ describe('SentryNode', () => { expect.assertions(10); getCurrentHub().bindClient( new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect(event.tags).toEqual({ test: '1' }); expect(event.exception).not.toBeUndefined(); @@ -203,6 +211,7 @@ describe('SentryNode', () => { expect.assertions(15); getCurrentHub().bindClient( new NodeClient({ + stackParser, integrations: [new ContextLines(), new LinkedErrors()], beforeSend: (event: Event) => { expect(event.exception).not.toBeUndefined(); @@ -243,6 +252,7 @@ describe('SentryNode', () => { expect.assertions(2); getCurrentHub().bindClient( new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect(event.message).toBe('test'); expect(event.exception).toBeUndefined(); @@ -259,6 +269,7 @@ describe('SentryNode', () => { expect.assertions(2); getCurrentHub().bindClient( new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect(event.message).toBe('test event'); expect(event.exception).toBeUndefined(); @@ -275,6 +286,7 @@ describe('SentryNode', () => { const d = domain.create(); const client = new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect(event.message).toBe('test domain'); expect(event.exception).toBeUndefined(); @@ -295,6 +307,7 @@ describe('SentryNode', () => { expect.assertions(1); getCurrentHub().bindClient( new NodeClient({ + stackParser, beforeSend: (event: Event) => { expect( event.exception!.values![0].stacktrace!.frames![ diff --git a/packages/node/test/integrations/linkederrors.test.ts b/packages/node/test/integrations/linkederrors.test.ts index 7dcaf077e4c6..e69664242dbe 100644 --- a/packages/node/test/integrations/linkederrors.test.ts +++ b/packages/node/test/integrations/linkederrors.test.ts @@ -1,8 +1,12 @@ import { ExtendedError } from '@sentry/types'; +import { createStackParser } from '@sentry/utils'; import { Event } from '../../src'; import { NodeBackend } from '../../src/backend'; import { LinkedErrors } from '../../src/integrations/linkederrors'; +import { nodeStackParser } from '../../src/stack-parser'; + +const stackParser = createStackParser(nodeStackParser); let linkedErrors: any; @@ -18,7 +22,7 @@ describe('LinkedErrors', () => { const event = { message: 'foo', }; - return linkedErrors._handler(event).then((result: any) => { + return linkedErrors._handler(stackParser, event).then((result: any) => { expect(spy.mock.calls.length).toEqual(0); expect(result).toEqual(event); }); @@ -28,13 +32,13 @@ describe('LinkedErrors', () => { expect.assertions(2); const spy = jest.spyOn(linkedErrors, '_walkErrorTree'); const one = new Error('originalException'); - const backend = new NodeBackend({}); + const backend = new NodeBackend({ stackParser }); let event: Event | undefined; return backend .eventFromException(one) .then(eventFromException => { event = eventFromException; - return linkedErrors._handler(eventFromException); + return linkedErrors._handler(stackParser, eventFromException); }) .then(result => { expect(spy.mock.calls.length).toEqual(0); @@ -51,10 +55,10 @@ describe('LinkedErrors', () => { }), ); const one = new Error('originalException'); - const backend = new NodeBackend({}); + const backend = new NodeBackend({ stackParser }); return backend.eventFromException(one).then(event => linkedErrors - ._handler(event, { + ._handler(stackParser, event, { originalException: one, }) .then((_: any) => { @@ -71,10 +75,10 @@ describe('LinkedErrors', () => { one.cause = two; two.cause = three; - const backend = new NodeBackend({}); + const backend = new NodeBackend({ stackParser }); return backend.eventFromException(one).then(event => linkedErrors - ._handler(event, { + ._handler(stackParser, event, { originalException: one, }) .then((result: any) => { @@ -104,10 +108,10 @@ describe('LinkedErrors', () => { one.reason = two; two.reason = three; - const backend = new NodeBackend({}); + const backend = new NodeBackend({ stackParser }); return backend.eventFromException(one).then(event => linkedErrors - ._handler(event, { + ._handler(stackParser, event, { originalException: one, }) .then((result: any) => { @@ -137,10 +141,10 @@ describe('LinkedErrors', () => { one.cause = two; two.cause = three; - const backend = new NodeBackend({}); + const backend = new NodeBackend({ stackParser }); return backend.eventFromException(one).then(event => linkedErrors - ._handler(event, { + ._handler(stackParser, event, { originalException: one, }) .then((result: any) => { diff --git a/packages/node/test/stacktrace.test.ts b/packages/node/test/stacktrace.test.ts index 656ba1a69a9b..267a167bb1c2 100644 --- a/packages/node/test/stacktrace.test.ts +++ b/packages/node/test/stacktrace.test.ts @@ -10,7 +10,12 @@ * @license MIT */ +import { createStackParser } from '@sentry/utils'; + import { parseStackFrames } from '../src/eventbuilder'; +import { nodeStackParser } from '../src/stack-parser'; + +const stackParser = createStackParser(nodeStackParser); function testBasic() { return new Error('something went wrong'); @@ -26,17 +31,17 @@ function evalWrapper() { describe('Stack parsing', () => { test('test basic error', () => { - const frames = parseStackFrames(testBasic()); + const frames = parseStackFrames(stackParser, testBasic()); const last = frames.length - 1; expect(frames[last].filename).toEqual(__filename); expect(frames[last].function).toEqual('testBasic'); - expect(frames[last].lineno).toEqual(16); + expect(frames[last].lineno).toEqual(20); expect(frames[last].colno).toEqual(10); }); test('test error with wrapper', () => { - const frames = parseStackFrames(testWrapper()); + const frames = parseStackFrames(stackParser, testWrapper()); const last = frames.length - 1; expect(frames[last].function).toEqual('testBasic'); @@ -44,7 +49,7 @@ describe('Stack parsing', () => { }); test('test error with eval wrapper', () => { - const frames = parseStackFrames(evalWrapper()); + const frames = parseStackFrames(stackParser, evalWrapper()); const last = frames.length - 1; expect(frames[last].function).toEqual('testBasic'); @@ -59,7 +64,7 @@ describe('Stack parsing', () => { ' at [object Object].global.every [as _onTimeout] (/Users/hoitz/develop/test.coffee:36:3)\n' + ' at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)\n'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -83,7 +88,7 @@ describe('Stack parsing', () => { test('parses undefined stack', () => { const err = { stack: undefined }; - const trace = parseStackFrames(err as Error); + const trace = parseStackFrames(stackParser, err as Error); expect(trace).toEqual([]); }); @@ -97,7 +102,7 @@ describe('Stack parsing', () => { 'oh no' + ' at TestCase.run (/Users/felix/code/node-fast-or-slow/lib/test_case.js:61:8)\n'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -126,7 +131,7 @@ describe('Stack parsing', () => { ' at Test.fn (/Users/felix/code/node-fast-or-slow/test/fast/example/test-example.js:6)\n' + ' at Test.run (/Users/felix/code/node-fast-or-slow/lib/test.js:45)'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -157,7 +162,7 @@ describe('Stack parsing', () => { ' at Array.0 (native)\n' + ' at EventEmitter._tickCallback (node.js:126:26)'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -212,7 +217,7 @@ describe('Stack parsing', () => { const err = new Error(); err.stack = 'AssertionError: true == false\n' + ' at /Users/felix/code/node-fast-or-slow/lib/test_case.js:80:10'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -232,7 +237,7 @@ describe('Stack parsing', () => { 'AssertionError: true == false\nAnd some more shit\n' + ' at /Users/felix/code/node-fast-or-slow/lib/test_case.js:80:10'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -252,7 +257,7 @@ describe('Stack parsing', () => { 'AssertionError: expected [] to be arguments\n' + ' at Assertion.prop.(anonymous function) (/Users/den/Projects/should.js/lib/should.js:60:14)\n'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -273,7 +278,7 @@ describe('Stack parsing', () => { ' at Test.run (/Users/felix (something)/code/node-fast-or-slow/lib/test.js:45:10)\n' + ' at TestCase.run (/Users/felix (something)/code/node-fast-or-slow/lib/test_case.js:61:8)\n'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { @@ -309,7 +314,7 @@ describe('Stack parsing', () => { ' at async onBatch (/code/node_modules/kafkajs/src/consumer/runner.js:326:9)\n' + ' at async /code/node_modules/kafkajs/src/consumer/runner.js:376:15\n'; - const frames = parseStackFrames(err); + const frames = parseStackFrames(stackParser, err); expect(frames).toEqual([ { diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 13651b7cd78e..20856f52aa64 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -50,7 +50,7 @@ export { Severity } from './severity'; export { SeverityLevel, SeverityLevels } from './severity'; export { Span, SpanContext } from './span'; export { StackFrame } from './stackframe'; -export { Stacktrace } from './stacktrace'; +export { Stacktrace, StackParser, StackLineParser, StackLineParserFn } from './stacktrace'; export { CustomSamplingContext, Measurements, diff --git a/packages/types/src/options.ts b/packages/types/src/options.ts index 3fefd41ca137..a7306acdd76f 100644 --- a/packages/types/src/options.ts +++ b/packages/types/src/options.ts @@ -3,6 +3,7 @@ import { Event, EventHint } from './event'; import { Integration } from './integration'; import { CaptureContext } from './scope'; import { SdkMetadata } from './sdkmetadata'; +import { StackLineParser, StackParser } from './stacktrace'; import { SamplingContext } from './transaction'; import { Transport, TransportClass, TransportOptions } from './transport'; @@ -149,6 +150,12 @@ export interface Options { */ initialScope?: CaptureContext; + /** + * A stack parser implementation or an array of stack line parsers + * By default, a stack parser is supplied for all supported browsers + */ + stackParser?: StackParser | StackLineParser[]; + /** * Set of metadata about the SDK that can be internally used to enhance envelopes and events, * and provide additional data about every request. diff --git a/packages/types/src/stacktrace.ts b/packages/types/src/stacktrace.ts index 120a1b471af6..ae2f350f716b 100644 --- a/packages/types/src/stacktrace.ts +++ b/packages/types/src/stacktrace.ts @@ -5,3 +5,7 @@ export interface Stacktrace { frames?: StackFrame[]; frames_omitted?: [number, number]; } + +export type StackParser = (stack: string, skipFirst?: number) => StackFrame[]; +export type StackLineParserFn = (line: string) => StackFrame | undefined; +export type StackLineParser = [number, StackLineParserFn]; diff --git a/packages/utils/src/stacktrace.ts b/packages/utils/src/stacktrace.ts index acb66cf01618..15c5401c09bd 100644 --- a/packages/utils/src/stacktrace.ts +++ b/packages/utils/src/stacktrace.ts @@ -1,11 +1,7 @@ -import { StackFrame } from '@sentry/types'; +import { StackFrame, StackLineParser, StackParser } from '@sentry/types'; const STACKTRACE_LIMIT = 50; -export type StackParser = (stack: string, skipFirst?: number) => StackFrame[]; -export type StackLineParserFn = (line: string) => StackFrame | undefined; -export type StackLineParser = [number, StackLineParserFn]; - /** * Creates a stack parser with the supplied line parsers * From 0988600ad53c4883180ad8083d4e8fb8b85f6616 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 8 Apr 2022 16:35:27 +0100 Subject: [PATCH 17/20] Fix build --- packages/browser/src/eventbuilder.ts | 3 +-- packages/browser/src/integrations/globalhandlers.ts | 3 +-- packages/browser/src/integrations/linkederrors.ts | 4 ++-- packages/browser/src/stack-parsers.ts | 3 +-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/browser/src/eventbuilder.ts b/packages/browser/src/eventbuilder.ts index eff2bc46095d..c85f1ec7d818 100644 --- a/packages/browser/src/eventbuilder.ts +++ b/packages/browser/src/eventbuilder.ts @@ -1,4 +1,4 @@ -import { Event, EventHint, Exception, Severity, StackFrame } from '@sentry/types'; +import { Event, EventHint, Exception, Severity, StackFrame, StackParser } from '@sentry/types'; import { addExceptionMechanism, addExceptionTypeValue, @@ -11,7 +11,6 @@ import { isPlainObject, normalizeToSize, resolvedSyncPromise, - StackParser, } from '@sentry/utils'; /** diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts index 38257cf6a7aa..70966e4f7ec5 100644 --- a/packages/browser/src/integrations/globalhandlers.ts +++ b/packages/browser/src/integrations/globalhandlers.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { getCurrentHub } from '@sentry/core'; -import { Event, EventHint, Hub, Integration, Primitive, Severity } from '@sentry/types'; +import { Event, EventHint, Hub, Integration, Primitive, Severity, StackParser } from '@sentry/types'; import { addExceptionMechanism, addInstrumentationHandler, @@ -9,7 +9,6 @@ import { isPrimitive, isString, logger, - StackParser, stackParserFromOptions, } from '@sentry/utils'; diff --git a/packages/browser/src/integrations/linkederrors.ts b/packages/browser/src/integrations/linkederrors.ts index 2bd053db0c79..1cc30c182950 100644 --- a/packages/browser/src/integrations/linkederrors.ts +++ b/packages/browser/src/integrations/linkederrors.ts @@ -1,6 +1,6 @@ import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; -import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types'; -import { isInstanceOf, StackParser, stackParserFromOptions } from '@sentry/utils'; +import { Event, EventHint, Exception, ExtendedError, Integration, StackParser } from '@sentry/types'; +import { isInstanceOf, stackParserFromOptions } from '@sentry/utils'; import { BrowserClient } from '../client'; import { exceptionFromError } from '../eventbuilder'; diff --git a/packages/browser/src/stack-parsers.ts b/packages/browser/src/stack-parsers.ts index 7d9298fc24c6..5ee652001854 100644 --- a/packages/browser/src/stack-parsers.ts +++ b/packages/browser/src/stack-parsers.ts @@ -1,5 +1,4 @@ -import { StackFrame } from '@sentry/types'; -import { StackLineParser, StackLineParserFn } from '@sentry/utils'; +import { StackFrame, StackLineParser, StackLineParserFn } from '@sentry/types'; // global reference to slice const UNKNOWN_FUNCTION = '?'; From c6e8a604b4bf02a926ec698da06770d5b6090061 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 8 Apr 2022 17:05:35 +0100 Subject: [PATCH 18/20] export nodeStackParser --- packages/node/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 9f65c3f1a1a8..c6f5b6a3802f 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -47,6 +47,7 @@ export { NodeClient } from './client'; export { defaultIntegrations, init, lastEventId, flush, close, getSentryRelease } from './sdk'; export { deepReadDirSync } from './utils'; export { SDK_NAME } from './version'; +export { nodeStackParser } from './stack-parser'; import { Integrations as CoreIntegrations } from '@sentry/core'; import { getMainCarrier } from '@sentry/hub'; From 03b5d5cf54e2a789b682195db7008ab4b6d4afcc Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 8 Apr 2022 17:10:35 +0100 Subject: [PATCH 19/20] Fix test --- packages/node/test/stacktrace.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node/test/stacktrace.test.ts b/packages/node/test/stacktrace.test.ts index 267a167bb1c2..ec5ef8b94800 100644 --- a/packages/node/test/stacktrace.test.ts +++ b/packages/node/test/stacktrace.test.ts @@ -36,7 +36,7 @@ describe('Stack parsing', () => { const last = frames.length - 1; expect(frames[last].filename).toEqual(__filename); expect(frames[last].function).toEqual('testBasic'); - expect(frames[last].lineno).toEqual(20); + expect(frames[last].lineno).toEqual(21); expect(frames[last].colno).toEqual(10); }); From 623fcfdfd7aed9ae4af8ebec532a509264481d7b Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Tue, 12 Apr 2022 14:16:39 +0100 Subject: [PATCH 20/20] Fix tests from bad merge --- .../browser/test/unit/integrations/linkederrors.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/browser/test/unit/integrations/linkederrors.test.ts b/packages/browser/test/unit/integrations/linkederrors.test.ts index 83c179939785..2589487dbcac 100644 --- a/packages/browser/test/unit/integrations/linkederrors.test.ts +++ b/packages/browser/test/unit/integrations/linkederrors.test.ts @@ -40,7 +40,7 @@ describe('LinkedErrors', () => { const originalException = one; const client = new BrowserClient({ stackParser: parser }); return client.eventFromException(originalException).then(event => { - const result = LinkedErrorsModule._handler('cause', 5, event, { + const result = LinkedErrorsModule._handler(parser, 'cause', 5, event, { originalException, }); @@ -70,7 +70,7 @@ describe('LinkedErrors', () => { const originalException = one; const client = new BrowserClient({ stackParser: parser }); return client.eventFromException(originalException).then(event => { - const result = LinkedErrorsModule._handler('reason', 5, event, { + const result = LinkedErrorsModule._handler(parser, 'reason', 5, event, { originalException, }); @@ -97,7 +97,7 @@ describe('LinkedErrors', () => { const client = new BrowserClient({ stackParser: parser }); const originalException = one; return client.eventFromException(originalException).then(event => { - const result = LinkedErrorsModule._handler('cause', 2, event, { + const result = LinkedErrorsModule._handler(parser, 'cause', 2, event, { originalException, });