From 7ed50ed33ae8e0c584c25298cd94a551cfbd7838 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 28 Aug 2023 15:42:24 +0100 Subject: [PATCH 1/7] fix: Defer tracing decision to downstream SDKs when using SDK without performance (#8839) --- packages/core/src/scope.ts | 1 - packages/hub/test/scope.test.ts | 4 ++-- packages/node/test/integrations/http.test.ts | 5 +++-- packages/tracing-internal/src/browser/browsertracing.ts | 2 +- packages/types/src/tracing.ts | 2 +- packages/utils/src/tracing.ts | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index b72defc56016..8875f1c996f2 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -636,6 +636,5 @@ function generatePropagationContext(): PropagationContext { return { traceId: uuid4(), spanId: uuid4().substring(16), - sampled: false, }; } diff --git a/packages/hub/test/scope.test.ts b/packages/hub/test/scope.test.ts index 982cba766a87..4c0d830340ec 100644 --- a/packages/hub/test/scope.test.ts +++ b/packages/hub/test/scope.test.ts @@ -20,7 +20,7 @@ describe('Scope', () => { expect(scope._propagationContext).toEqual({ traceId: expect.any(String), spanId: expect.any(String), - sampled: false, + sampled: undefined, dsc: undefined, parentSpanId: undefined, }); @@ -442,7 +442,7 @@ describe('Scope', () => { expect(scope._propagationContext).toEqual({ traceId: expect.any(String), spanId: expect.any(String), - sampled: false, + sampled: undefined, }); // @ts-expect-error accessing private property expect(scope._propagationContext).not.toEqual(oldPropagationContext); diff --git a/packages/node/test/integrations/http.test.ts b/packages/node/test/integrations/http.test.ts index e784eb308f54..0f1613a27345 100644 --- a/packages/node/test/integrations/http.test.ts +++ b/packages/node/test/integrations/http.test.ts @@ -208,10 +208,11 @@ describe('tracing', () => { const baggageHeader = request.getHeader('baggage') as string; const parts = sentryTraceHeader.split('-'); - expect(parts.length).toEqual(3); + + // Should not include sampling decision since we don't wanna influence the tracing decisions downstream + expect(parts.length).toEqual(2); expect(parts[0]).toEqual(traceId); expect(parts[1]).toEqual(expect.any(String)); - expect(parts[2]).toEqual('0'); expect(baggageHeader).toEqual( `sentry-environment=production,sentry-release=1.0.0,sentry-user_segment=segmentA,sentry-public_key=dogsarebadatkeepingsecrets,sentry-trace_id=${traceId}`, diff --git a/packages/tracing-internal/src/browser/browsertracing.ts b/packages/tracing-internal/src/browser/browsertracing.ts index d01c837d26c2..a11ea7ff2cf2 100644 --- a/packages/tracing-internal/src/browser/browsertracing.ts +++ b/packages/tracing-internal/src/browser/browsertracing.ts @@ -364,7 +364,7 @@ export class BrowserTracing implements Integration { traceId: idleTransaction.traceId, spanId: idleTransaction.spanId, parentSpanId: idleTransaction.parentSpanId, - sampled: !!idleTransaction.sampled, + sampled: idleTransaction.sampled, }); } diff --git a/packages/types/src/tracing.ts b/packages/types/src/tracing.ts index 11c4a1658d50..7c5b02c45596 100644 --- a/packages/types/src/tracing.ts +++ b/packages/types/src/tracing.ts @@ -5,7 +5,7 @@ export type TracePropagationTargets = (string | RegExp)[]; export interface PropagationContext { traceId: string; spanId: string; - sampled: boolean; + sampled?: boolean; parentSpanId?: string; dsc?: DynamicSamplingContext; } diff --git a/packages/utils/src/tracing.ts b/packages/utils/src/tracing.ts index f879b856f9f2..6ad839f2b920 100644 --- a/packages/utils/src/tracing.ts +++ b/packages/utils/src/tracing.ts @@ -61,7 +61,7 @@ export function tracingContextFromHeaders( const propagationContext: PropagationContext = { traceId: traceId || uuid4(), spanId: uuid4().substring(16), - sampled: parentSampled === undefined ? false : parentSampled, + sampled: parentSampled, }; if (parentSpanId) { From ff0da3e3f3317792e068e3d9f3820cabb2c32df8 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 29 Aug 2023 10:12:35 +0200 Subject: [PATCH 2/7] ref: Use consistent console instrumentation (#8879) While looking into logger issues, I noticed that we fill console.xxx multiple times. This PR changes that so that we use the console instrumentation from utils in all cases. --- packages/integrations/src/captureconsole.ts | 77 +++--- .../integrations/test/captureconsole.test.ts | 260 ++++++++++-------- packages/node/src/integrations/console.ts | 49 ++-- packages/utils/src/instrument.ts | 28 +- 4 files changed, 218 insertions(+), 196 deletions(-) diff --git a/packages/integrations/src/captureconsole.ts b/packages/integrations/src/captureconsole.ts index d72da5f2b5c4..993fb9414052 100644 --- a/packages/integrations/src/captureconsole.ts +++ b/packages/integrations/src/captureconsole.ts @@ -1,5 +1,11 @@ import type { EventProcessor, Hub, Integration } from '@sentry/types'; -import { CONSOLE_LEVELS, fill, GLOBAL_OBJ, safeJoin, severityLevelFromString } from '@sentry/utils'; +import { + addInstrumentationHandler, + CONSOLE_LEVELS, + GLOBAL_OBJ, + safeJoin, + severityLevelFromString, +} from '@sentry/utils'; /** Send Console API calls as Sentry Events */ export class CaptureConsole implements Integration { @@ -34,46 +40,45 @@ export class CaptureConsole implements Integration { return; } - this._levels.forEach((level: string) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - if (!(level in (GLOBAL_OBJ as any).console)) { + const levels = this._levels; + + addInstrumentationHandler('console', ({ args, level }: { args: unknown[]; level: string }) => { + if (!levels.includes(level)) { return; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access - fill((GLOBAL_OBJ as any).console, level, (originalConsoleMethod: () => any) => (...args: any[]): void => { - const hub = getCurrentHub(); - - if (hub.getIntegration(CaptureConsole)) { - hub.withScope(scope => { - scope.setLevel(severityLevelFromString(level)); - scope.setExtra('arguments', args); - scope.addEventProcessor(event => { - event.logger = 'console'; - return event; - }); + const hub = getCurrentHub(); - let message = safeJoin(args, ' '); - const error = args.find(arg => arg instanceof Error); - if (level === 'assert') { - if (args[0] === false) { - message = `Assertion failed: ${safeJoin(args.slice(1), ' ') || 'console.assert'}`; - scope.setExtra('arguments', args.slice(1)); - hub.captureMessage(message); - } - } else if (level === 'error' && error) { - hub.captureException(error); - } else { - hub.captureMessage(message); - } - }); - } + if (!hub.getIntegration(CaptureConsole)) { + return; + } - // this fails for some browsers. :( - if (originalConsoleMethod) { - originalConsoleMethod.apply(GLOBAL_OBJ.console, args); - } - }); + consoleHandler(hub, args, level); }); } } + +function consoleHandler(hub: Hub, args: unknown[], level: string): void { + hub.withScope(scope => { + scope.setLevel(severityLevelFromString(level)); + scope.setExtra('arguments', args); + scope.addEventProcessor(event => { + event.logger = 'console'; + return event; + }); + + let message = safeJoin(args, ' '); + const error = args.find(arg => arg instanceof Error); + if (level === 'assert') { + if (args[0] === false) { + message = `Assertion failed: ${safeJoin(args.slice(1), ' ') || 'console.assert'}`; + scope.setExtra('arguments', args.slice(1)); + hub.captureMessage(message); + } + } else if (level === 'error' && error) { + hub.captureException(error); + } else { + hub.captureMessage(message); + } + }); +} diff --git a/packages/integrations/test/captureconsole.test.ts b/packages/integrations/test/captureconsole.test.ts index 00e9f23c4564..0b851c493062 100644 --- a/packages/integrations/test/captureconsole.test.ts +++ b/packages/integrations/test/captureconsole.test.ts @@ -1,176 +1,194 @@ /* eslint-disable @typescript-eslint/unbound-method */ import type { Event, Hub, Integration } from '@sentry/types'; +import type { ConsoleLevel } from '@sentry/utils'; +import { addInstrumentationHandler, CONSOLE_LEVELS, GLOBAL_OBJ, originalConsoleMethods } from '@sentry/utils'; import { CaptureConsole } from '../src/captureconsole'; -const mockScope = { - setLevel: jest.fn(), - setExtra: jest.fn(), - addEventProcessor: jest.fn(), -}; - -const mockHub = { - withScope: jest.fn(callback => { - callback(mockScope); - }), - captureMessage: jest.fn(), - captureException: jest.fn(), -}; - -const mockConsole = { +const mockConsole: { [key in ConsoleLevel]: jest.Mock } = { debug: jest.fn(), log: jest.fn(), warn: jest.fn(), error: jest.fn(), assert: jest.fn(), info: jest.fn(), + trace: jest.fn(), }; -const getMockHubWithIntegration = (integration: Integration) => - ({ +function getMockHub(integration: Integration): Hub { + const mockScope = { + setLevel: jest.fn(), + setExtra: jest.fn(), + addEventProcessor: jest.fn(), + }; + + const mockHub = { + withScope: jest.fn(callback => { + callback(mockScope); + }), + captureMessage: jest.fn(), + captureException: jest.fn(), + getScope: jest.fn(() => mockScope), + }; + + return { ...mockHub, getIntegration: jest.fn(() => integration), - } as unknown as Hub); - -// We're using this to un-monkey patch the console after each test. -const originalConsole = Object.assign({}, global.console); + } as unknown as Hub; +} describe('CaptureConsole setup', () => { + // Ensure we've initialized the instrumentation so we can get the original one + addInstrumentationHandler('console', () => {}); + const _originalConsoleMethods = Object.assign({}, originalConsoleMethods); + beforeEach(() => { - // this suppresses output to the terminal running the tests, but doesn't interfere with our wrapping - Object.assign(global.console, mockConsole); + CONSOLE_LEVELS.forEach(key => { + originalConsoleMethods[key] = mockConsole[key]; + }); }); afterEach(() => { jest.clearAllMocks(); - // Un-monkey-patch the console functions - Object.assign(global.console, originalConsole); + CONSOLE_LEVELS.forEach(key => { + originalConsoleMethods[key] = _originalConsoleMethods[key]; + }); }); describe('monkeypatching', () => { - beforeEach(() => { - // for these tests only, we don't want to use the mock console, because we're testing for equality to methods from - // the original, so undo the global `beforeEach()` - Object.assign(global.console, originalConsole); - }); - it('should patch user-configured console levels', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'warn'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - expect(global.console.error).toBe(originalConsole.error); // not monkey patched - expect(global.console.log).not.toBe(originalConsole.log); // monkey patched - expect(global.console.warn).not.toBe(originalConsole.warn); // monkey patched + GLOBAL_OBJ.console.error('msg 1'); + GLOBAL_OBJ.console.log('msg 2'); + GLOBAL_OBJ.console.warn('msg 3'); + + expect(mockHub.captureMessage).toHaveBeenCalledTimes(2); }); it('should fall back to default console levels if none are provided', () => { const captureConsoleIntegration = new CaptureConsole(); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - // expect a set of defined console levels to have been monkey patched - expect(global.console.debug).not.toBe(originalConsole.debug); - expect(global.console.info).not.toBe(originalConsole.info); - expect(global.console.warn).not.toBe(originalConsole.warn); - expect(global.console.error).not.toBe(originalConsole.error); - expect(global.console.log).not.toBe(originalConsole.log); - expect(global.console.assert).not.toBe(originalConsole.assert); - expect(global.console.trace).not.toBe(originalConsole.trace); - - // any other fields should not have been patched - expect(global.console.table).toBe(originalConsole.table); + // Assert has a special handling + (['debug', 'info', 'warn', 'error', 'log', 'trace'] as const).forEach(key => { + GLOBAL_OBJ.console[key]('msg'); + }); + + GLOBAL_OBJ.console.assert(false); + + expect(mockHub.captureMessage).toHaveBeenCalledTimes(7); }); it('should not wrap any functions with an empty levels option', () => { const captureConsoleIntegration = new CaptureConsole({ levels: [] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - // expect the default set of console levels not to have been monkey patched - expect(global.console.debug).toBe(originalConsole.debug); - expect(global.console.info).toBe(originalConsole.info); - expect(global.console.warn).toBe(originalConsole.warn); - expect(global.console.error).toBe(originalConsole.error); - expect(global.console.log).toBe(originalConsole.log); - expect(global.console.assert).toBe(originalConsole.assert); + CONSOLE_LEVELS.forEach(key => { + GLOBAL_OBJ.console[key]('msg'); + }); - // suppress output from the logging we're about to do - global.console.log = global.console.info = jest.fn(); - - // expect no message to be captured with console.log - global.console.log('some message'); - expect(mockHub.captureMessage).not.toHaveBeenCalled(); + expect(mockHub.captureMessage).toHaveBeenCalledTimes(0); }); }); it('setup should fail gracefully when console is not available', () => { - const consoleRef = global.console; + const consoleRef = GLOBAL_OBJ.console; // @ts-ignore remove console - delete global.console; + delete GLOBAL_OBJ.console; + const captureConsoleIntegration = new CaptureConsole(); + const mockHub = getMockHub(captureConsoleIntegration); expect(() => { - const captureConsoleIntegration = new CaptureConsole(); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); }).not.toThrow(); // reinstate initial console - global.console = consoleRef; + GLOBAL_OBJ.console = consoleRef; }); it('should set a level in the scope when console function is called', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); + const mockScope = mockHub.getScope(); + // call a wrapped function - global.console.error('some logging message'); + GLOBAL_OBJ.console.error('some logging message'); expect(mockScope.setLevel).toHaveBeenCalledTimes(1); expect(mockScope.setLevel).toHaveBeenCalledWith('error'); }); - it('should send arguments as extra data on failed assertion', () => { + it('should send arguments as extra data', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - // call a wrapped function - global.console.log('some arg 1', 'some arg 2'); - global.console.log(); + const mockScope = mockHub.getScope(); + + GLOBAL_OBJ.console.log('some arg 1', 'some arg 2'); - expect(mockScope.setExtra).toHaveBeenCalledTimes(2); + expect(mockScope.setExtra).toHaveBeenCalledTimes(1); expect(mockScope.setExtra).toHaveBeenCalledWith('arguments', ['some arg 1', 'some arg 2']); + }); + + it('should send empty arguments as extra data', () => { + const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] }); + const mockHub = getMockHub(captureConsoleIntegration); + captureConsoleIntegration.setupOnce( + () => undefined, + () => mockHub, + ); + + const mockScope = mockHub.getScope(); + + GLOBAL_OBJ.console.log(); + + expect(mockScope.setExtra).toHaveBeenCalledTimes(1); expect(mockScope.setExtra).toHaveBeenCalledWith('arguments', []); }); it('should add an event processor that sets the `logger` field of events', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); + const mockScope = mockHub.getScope(); + // call a wrapped function - global.console.log('some message'); + GLOBAL_OBJ.console.log('some message'); expect(mockScope.addEventProcessor).toHaveBeenCalledTimes(1); - const addedEventProcessor = mockScope.addEventProcessor.mock.calls[0][0]; + const addedEventProcessor = (mockScope.addEventProcessor as jest.Mock).mock.calls[0][0]; const someEvent: Event = {}; addedEventProcessor(someEvent); @@ -179,12 +197,15 @@ describe('CaptureConsole setup', () => { it('should capture message on a failed assertion', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['assert'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.assert(1 + 1 === 3); + const mockScope = mockHub.getScope(); + + GLOBAL_OBJ.console.assert(1 + 1 === 3); expect(mockScope.setExtra).toHaveBeenLastCalledWith('arguments', []); expect(mockHub.captureMessage).toHaveBeenCalledTimes(1); @@ -193,12 +214,15 @@ describe('CaptureConsole setup', () => { it('should capture correct message on a failed assertion with message', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['assert'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.assert(1 + 1 === 3, 'expression is false'); + const mockScope = mockHub.getScope(); + + GLOBAL_OBJ.console.assert(1 + 1 === 3, 'expression is false'); expect(mockScope.setExtra).toHaveBeenLastCalledWith('arguments', ['expression is false']); expect(mockHub.captureMessage).toHaveBeenCalledTimes(1); @@ -207,23 +231,25 @@ describe('CaptureConsole setup', () => { it('should not capture message on a successful assertion', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['assert'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.assert(1 + 1 === 2); + GLOBAL_OBJ.console.assert(1 + 1 === 2); }); it('should capture exception when console logs an error object with level set to "error"', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); const someError = new Error('some error'); - global.console.error(someError); + GLOBAL_OBJ.console.error(someError); expect(mockHub.captureException).toHaveBeenCalledTimes(1); expect(mockHub.captureException).toHaveBeenCalledWith(someError); @@ -231,13 +257,14 @@ describe('CaptureConsole setup', () => { it('should capture exception on `console.error` when no levels are provided in constructor', () => { const captureConsoleIntegration = new CaptureConsole(); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); const someError = new Error('some error'); - global.console.error(someError); + GLOBAL_OBJ.console.error(someError); expect(mockHub.captureException).toHaveBeenCalledTimes(1); expect(mockHub.captureException).toHaveBeenCalledWith(someError); @@ -245,13 +272,14 @@ describe('CaptureConsole setup', () => { it('should capture exception when console logs an error object in any of the args when level set to "error"', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); const someError = new Error('some error'); - global.console.error('Something went wrong', someError); + GLOBAL_OBJ.console.error('Something went wrong', someError); expect(mockHub.captureException).toHaveBeenCalledTimes(1); expect(mockHub.captureException).toHaveBeenCalledWith(someError); @@ -259,12 +287,13 @@ describe('CaptureConsole setup', () => { it('should capture message on `console.log` when no levels are provided in constructor', () => { const captureConsoleIntegration = new CaptureConsole(); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.error('some message'); + GLOBAL_OBJ.console.error('some message'); expect(mockHub.captureMessage).toHaveBeenCalledTimes(1); expect(mockHub.captureMessage).toHaveBeenCalledWith('some message'); @@ -272,12 +301,13 @@ describe('CaptureConsole setup', () => { it('should capture message when console logs a non-error object with level set to "error"', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.error('some non-error message'); + GLOBAL_OBJ.console.error('some non-error message'); expect(mockHub.captureMessage).toHaveBeenCalledTimes(1); expect(mockHub.captureMessage).toHaveBeenCalledWith('some non-error message'); @@ -286,12 +316,13 @@ describe('CaptureConsole setup', () => { it('should capture a message for non-error log levels', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['info'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.info('some message'); + GLOBAL_OBJ.console.info('some message'); expect(mockHub.captureMessage).toHaveBeenCalledTimes(1); expect(mockHub.captureMessage).toHaveBeenCalledWith('some message'); @@ -299,70 +330,63 @@ describe('CaptureConsole setup', () => { it('should call the original console function when console members are called', () => { // Mock console log to test if it was called - const originalConsoleLog = global.console.log; + const originalConsoleLog = GLOBAL_OBJ.console.log; const mockConsoleLog = jest.fn(); - global.console.log = mockConsoleLog; + GLOBAL_OBJ.console.log = mockConsoleLog; const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); - global.console.log('some message 1', 'some message 2'); + GLOBAL_OBJ.console.log('some message 1', 'some message 2'); expect(mockConsoleLog).toHaveBeenCalledTimes(1); expect(mockConsoleLog).toHaveBeenCalledWith('some message 1', 'some message 2'); // Reset console log - global.console.log = originalConsoleLog; + GLOBAL_OBJ.console.log = originalConsoleLog; }); it('should not wrap any levels that are not members of console', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'someNonExistingLevel', 'error'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); // The provided level should not be created - expect((global.console as any)['someNonExistingLevel']).toBeUndefined(); - - // Ohter levels should be wrapped as expected - expect(global.console.log).not.toBe(originalConsole.log); - expect(global.console.error).not.toBe(originalConsole.error); + expect((GLOBAL_OBJ.console as any)['someNonExistingLevel']).toBeUndefined(); }); it('should wrap the console when the client does not have a registered captureconsole integration, but not capture any messages', () => { const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'error'] }); + const mockHub = getMockHub(null as any); // simulate not having the integration registered captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(null as any), // simulate not having the integration registered + () => mockHub, ); - // Console should be wrapped - expect(global.console.log).not.toBe(originalConsole.log); - expect(global.console.error).not.toBe(originalConsole.error); - // Should not capture messages - global.console.log('some message'); + GLOBAL_OBJ.console.log('some message'); expect(mockHub.captureMessage).not.toHaveBeenCalledWith(); }); it("should not crash when the original console methods don't exist at time of invocation", () => { - const originalConsoleLog = global.console.log; - global.console.log = undefined as any; // don't `delete` here, otherwise `fill` won't wrap the function + originalConsoleMethods.log = undefined; const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] }); + const mockHub = getMockHub(captureConsoleIntegration); captureConsoleIntegration.setupOnce( () => undefined, - () => getMockHubWithIntegration(captureConsoleIntegration), + () => mockHub, ); expect(() => { - global.console.log('some message'); + GLOBAL_OBJ.console.log('some message'); }).not.toThrow(); - - global.console.log = originalConsoleLog; }); }); diff --git a/packages/node/src/integrations/console.ts b/packages/node/src/integrations/console.ts index da0b684c4992..eb8a38980a64 100644 --- a/packages/node/src/integrations/console.ts +++ b/packages/node/src/integrations/console.ts @@ -1,6 +1,6 @@ import { getCurrentHub } from '@sentry/core'; import type { Integration } from '@sentry/types'; -import { fill, severityLevelFromString } from '@sentry/utils'; +import { addInstrumentationHandler, severityLevelFromString } from '@sentry/utils'; import * as util from 'util'; /** Console module integration */ @@ -19,37 +19,24 @@ export class Console implements Integration { * @inheritDoc */ public setupOnce(): void { - for (const level of ['debug', 'info', 'warn', 'error', 'log']) { - fill(console, level, createConsoleWrapper(level)); - } - } -} + addInstrumentationHandler('console', ({ args, level }: { args: unknown[]; level: string }) => { + const hub = getCurrentHub(); -/** - * Wrapper function that'll be used for every console level - */ -function createConsoleWrapper(level: string): (originalConsoleMethod: () => void) => void { - return function consoleWrapper(originalConsoleMethod: () => void): () => void { - const sentryLevel = severityLevelFromString(level); - - /* eslint-disable prefer-rest-params */ - return function (this: typeof console): void { - if (getCurrentHub().getIntegration(Console)) { - getCurrentHub().addBreadcrumb( - { - category: 'console', - level: sentryLevel, - message: util.format.apply(undefined, arguments), - }, - { - input: [...arguments], - level, - }, - ); + if (!hub.getIntegration(Console)) { + return; } - originalConsoleMethod.apply(this, arguments); - }; - /* eslint-enable prefer-rest-params */ - }; + hub.addBreadcrumb( + { + category: 'console', + level: severityLevelFromString(level), + message: util.format.apply(undefined, args), + }, + { + input: [...args], + level, + }, + ); + }); + } } diff --git a/packages/utils/src/instrument.ts b/packages/utils/src/instrument.ts index be0f8f49cedc..94812f47b252 100644 --- a/packages/utils/src/instrument.ts +++ b/packages/utils/src/instrument.ts @@ -10,11 +10,12 @@ import type { } from '@sentry/types'; import { isString } from './is'; +import type { ConsoleLevel } from './logger'; import { CONSOLE_LEVELS, logger } from './logger'; import { fill } from './object'; import { getFunctionName } from './stacktrace'; import { supportsHistory, supportsNativeFetch } from './supports'; -import { getGlobalObject } from './worldwide'; +import { getGlobalObject, GLOBAL_OBJ } from './worldwide'; // eslint-disable-next-line deprecation/deprecation const WINDOW = getGlobalObject(); @@ -112,25 +113,30 @@ function triggerHandlers(type: InstrumentHandlerType, data: any): void { } } +/** Only exported for testing & debugging. */ +export const originalConsoleMethods: { + [key in ConsoleLevel]?: (...args: any[]) => void; +} = {}; + /** JSDoc */ function instrumentConsole(): void { - if (!('console' in WINDOW)) { + if (!('console' in GLOBAL_OBJ)) { return; } - CONSOLE_LEVELS.forEach(function (level: string): void { - if (!(level in WINDOW.console)) { + CONSOLE_LEVELS.forEach(function (level: ConsoleLevel): void { + if (!(level in GLOBAL_OBJ.console)) { return; } - fill(WINDOW.console, level, function (originalConsoleMethod: () => any): Function { + fill(GLOBAL_OBJ.console, level, function (originalConsoleMethod: () => any): Function { + originalConsoleMethods[level] = originalConsoleMethod; + return function (...args: any[]): void { triggerHandlers('console', { args, level }); - // this fails for some browsers. :( - if (originalConsoleMethod) { - originalConsoleMethod.apply(WINDOW.console, args); - } + const log = originalConsoleMethods[level]; + log && log.apply(GLOBAL_OBJ.console, args); }; }); }); @@ -142,7 +148,7 @@ function instrumentFetch(): void { return; } - fill(WINDOW, 'fetch', function (originalFetch: () => void): () => void { + fill(GLOBAL_OBJ, 'fetch', function (originalFetch: () => void): () => void { return function (...args: any[]): void { const { method, url } = parseFetchArgs(args); @@ -160,7 +166,7 @@ function instrumentFetch(): void { }); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - return originalFetch.apply(WINDOW, args).then( + return originalFetch.apply(GLOBAL_OBJ, args).then( (response: Response) => { triggerHandlers('fetch', { ...handlerData, From e3dda4ce6435f55e364da85016e55c162f6885a9 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 29 Aug 2023 10:28:17 +0200 Subject: [PATCH 3/7] fix(sveltekit): Ensure target file exists before applying auto instrumentation (#8881) In our auto instrumentation Vite plugin for SvelteKit, we read `+(page|layout)(.server).(js|ts)` files' code to determine if we should add our wrapper to the file or not. We previously didn't check for a file id's existence before reading the file if the id matched that certain pattern, wrongly assuming that these ids would always map to actually existing files. It seems like Vite plugins such as Houdini's plugin add file ids to the build for files that actually don't exist (#8846, #8854) . When our plugin's `load` hook was called for such an id, it then tried to access and read the file which caused a build error. This patch now adds a file existence guard to ensure we simply no-op for these files. --- packages/sveltekit/src/vite/autoInstrument.ts | 18 +++++++++++++++--- .../sveltekit/test/vite/autoInstrument.test.ts | 17 ++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/packages/sveltekit/src/vite/autoInstrument.ts b/packages/sveltekit/src/vite/autoInstrument.ts index cabfc743db0c..07e8b7646124 100644 --- a/packages/sveltekit/src/vite/autoInstrument.ts +++ b/packages/sveltekit/src/vite/autoInstrument.ts @@ -40,7 +40,7 @@ type AutoInstrumentPluginOptions = AutoInstrumentSelection & { * @returns the plugin */ export function makeAutoInstrumentationPlugin(options: AutoInstrumentPluginOptions): Plugin { - const { load: shouldWrapLoad, serverLoad: shouldWrapServerLoad, debug } = options; + const { load: wrapLoadEnabled, serverLoad: wrapServerLoadEnabled, debug } = options; return { name: 'sentry-auto-instrumentation', @@ -49,7 +49,7 @@ export function makeAutoInstrumentationPlugin(options: AutoInstrumentPluginOptio async load(id) { const applyUniversalLoadWrapper = - shouldWrapLoad && + wrapLoadEnabled && /^\+(page|layout)\.(js|ts|mjs|mts)$/.test(path.basename(id)) && (await canWrapLoad(id, debug)); @@ -60,7 +60,7 @@ export function makeAutoInstrumentationPlugin(options: AutoInstrumentPluginOptio } const applyServerLoadWrapper = - shouldWrapServerLoad && + wrapServerLoadEnabled && /^\+(page|layout)\.server\.(js|ts|mjs|mts)$/.test(path.basename(id)) && (await canWrapLoad(id, debug)); @@ -90,7 +90,19 @@ export function makeAutoInstrumentationPlugin(options: AutoInstrumentPluginOptio * @returns `true` if we can wrap the given file, `false` otherwise */ export async function canWrapLoad(id: string, debug: boolean): Promise { + // Some 3rd party plugins add ids to the build that actually don't exist. + // We need to check for that here, otherwise users get get a build errors. + if (!fs.existsSync(id)) { + debug && + // eslint-disable-next-line no-console + console.log( + `Skipping wrapping ${id} because it doesn't exist. A 3rd party plugin might have added this as a virtual file to the build`, + ); + return false; + } + const code = (await fs.promises.readFile(id, 'utf8')).toString(); + const mod = parseModule(code); const program = mod.$ast.type === 'Program' && mod.$ast; diff --git a/packages/sveltekit/test/vite/autoInstrument.test.ts b/packages/sveltekit/test/vite/autoInstrument.test.ts index 954138f017bf..13ee56eef3c6 100644 --- a/packages/sveltekit/test/vite/autoInstrument.test.ts +++ b/packages/sveltekit/test/vite/autoInstrument.test.ts @@ -21,6 +21,12 @@ vi.mock('fs', async () => { return fileContent || DEFAULT_CONTENT; }), }, + existsSync: vi.fn().mockImplementation(id => { + if (id === '+page.virtual.ts') { + return false; + } + return true; + }), }; }); @@ -198,15 +204,20 @@ describe('canWrapLoad', () => { 'export const loadNotLoad = () => {}; export const prerender = true;', 'export function aload(){}; export const prerender = true;', 'export function loader(){}; export const prerender = true;', - 'let loademe = false; export {loadme}', + 'let loadme = false; export {loadme}', 'const a = {load: true}; export {a}', 'if (s === "load") {}', 'const a = load ? load : false', '// const load = () => {}', '/* export const load = () => {} */ export const prerender = true;', '/* export const notLoad = () => { const a = getSomething() as load; } */ export const prerender = true;', - ])('returns `false` if no load declaration exists', async (_, code) => { + ])('returns `false` if no load declaration exists', async code => { fileContent = code; - expect(await canWrapLoad('+page.ts', false)).toEqual(true); + expect(await canWrapLoad('+page.ts', false)).toEqual(false); + }); + + it("returns `false` if the passed file id doesn't exist", async () => { + fileContent = DEFAULT_CONTENT; + expect(await canWrapLoad('+page.virtual.ts', false)).toEqual(false); }); }); From e72c04712c2156cb2c614906afbf819d941de9c7 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 29 Aug 2023 15:12:30 +0200 Subject: [PATCH 4/7] ref(browser): Refactor sentry breadcrumb to use hook (#8892) Noticed that this is a bit tightly coupled in the browser client, and could be simplified by using a hook. --- packages/browser/src/client.ts | 22 ---------- .../browser/src/integrations/breadcrumbs.ts | 40 +++++++++---------- packages/core/src/baseclient.ts | 8 ++++ packages/types/src/client.ts | 11 +++++ 4 files changed, 39 insertions(+), 42 deletions(-) diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index fba5dfc008e6..60579038a50a 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -15,8 +15,6 @@ import { createClientReportEnvelope, dsnToString, getSDKSource, logger } from '@ import { eventFromException, eventFromMessage } from './eventbuilder'; import { WINDOW } from './helpers'; -import type { Breadcrumbs } from './integrations'; -import { BREADCRUMB_INTEGRATION_ID } from './integrations/breadcrumbs'; import type { BrowserTransportOptions } from './transports/types'; import { createUserFeedbackEnvelope } from './userfeedback'; @@ -91,26 +89,6 @@ export class BrowserClient extends BaseClient { return eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace); } - /** - * @inheritDoc - */ - public sendEvent(event: Event, hint?: EventHint): void { - // We only want to add the sentry event breadcrumb when the user has the breadcrumb integration installed and - // activated its `sentry` option. - // We also do not want to use the `Breadcrumbs` class here directly, because we do not want it to be included in - // bundles, if it is not used by the SDK. - // This all sadly is a bit ugly, but we currently don't have a "pre-send" hook on the integrations so we do it this - // way for now. - const breadcrumbIntegration = this.getIntegrationById(BREADCRUMB_INTEGRATION_ID) as Breadcrumbs | undefined; - // We check for definedness of `addSentryBreadcrumb` in case users provided their own integration with id - // "Breadcrumbs" that does not have this function. - if (breadcrumbIntegration && breadcrumbIntegration.addSentryBreadcrumb) { - breadcrumbIntegration.addSentryBreadcrumb(event); - } - - super.sendEvent(event, hint); - } - /** * Sends user feedback to Sentry. */ diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index a7330d1fb23e..e41bedc8bf1c 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -41,8 +41,6 @@ interface BreadcrumbsOptions { /** maxStringLength gets capped to prevent 100 breadcrumbs exceeding 1MB event payload size */ const MAX_ALLOWED_STRING_LENGTH = 1024; -export const BREADCRUMB_INTEGRATION_ID = 'Breadcrumbs'; - /** * Default Breadcrumbs instrumentations * TODO: Deprecated - with v6, this will be renamed to `Instrument` @@ -51,7 +49,7 @@ export class Breadcrumbs implements Integration { /** * @inheritDoc */ - public static id: string = BREADCRUMB_INTEGRATION_ID; + public static id: string = 'Breadcrumbs'; /** * @inheritDoc @@ -104,28 +102,30 @@ export class Breadcrumbs implements Integration { if (this.options.history) { addInstrumentationHandler('history', _historyBreadcrumb); } - } - - /** - * Adds a breadcrumb for Sentry events or transactions if this option is enabled. - */ - public addSentryBreadcrumb(event: SentryEvent): void { if (this.options.sentry) { - getCurrentHub().addBreadcrumb( - { - category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`, - event_id: event.event_id, - level: event.level, - message: getEventDescription(event), - }, - { - event, - }, - ); + const client = getCurrentHub().getClient(); + client && client.on && client.on('beforeSendEvent', addSentryBreadcrumb); } } } +/** + * Adds a breadcrumb for Sentry events or transactions if this option is enabled. + */ +function addSentryBreadcrumb(event: SentryEvent): void { + getCurrentHub().addBreadcrumb( + { + category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`, + event_id: event.event_id, + level: event.level, + message: getEventDescription(event), + }, + { + event, + }, + ); +} + /** * A HOC that creaes a function that creates breadcrumbs from DOM API calls. * This is a HOC so that we get access to dom options in the closure. diff --git a/packages/core/src/baseclient.ts b/packages/core/src/baseclient.ts index 354417351d1b..cb106b958a53 100644 --- a/packages/core/src/baseclient.ts +++ b/packages/core/src/baseclient.ts @@ -322,6 +322,8 @@ export abstract class BaseClient implements Client { * @inheritDoc */ public sendEvent(event: Event, hint: EventHint = {}): void { + this.emit('beforeSendEvent', event, hint); + if (this._dsn) { let env = createEventEnvelope(event, this._dsn, this._options._metadata, this._options.tunnel); @@ -381,6 +383,9 @@ export abstract class BaseClient implements Client { /** @inheritdoc */ public on(hook: 'beforeEnvelope', callback: (envelope: Envelope) => void): void; + /** @inheritdoc */ + public on(hook: 'beforeSendEvent', callback: (event: Event, hint?: EventHint) => void): void; + /** @inheritdoc */ public on( hook: 'afterSendEvent', @@ -412,6 +417,9 @@ export abstract class BaseClient implements Client { /** @inheritdoc */ public emit(hook: 'beforeEnvelope', envelope: Envelope): void; + /** @inheritdoc */ + public emit(hook: 'beforeSendEvent', event: Event, hint?: EventHint): void; + /** @inheritdoc */ public emit(hook: 'afterSendEvent', event: Event, sendResponse: TransportMakeRequestResponse | void): void; diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index 3b9c5835f8b8..65da5947ce69 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -176,6 +176,11 @@ export interface Client { */ on?(hook: 'beforeEnvelope', callback: (envelope: Envelope) => void): void; + /** + * Register a callback for before an event is sent. + */ + on?(hook: 'beforeSendEvent', callback: (event: Event, hint?: EventHint | void) => void): void; + /** * Register a callback for when an event has been sent. */ @@ -212,6 +217,12 @@ export interface Client { */ emit?(hook: 'beforeEnvelope', envelope: Envelope): void; + /* + * Fire a hook event before sending an event. Expects to be given an Event & EventHint as the + * second/third argument. + */ + emit?(hook: 'beforeSendEvent', event: Event, hint?: EventHint): void; + /* * Fire a hook event after sending an event. Expects to be given an Event as the * second argument. From 0fd86bc64e96c52cf5c594d331cd2e286440e74c Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 29 Aug 2023 15:33:21 +0200 Subject: [PATCH 5/7] ref(tracing): Add `origin` to spans (#8765) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds an `origin` to all spans, which defaults to `manual` but is set to something more meaningful for all our auto instrumentation. I tried to come up with reasonable origin names, I hope it makes sense everywhere 😅 Also note that this now uses a new TS feature which seems to be correctly transpiled to TS 3.8, as far as I can tell! 🎉 Closes https://github.com/getsentry/sentry-javascript/issues/8510 --------- Co-authored-by: Luca Forstner Co-authored-by: Lukas Stracke --- packages/angular/src/tracing.ts | 6 +++ packages/angular/test/tracing.test.ts | 8 ++++ .../browser/src/profiling/hubextensions.ts | 6 ++- packages/core/src/tracing/span.ts | 46 +++++++------------ packages/ember/addon/index.ts | 9 +++- .../sentry-performance.ts | 6 +++ packages/nextjs/src/client/performance.ts | 1 + .../src/common/utils/edgeWrapperUtils.ts | 2 + .../nextjs/src/common/utils/wrapperUtils.ts | 4 ++ .../src/common/wrapApiHandlerWithSentry.ts | 1 + .../common/wrapServerComponentWithSentry.ts | 1 + .../nextjs/test/config/withSentry.test.ts | 1 + .../src/integrations/express.ts | 11 ++++- .../src/integrations/fastify.ts | 11 ++++- .../src/integrations/graphql.ts | 6 +++ .../src/integrations/http.ts | 1 + .../src/integrations/mongo.ts | 11 ++++- .../src/integrations/mongoose.ts | 11 ++++- .../src/integrations/mysql.ts | 1 + .../src/integrations/mysql2.ts | 11 ++++- .../src/integrations/nest.ts | 1 + .../src/integrations/postgres.ts | 11 ++++- .../src/integrations/prisma.ts | 1 + packages/node/src/handlers.ts | 1 + packages/node/src/integrations/http.ts | 1 + .../node/src/integrations/undici/index.ts | 1 + .../opentelemetry-node/src/spanprocessor.ts | 12 ++++- .../opentelemetry-node/src/utils/spanData.ts | 7 +-- packages/react/src/profiler.tsx | 5 ++ packages/react/src/reactrouter.tsx | 2 + packages/react/src/reactrouterv3.ts | 2 + packages/react/src/reactrouterv6.tsx | 2 + packages/react/test/profiler.test.tsx | 6 +++ packages/react/test/reactrouterv3.test.tsx | 8 ++++ packages/react/test/reactrouterv4.test.tsx | 9 ++++ packages/react/test/reactrouterv5.test.tsx | 9 ++++ packages/react/test/reactrouterv6.4.test.tsx | 6 +++ packages/react/test/reactrouterv6.test.tsx | 14 ++++++ packages/remix/src/client/performance.tsx | 2 + packages/remix/src/utils/instrumentServer.ts | 3 ++ packages/serverless/src/awslambda.ts | 1 + packages/serverless/src/awsservices.ts | 1 + .../src/gcpfunction/cloud_events.ts | 1 + packages/serverless/src/gcpfunction/events.ts | 1 + packages/serverless/src/gcpfunction/http.ts | 1 + packages/serverless/src/google-cloud-grpc.ts | 1 + packages/serverless/src/google-cloud-http.ts | 1 + packages/serverless/test/awslambda.test.ts | 8 ++++ packages/serverless/test/awsservices.test.ts | 3 ++ packages/serverless/test/gcpfunction.test.ts | 15 ++++++ .../serverless/test/google-cloud-grpc.test.ts | 1 + .../serverless/test/google-cloud-http.test.ts | 2 + packages/svelte/src/performance.ts | 2 + packages/svelte/test/performance.test.ts | 8 ++++ packages/sveltekit/src/client/load.ts | 1 + packages/sveltekit/src/client/router.ts | 3 ++ packages/sveltekit/src/server/handle.ts | 1 + packages/sveltekit/src/server/load.ts | 2 + packages/sveltekit/test/client/load.test.ts | 2 + packages/sveltekit/test/client/router.test.ts | 5 ++ packages/sveltekit/test/server/load.test.ts | 6 +++ .../src/browser/metrics/index.ts | 8 ++++ .../tracing-internal/src/browser/request.ts | 2 + .../tracing-internal/src/browser/router.ts | 2 + .../src/node/integrations/apollo.ts | 1 + .../src/node/integrations/express.ts | 3 ++ .../src/node/integrations/graphql.ts | 1 + .../src/node/integrations/mongo.ts | 1 + .../src/node/integrations/mysql.ts | 1 + .../src/node/integrations/postgres.ts | 1 + .../src/node/integrations/prisma.ts | 1 + .../test/browser/metrics/index.test.ts | 2 + .../test/browser/router.test.ts | 3 ++ .../test/integrations/apollo-nestjs.test.ts | 2 + .../tracing/test/integrations/apollo.test.ts | 2 + .../tracing/test/integrations/graphql.test.ts | 1 + .../test/integrations/node/mongo.test.ts | 3 ++ .../test/integrations/node/postgres.test.ts | 3 ++ .../test/integrations/node/prisma.test.ts | 1 + packages/tracing/test/span.test.ts | 1 + packages/types/src/index.ts | 2 +- packages/types/src/span.ts | 15 ++++++ packages/vue/src/router.ts | 2 + packages/vue/src/tracing.ts | 2 + packages/vue/test/router.test.ts | 6 +++ 85 files changed, 346 insertions(+), 43 deletions(-) diff --git a/packages/angular/src/tracing.ts b/packages/angular/src/tracing.ts index 5378208a3404..852442af66eb 100644 --- a/packages/angular/src/tracing.ts +++ b/packages/angular/src/tracing.ts @@ -39,6 +39,7 @@ export function routingInstrumentation( customStartTransaction({ name: WINDOW.location.pathname, op: 'pageload', + origin: 'auto.pageload.angular', metadata: { source: 'url' }, }); } @@ -84,6 +85,7 @@ export class TraceService implements OnDestroy { activeTransaction = stashedStartTransaction({ name: strippedUrl, op: 'navigation', + origin: 'auto.navigation.angular', metadata: { source: 'url' }, }); } @@ -95,6 +97,7 @@ export class TraceService implements OnDestroy { this._routingSpan = activeTransaction.startChild({ description: `${navigationEvent.url}`, op: ANGULAR_ROUTING_OP, + origin: 'auto.ui.angular', tags: { 'routing.instrumentation': '@sentry/angular', url: strippedUrl, @@ -192,6 +195,7 @@ export class TraceDirective implements OnInit, AfterViewInit { this._tracingSpan = activeTransaction.startChild({ description: `<${this.componentName}>`, op: ANGULAR_INIT_OP, + origin: 'auto.ui.angular.trace_directive', }); } } @@ -233,6 +237,7 @@ export function TraceClassDecorator(): ClassDecorator { tracingSpan = activeTransaction.startChild({ description: `<${target.name}>`, op: ANGULAR_INIT_OP, + origin: 'auto.ui.angular.trace_class_decorator', }); } if (originalOnInit) { @@ -270,6 +275,7 @@ export function TraceMethodDecorator(): MethodDecorator { description: `<${target.constructor.name}>`, endTimestamp: now, op: `${ANGULAR_OP}.${String(propertyKey)}`, + origin: 'auto.ui.angular.trace_method_decorator', startTimestamp: now, }); } diff --git a/packages/angular/test/tracing.test.ts b/packages/angular/test/tracing.test.ts index a3375518466a..e1796f617150 100644 --- a/packages/angular/test/tracing.test.ts +++ b/packages/angular/test/tracing.test.ts @@ -48,6 +48,7 @@ describe('Angular Tracing', () => { expect(startTransaction).toHaveBeenCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.angular', metadata: { source: 'url' }, }); }); @@ -137,6 +138,7 @@ describe('Angular Tracing', () => { expect(customStartTransaction).toHaveBeenCalledWith({ name: url, op: 'pageload', + origin: 'auto.pageload.angular', metadata: { source: 'url' }, }); @@ -327,6 +329,7 @@ describe('Angular Tracing', () => { expect(customStartTransaction).toHaveBeenCalledWith({ name: url, op: 'navigation', + origin: 'auto.navigation.angular', metadata: { source: 'url' }, }); expect(transaction.setName).toHaveBeenCalledWith(result, 'route'); @@ -358,6 +361,7 @@ describe('Angular Tracing', () => { expect(transaction.startChild).toHaveBeenCalledWith({ op: 'ui.angular.init', + origin: 'auto.ui.angular.trace_directive', description: '', }); @@ -384,6 +388,7 @@ describe('Angular Tracing', () => { expect(transaction.startChild).toHaveBeenCalledWith({ op: 'ui.angular.init', + origin: 'auto.ui.angular.trace_directive', description: '', }); @@ -458,6 +463,7 @@ describe('Angular Tracing', () => { expect(transaction.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.angular.init', + origin: 'auto.ui.angular.trace_class_decorator', }); expect(origNgOnInitMock).toHaveBeenCalledTimes(1); @@ -511,6 +517,7 @@ describe('Angular Tracing', () => { expect(transaction.startChild.mock.calls[0][0]).toEqual({ description: '', op: 'ui.angular.ngOnInit', + origin: 'auto.ui.angular.trace_method_decorator', startTimestamp: expect.any(Number), endTimestamp: expect.any(Number), }); @@ -518,6 +525,7 @@ describe('Angular Tracing', () => { expect(transaction.startChild.mock.calls[1][0]).toEqual({ description: '', op: 'ui.angular.ngAfterViewInit', + origin: 'auto.ui.angular.trace_method_decorator', startTimestamp: expect.any(Number), endTimestamp: expect.any(Number), }); diff --git a/packages/browser/src/profiling/hubextensions.ts b/packages/browser/src/profiling/hubextensions.ts index 49763ac35659..187e4a463224 100644 --- a/packages/browser/src/profiling/hubextensions.ts +++ b/packages/browser/src/profiling/hubextensions.ts @@ -174,7 +174,11 @@ export function wrapTransactionWithProfiling(transaction: Transaction): Transact // This is temporary - we will use the collected span data to evaluate // if deferring txn.finish until profiler resolves is a viable approach. - const stopProfilerSpan = transaction.startChild({ description: 'profiler.stop', op: 'profiler' }); + const stopProfilerSpan = transaction.startChild({ + description: 'profiler.stop', + op: 'profiler', + origin: 'auto.profiler.browser', + }); return profiler .stop() diff --git a/packages/core/src/tracing/span.ts b/packages/core/src/tracing/span.ts index 4301391ff1da..3ce158c8addf 100644 --- a/packages/core/src/tracing/span.ts +++ b/packages/core/src/tracing/span.ts @@ -4,6 +4,7 @@ import type { Primitive, Span as SpanInterface, SpanContext, + SpanOrigin, TraceContext, Transaction, } from '@sentry/types'; @@ -115,6 +116,11 @@ export class Span implements SpanInterface { */ public instrumenter: Instrumenter; + /** + * The origin of the span, giving context about what created the span. + */ + public origin?: SpanOrigin; + /** * You should never call the constructor manually, always use `Sentry.startTransaction()` * or call `startChild()` on an existing span. @@ -122,23 +128,15 @@ export class Span implements SpanInterface { * @hideconstructor * @hidden */ - public constructor(spanContext?: SpanContext) { - this.traceId = uuid4(); - this.spanId = uuid4().substring(16); - this.startTimestamp = timestampInSeconds(); - this.tags = {}; - this.data = {}; - this.instrumenter = 'sentry'; - - if (!spanContext) { - return this; - } - if (spanContext.traceId) { - this.traceId = spanContext.traceId; - } - if (spanContext.spanId) { - this.spanId = spanContext.spanId; - } + public constructor(spanContext: SpanContext = {}) { + this.traceId = spanContext.traceId || uuid4(); + this.spanId = spanContext.spanId || uuid4().substring(16); + this.startTimestamp = spanContext.startTimestamp || timestampInSeconds(); + this.tags = spanContext.tags || {}; + this.data = spanContext.data || {}; + this.instrumenter = spanContext.instrumenter || 'sentry'; + this.origin = spanContext.origin || 'manual'; + if (spanContext.parentSpanId) { this.parentSpanId = spanContext.parentSpanId; } @@ -155,24 +153,12 @@ export class Span implements SpanInterface { if (spanContext.name) { this.description = spanContext.name; } - if (spanContext.data) { - this.data = spanContext.data; - } - if (spanContext.tags) { - this.tags = spanContext.tags; - } if (spanContext.status) { this.status = spanContext.status; } - if (spanContext.startTimestamp) { - this.startTimestamp = spanContext.startTimestamp; - } if (spanContext.endTimestamp) { this.endTimestamp = spanContext.endTimestamp; } - if (spanContext.instrumenter) { - this.instrumenter = spanContext.instrumenter; - } } /** @@ -355,6 +341,7 @@ export class Span implements SpanInterface { tags?: { [key: string]: Primitive }; timestamp?: number; trace_id: string; + origin?: SpanOrigin; } { return dropUndefinedKeys({ data: Object.keys(this.data).length > 0 ? this.data : undefined, @@ -367,6 +354,7 @@ export class Span implements SpanInterface { tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, timestamp: this.endTimestamp, trace_id: this.traceId, + origin: this.origin, }); } } diff --git a/packages/ember/addon/index.ts b/packages/ember/addon/index.ts index fbcea14d5533..ef38d3c382b3 100644 --- a/packages/ember/addon/index.ts +++ b/packages/ember/addon/index.ts @@ -87,7 +87,14 @@ export const instrumentRoutePerformance = (BaseRoute if (!currentTransaction) { return result; } - currentTransaction.startChild({ op, description, startTimestamp }).finish(); + currentTransaction + .startChild({ + op, + description, + origin: 'auto.ui.ember', + startTimestamp, + }) + .finish(); return result; }; diff --git a/packages/ember/addon/instance-initializers/sentry-performance.ts b/packages/ember/addon/instance-initializers/sentry-performance.ts index 2b962f4df2ae..0f00a6cec1fd 100644 --- a/packages/ember/addon/instance-initializers/sentry-performance.ts +++ b/packages/ember/addon/instance-initializers/sentry-performance.ts @@ -119,6 +119,7 @@ export function _instrumentEmberRouter( activeTransaction = startTransaction({ name: `route:${routeInfo.name}`, op: 'pageload', + origin: 'auto.pageload.ember', tags: { url, toRoute: routeInfo.name, @@ -141,6 +142,7 @@ export function _instrumentEmberRouter( activeTransaction = startTransaction({ name: `route:${toRoute}`, op: 'navigation', + origin: 'auto.navigation.ember', tags: { fromRoute, toRoute, @@ -150,6 +152,7 @@ export function _instrumentEmberRouter( transitionSpan = activeTransaction?.startChild({ op: 'ui.ember.transition', description: `route:${fromRoute} -> route:${toRoute}`, + origin: 'auto.ui.ember', }); }); @@ -211,6 +214,7 @@ function _instrumentEmberRunloop(config: EmberSentryConfig): void { activeTransaction ?.startChild({ op: `ui.ember.runloop.${queue}`, + origin: 'auto.ui.ember', startTimestamp: currentQueueStart, endTimestamp: now, }) @@ -287,6 +291,7 @@ function processComponentRenderAfter( activeTransaction?.startChild({ op, description: payload.containerKey || payload.object, + origin: 'auto.ui.ember', startTimestamp: begin.now, endTimestamp: now, }); @@ -370,6 +375,7 @@ function _instrumentInitialLoad(config: EmberSentryConfig): void { const transaction = getActiveTransaction(); const span = transaction?.startChild({ op: 'ui.ember.init', + origin: 'auto.ui.ember', startTimestamp, }); span?.finish(endTimestamp); diff --git a/packages/nextjs/src/client/performance.ts b/packages/nextjs/src/client/performance.ts index fd5f979a08b0..bdf1509d9ec1 100644 --- a/packages/nextjs/src/client/performance.ts +++ b/packages/nextjs/src/client/performance.ts @@ -178,6 +178,7 @@ export function nextRouterInstrumentation( const nextRouteChangeSpan = navigationTransaction.startChild({ op: 'ui.nextjs.route-change', description: 'Next.js Route Change', + origin: 'auto.navigation.nextjs', }); const finishRouteChangeSpan = (): void => { diff --git a/packages/nextjs/src/common/utils/edgeWrapperUtils.ts b/packages/nextjs/src/common/utils/edgeWrapperUtils.ts index f3023665d106..94ff5ad5bec4 100644 --- a/packages/nextjs/src/common/utils/edgeWrapperUtils.ts +++ b/packages/nextjs/src/common/utils/edgeWrapperUtils.ts @@ -23,6 +23,7 @@ export function withEdgeWrapping( span = prevSpan.startChild({ description: options.spanDescription, op: options.spanOp, + origin: 'auto.function.nextjs', }); } else if (req instanceof Request) { const sentryTrace = req.headers.get('sentry-trace') || ''; @@ -39,6 +40,7 @@ export function withEdgeWrapping( span = startTransaction({ name: options.spanDescription, op: options.spanOp, + origin: 'auto.ui.nextjs.withEdgeWrapping', ...traceparentData, metadata: { dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext, diff --git a/packages/nextjs/src/common/utils/wrapperUtils.ts b/packages/nextjs/src/common/utils/wrapperUtils.ts index a3cf13736900..80c9a57b65b5 100644 --- a/packages/nextjs/src/common/utils/wrapperUtils.ts +++ b/packages/nextjs/src/common/utils/wrapperUtils.ts @@ -104,6 +104,7 @@ export function withTracedServerSideDataFetcher Pr { op: 'http.server', name: options.requestedRouteName, + origin: 'auto.function.nextjs', ...traceparentData, status: 'ok', metadata: { @@ -131,12 +132,14 @@ export function withTracedServerSideDataFetcher Pr dataFetcherSpan = spanToContinue.startChild({ op: 'function.nextjs', description: `${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`, + origin: 'auto.function.nextjs', status: 'ok', }); } else { dataFetcherSpan = startTransaction({ op: 'function.nextjs', name: `${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`, + origin: 'auto.function.nextjs', ...traceparentData, status: 'ok', metadata: { @@ -203,6 +206,7 @@ export async function callDataFetcherTraced Promis // route's transaction const span = transaction.startChild({ op: 'function.nextjs', + origin: 'auto.function.nextjs', description: `${dataFetchingMethodName} (${parameterizedRoute})`, status: 'ok', }); diff --git a/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts index 85ec0cb4b1c2..62ecd952b460 100644 --- a/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/common/wrapApiHandlerWithSentry.ts @@ -129,6 +129,7 @@ export function withSentry(apiHandler: NextApiHandler, parameterizedRoute?: stri { name: `${reqMethod}${reqPath}`, op: 'http.server', + origin: 'auto.http.nextjs', ...traceparentData, metadata: { dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext, diff --git a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts index 81f030fa824c..c5db1c7f217f 100644 --- a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts +++ b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts @@ -43,6 +43,7 @@ export function wrapServerComponentWithSentry any> op: 'function.nextjs', name: `${componentType} Server Component (${componentRoute})`, status: 'ok', + origin: 'auto.function.nextjs', ...traceparentData, metadata: { source: 'component', diff --git a/packages/nextjs/test/config/withSentry.test.ts b/packages/nextjs/test/config/withSentry.test.ts index c7862e1473df..ba7c5fb3e865 100644 --- a/packages/nextjs/test/config/withSentry.test.ts +++ b/packages/nextjs/test/config/withSentry.test.ts @@ -80,6 +80,7 @@ describe('withSentry', () => { { name: 'GET http://dogs.are.great', op: 'http.server', + origin: 'auto.http.nextjs', metadata: { source: 'route', diff --git a/packages/node-experimental/src/integrations/express.ts b/packages/node-experimental/src/integrations/express.ts index 84e3f698a179..8a97431b0b0a 100644 --- a/packages/node-experimental/src/integrations/express.ts +++ b/packages/node-experimental/src/integrations/express.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -27,6 +28,14 @@ export class Express extends NodePerformanceIntegration implements Integra /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { - return [new ExpressInstrumentation()]; + return [ + new ExpressInstrumentation({ + requestHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.http.otel-express', + }); + }, + }), + ]; } } diff --git a/packages/node-experimental/src/integrations/fastify.ts b/packages/node-experimental/src/integrations/fastify.ts index 31ed6e3067bd..bff0f058c5d1 100644 --- a/packages/node-experimental/src/integrations/fastify.ts +++ b/packages/node-experimental/src/integrations/fastify.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { FastifyInstrumentation } from '@opentelemetry/instrumentation-fastify'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -27,6 +28,14 @@ export class Fastify extends NodePerformanceIntegration implements Integra /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { - return [new FastifyInstrumentation()]; + return [ + new FastifyInstrumentation({ + requestHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.http.otel-fastify', + }); + }, + }), + ]; } } diff --git a/packages/node-experimental/src/integrations/graphql.ts b/packages/node-experimental/src/integrations/graphql.ts index 409e2b2d3cff..1515f69b6516 100644 --- a/packages/node-experimental/src/integrations/graphql.ts +++ b/packages/node-experimental/src/integrations/graphql.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -30,6 +31,11 @@ export class GraphQL extends NodePerformanceIntegration implements Integra return [ new GraphQLInstrumentation({ ignoreTrivialResolveSpans: true, + responseHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.graphql.otel-graphql', + }); + }, }), ]; } diff --git a/packages/node-experimental/src/integrations/http.ts b/packages/node-experimental/src/integrations/http.ts index b0f9555a60be..e8f5300f6f73 100644 --- a/packages/node-experimental/src/integrations/http.ts +++ b/packages/node-experimental/src/integrations/http.ts @@ -153,6 +153,7 @@ export class Http implements Integration { }, contexts: {}, metadata: {}, + origin: 'auto.http.otel-http', }; if (span.kind === SpanKind.SERVER) { diff --git a/packages/node-experimental/src/integrations/mongo.ts b/packages/node-experimental/src/integrations/mongo.ts index 96375a6202e5..2b8752d770ad 100644 --- a/packages/node-experimental/src/integrations/mongo.ts +++ b/packages/node-experimental/src/integrations/mongo.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -27,6 +28,14 @@ export class Mongo extends NodePerformanceIntegration implements Integrati /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { - return [new MongoDBInstrumentation({})]; + return [ + new MongoDBInstrumentation({ + responseHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.db.otel-mongo', + }); + }, + }), + ]; } } diff --git a/packages/node-experimental/src/integrations/mongoose.ts b/packages/node-experimental/src/integrations/mongoose.ts index de08f600a3a7..42d863966ea3 100644 --- a/packages/node-experimental/src/integrations/mongoose.ts +++ b/packages/node-experimental/src/integrations/mongoose.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { MongooseInstrumentation } from '@opentelemetry/instrumentation-mongoose'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -27,6 +28,14 @@ export class Mongoose extends NodePerformanceIntegration implements Integr /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { - return [new MongooseInstrumentation({})]; + return [ + new MongooseInstrumentation({ + responseHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.db.otel-mongoose', + }); + }, + }), + ]; } } diff --git a/packages/node-experimental/src/integrations/mysql.ts b/packages/node-experimental/src/integrations/mysql.ts index 4308234b7410..3973f07f4685 100644 --- a/packages/node-experimental/src/integrations/mysql.ts +++ b/packages/node-experimental/src/integrations/mysql.ts @@ -27,6 +27,7 @@ export class Mysql extends NodePerformanceIntegration implements Integrati /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { + // Has no hook to adjust spans and add origin return [new MySQLInstrumentation({})]; } } diff --git a/packages/node-experimental/src/integrations/mysql2.ts b/packages/node-experimental/src/integrations/mysql2.ts index 278eeee4870f..f7d8f2c96fc9 100644 --- a/packages/node-experimental/src/integrations/mysql2.ts +++ b/packages/node-experimental/src/integrations/mysql2.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { MySQL2Instrumentation } from '@opentelemetry/instrumentation-mysql2'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -27,6 +28,14 @@ export class Mysql2 extends NodePerformanceIntegration implements Integrat /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { - return [new MySQL2Instrumentation({})]; + return [ + new MySQL2Instrumentation({ + responseHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.db.otel-mysql2', + }); + }, + }), + ]; } } diff --git a/packages/node-experimental/src/integrations/nest.ts b/packages/node-experimental/src/integrations/nest.ts index a358500b1fdd..b7e47b2f49c8 100644 --- a/packages/node-experimental/src/integrations/nest.ts +++ b/packages/node-experimental/src/integrations/nest.ts @@ -27,6 +27,7 @@ export class Nest extends NodePerformanceIntegration implements Integratio /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { + // Does not have a hook to adjust spans and add origin return [new NestInstrumentation({})]; } } diff --git a/packages/node-experimental/src/integrations/postgres.ts b/packages/node-experimental/src/integrations/postgres.ts index aacb679a906c..f6d1414a7fc0 100644 --- a/packages/node-experimental/src/integrations/postgres.ts +++ b/packages/node-experimental/src/integrations/postgres.ts @@ -1,5 +1,6 @@ import type { Instrumentation } from '@opentelemetry/instrumentation'; import { PgInstrumentation } from '@opentelemetry/instrumentation-pg'; +import { addOtelSpanData } from '@sentry/opentelemetry-node'; import type { Integration } from '@sentry/types'; import { NodePerformanceIntegration } from './NodePerformanceIntegration'; @@ -27,6 +28,14 @@ export class Postgres extends NodePerformanceIntegration implements Integr /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { - return [new PgInstrumentation({})]; + return [ + new PgInstrumentation({ + requestHook(span) { + addOtelSpanData(span.spanContext().spanId, { + origin: 'auto.db.otel-postgres', + }); + }, + }), + ]; } } diff --git a/packages/node-experimental/src/integrations/prisma.ts b/packages/node-experimental/src/integrations/prisma.ts index d29c44560e29..203e9d8ed6b1 100644 --- a/packages/node-experimental/src/integrations/prisma.ts +++ b/packages/node-experimental/src/integrations/prisma.ts @@ -31,6 +31,7 @@ export class Prisma extends NodePerformanceIntegration implements Integrat /** @inheritDoc */ public setupInstrumentation(): void | Instrumentation[] { + // does not have a hook to adjust spans & add origin return [new PrismaInstrumentation({})]; } } diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index 5d28be6d3c21..885fae1430d8 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -71,6 +71,7 @@ export function tracingHandler(): ( { name, op: 'http.server', + origin: 'auto.http.node.tracingHandler', ...traceparentData, metadata: { dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext, diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 1102c0301095..95b68e2c8eb3 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -251,6 +251,7 @@ function _createWrappedRequestMethodFactory( const requestSpan = shouldCreateSpan(rawRequestUrl) ? parentSpan?.startChild({ op: 'http.client', + origin: 'auto.http.node.http', description: `${data['http.method']} ${data.url}`, data, }) diff --git a/packages/node/src/integrations/undici/index.ts b/packages/node/src/integrations/undici/index.ts index 0c69dec37d3f..aeb614b3fddd 100644 --- a/packages/node/src/integrations/undici/index.ts +++ b/packages/node/src/integrations/undici/index.ts @@ -304,6 +304,7 @@ function createRequestSpan( } return activeSpan?.startChild({ op: 'http.client', + origin: 'auto.http.node.undici', description: `${method} ${getSanitizedUrlString(url)}`, data, }); diff --git a/packages/opentelemetry-node/src/spanprocessor.ts b/packages/opentelemetry-node/src/spanprocessor.ts index b2dc2beebf71..0e208b050357 100644 --- a/packages/opentelemetry-node/src/spanprocessor.ts +++ b/packages/opentelemetry-node/src/spanprocessor.ts @@ -225,7 +225,7 @@ function updateSpanWithOtelData(sentrySpan: SentrySpan, otelSpan: OtelSpan): voi const { op, description, data } = parseSpanDescription(otelSpan); - const { data: additionalData, tags } = getOtelSpanData(otelSpan.spanContext().spanId); + const { data: additionalData, tags, origin } = getOtelSpanData(otelSpan.spanContext().spanId); sentrySpan.setStatus(mapOtelStatus(otelSpan)); sentrySpan.setData('otel.kind', SpanKind[kind]); @@ -245,11 +245,15 @@ function updateSpanWithOtelData(sentrySpan: SentrySpan, otelSpan: OtelSpan): voi sentrySpan.op = op; sentrySpan.description = description; + + if (origin) { + sentrySpan.origin = origin; + } } function updateTransactionWithOtelData(transaction: Transaction, otelSpan: OtelSpan): void { const { op, description, source, data } = parseSpanDescription(otelSpan); - const { data: additionalData, tags, contexts, metadata } = getOtelSpanData(otelSpan.spanContext().spanId); + const { data: additionalData, tags, contexts, metadata, origin } = getOtelSpanData(otelSpan.spanContext().spanId); transaction.setContext('otel', { attributes: otelSpan.attributes, @@ -283,6 +287,10 @@ function updateTransactionWithOtelData(transaction: Transaction, otelSpan: OtelS transaction.op = op; transaction.setName(description, source); + + if (origin) { + transaction.origin = origin; + } } function convertOtelTimeToSeconds([seconds, nano]: [number, number]): number { diff --git a/packages/opentelemetry-node/src/utils/spanData.ts b/packages/opentelemetry-node/src/utils/spanData.ts index ed83892301d9..74d20b964985 100644 --- a/packages/opentelemetry-node/src/utils/spanData.ts +++ b/packages/opentelemetry-node/src/utils/spanData.ts @@ -1,4 +1,4 @@ -import type { Context } from '@sentry/types'; +import type { Context, SpanOrigin } from '@sentry/types'; type SentryTags = Record; type SentryData = Record; @@ -9,13 +9,14 @@ export interface AdditionalOtelSpanData { tags: SentryTags; contexts: Contexts; metadata: unknown; + origin?: SpanOrigin; } const OTEL_SPAN_DATA_MAP: Map = new Map(); /** Add data that should be added to the sentry span resulting from the given otel span ID. */ -export function addOtelSpanData(otelSpanId: string, data: AdditionalOtelSpanData): void { - OTEL_SPAN_DATA_MAP.set(otelSpanId, data); +export function addOtelSpanData(otelSpanId: string, data: Partial): void { + OTEL_SPAN_DATA_MAP.set(otelSpanId, { data: {}, tags: {}, contexts: {}, metadata: {}, ...data }); } /** Get additional data for a Sentry span. */ diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx index 4ada66266f26..34aa52092635 100644 --- a/packages/react/src/profiler.tsx +++ b/packages/react/src/profiler.tsx @@ -62,6 +62,7 @@ class Profiler extends React.Component { this._mountSpan = activeTransaction.startChild({ description: `<${name}>`, op: REACT_MOUNT_OP, + origin: 'auto.ui.react.profiler', }); } } @@ -89,6 +90,7 @@ class Profiler extends React.Component { }, description: `<${this.props.name}>`, op: REACT_UPDATE_OP, + origin: 'auto.ui.react.profiler', startTimestamp: now, }); } @@ -116,6 +118,7 @@ class Profiler extends React.Component { description: `<${name}>`, endTimestamp: timestampInSeconds(), op: REACT_RENDER_OP, + origin: 'auto.ui.react.profiler', startTimestamp: this._mountSpan.endTimestamp, }); } @@ -180,6 +183,7 @@ function useProfiler( return activeTransaction.startChild({ description: `<${name}>`, op: REACT_MOUNT_OP, + origin: 'auto.ui.react.profiler', }); } @@ -197,6 +201,7 @@ function useProfiler( description: `<${name}>`, endTimestamp: timestampInSeconds(), op: REACT_RENDER_OP, + origin: 'auto.ui.react.profiler', startTimestamp: mountSpan.endTimestamp, }); } diff --git a/packages/react/src/reactrouter.tsx b/packages/react/src/reactrouter.tsx index 95c507e3d07b..ab45d4e5f82e 100644 --- a/packages/react/src/reactrouter.tsx +++ b/packages/react/src/reactrouter.tsx @@ -93,6 +93,7 @@ function createReactRouterInstrumentation( activeTransaction = customStartTransaction({ name, op: 'pageload', + origin: 'auto.pageload.react.reactrouter', tags, metadata: { source, @@ -111,6 +112,7 @@ function createReactRouterInstrumentation( activeTransaction = customStartTransaction({ name, op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags, metadata: { source, diff --git a/packages/react/src/reactrouterv3.ts b/packages/react/src/reactrouterv3.ts index 4d12b3581e53..f185a025a649 100644 --- a/packages/react/src/reactrouterv3.ts +++ b/packages/react/src/reactrouterv3.ts @@ -53,6 +53,7 @@ export function reactRouterV3Instrumentation( activeTransaction = startTransaction({ name: prevName, op: 'pageload', + origin: 'auto.pageload.react.reactrouterv3', tags: { 'routing.instrumentation': 'react-router-v3', }, @@ -81,6 +82,7 @@ export function reactRouterV3Instrumentation( activeTransaction = startTransaction({ name: prevName, op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags, metadata: { source, diff --git a/packages/react/src/reactrouterv6.tsx b/packages/react/src/reactrouterv6.tsx index 161c7dd5fb3b..de356b05347b 100644 --- a/packages/react/src/reactrouterv6.tsx +++ b/packages/react/src/reactrouterv6.tsx @@ -55,6 +55,7 @@ export function reactRouterV6Instrumentation( activeTransaction = customStartTransaction({ name: initPathName, op: 'pageload', + origin: 'auto.pageload.react.reactrouterv6', tags: SENTRY_TAGS, metadata: { source: 'url', @@ -152,6 +153,7 @@ function handleNavigation( activeTransaction = _customStartTransaction({ name, op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: SENTRY_TAGS, metadata: { source, diff --git a/packages/react/test/profiler.test.tsx b/packages/react/test/profiler.test.tsx index 20dc1f2962c5..70eaff2d2c8b 100644 --- a/packages/react/test/profiler.test.tsx +++ b/packages/react/test/profiler.test.tsx @@ -79,6 +79,7 @@ describe('withProfiler', () => { expect(mockStartChild).toHaveBeenLastCalledWith({ description: `<${UNKNOWN_COMPONENT}>`, op: REACT_MOUNT_OP, + origin: 'auto.ui.react.profiler', }); }); }); @@ -96,6 +97,7 @@ describe('withProfiler', () => { description: `<${UNKNOWN_COMPONENT}>`, endTimestamp: expect.any(Number), op: REACT_RENDER_OP, + origin: 'auto.ui.react.profiler', startTimestamp: undefined, }); }); @@ -127,6 +129,7 @@ describe('withProfiler', () => { data: { changedProps: ['num'] }, description: `<${UNKNOWN_COMPONENT}>`, op: REACT_UPDATE_OP, + origin: 'auto.ui.react.profiler', startTimestamp: expect.any(Number), }); expect(mockFinish).toHaveBeenCalledTimes(2); @@ -137,6 +140,7 @@ describe('withProfiler', () => { data: { changedProps: ['num'] }, description: `<${UNKNOWN_COMPONENT}>`, op: REACT_UPDATE_OP, + origin: 'auto.ui.react.profiler', startTimestamp: expect.any(Number), }); expect(mockFinish).toHaveBeenCalledTimes(3); @@ -175,6 +179,7 @@ describe('useProfiler()', () => { expect(mockStartChild).toHaveBeenLastCalledWith({ description: '', op: REACT_MOUNT_OP, + origin: 'auto.ui.react.profiler', }); }); }); @@ -197,6 +202,7 @@ describe('useProfiler()', () => { expect.objectContaining({ description: '', op: REACT_RENDER_OP, + origin: 'auto.ui.react.profiler', }), ); }); diff --git a/packages/react/test/reactrouterv3.test.tsx b/packages/react/test/reactrouterv3.test.tsx index a4cbe463adbc..42d1b6992440 100644 --- a/packages/react/test/reactrouterv3.test.tsx +++ b/packages/react/test/reactrouterv3.test.tsx @@ -52,6 +52,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv3', tags: { 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'route', @@ -77,6 +78,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags: { from: '/', 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'route', @@ -90,6 +92,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/features', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags: { from: '/about', 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'route', @@ -143,6 +146,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/users/:userid', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags: { from: '/', 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'route', @@ -164,6 +168,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/:orgid/v1/:teamid', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags: { from: '/', 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'route', @@ -179,6 +184,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/:orgid', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags: { from: '/organizations/:orgid/v1/:teamid', 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'route', @@ -199,6 +205,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/1234/some/other/route', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv3', tags: { from: '/', 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'url', @@ -219,6 +226,7 @@ describe('React Router V3', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv3', tags: { 'routing.instrumentation': 'react-router-v3' }, metadata: { source: 'url', diff --git a/packages/react/test/reactrouterv4.test.tsx b/packages/react/test/reactrouterv4.test.tsx index 343f78c175e5..fb608a37726e 100644 --- a/packages/react/test/reactrouterv4.test.tsx +++ b/packages/react/test/reactrouterv4.test.tsx @@ -37,6 +37,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -66,6 +67,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -77,6 +79,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/features', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -155,6 +158,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/users/123', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -182,6 +186,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/users/123', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -211,6 +216,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/1234/v1/758', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -226,6 +232,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/543', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'url' }, }); @@ -259,6 +266,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/:orgid/v1/:teamid', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'route' }, }); @@ -270,6 +278,7 @@ describe('React Router v4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/:orgid', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v4' }, metadata: { source: 'route' }, }); diff --git a/packages/react/test/reactrouterv5.test.tsx b/packages/react/test/reactrouterv5.test.tsx index 568e630ccc25..c4a6ae2f7d98 100644 --- a/packages/react/test/reactrouterv5.test.tsx +++ b/packages/react/test/reactrouterv5.test.tsx @@ -37,6 +37,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -66,6 +67,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -77,6 +79,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/features', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -155,6 +158,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/users/123', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -182,6 +186,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/users/123', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -212,6 +217,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/1234/v1/758', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -227,6 +233,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/543', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'url' }, }); @@ -260,6 +267,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/:orgid/v1/:teamid', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'route' }, }); @@ -271,6 +279,7 @@ describe('React Router v5', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/organizations/:orgid', op: 'navigation', + origin: 'auto.navigation.react.reactrouter', tags: { 'routing.instrumentation': 'react-router-v5' }, metadata: { source: 'route' }, }); diff --git a/packages/react/test/reactrouterv6.4.test.tsx b/packages/react/test/reactrouterv6.4.test.tsx index e6bfc67b9bcf..913b6041e053 100644 --- a/packages/react/test/reactrouterv6.4.test.tsx +++ b/packages/react/test/reactrouterv6.4.test.tsx @@ -70,6 +70,7 @@ describe('React Router v6.4', () => { expect(mockStartTransaction).toHaveBeenCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6', }, @@ -106,6 +107,7 @@ describe('React Router v6.4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -144,6 +146,7 @@ describe('React Router v6.4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about/us', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -182,6 +185,7 @@ describe('React Router v6.4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about/:page', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -232,6 +236,7 @@ describe('React Router v6.4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/stores/:storeId/products/:productId', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -300,6 +305,7 @@ describe('React Router v6.4', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/app/about/us', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'url' }, }); diff --git a/packages/react/test/reactrouterv6.test.tsx b/packages/react/test/reactrouterv6.test.tsx index 6d0faa719f57..281999b95696 100644 --- a/packages/react/test/reactrouterv6.test.tsx +++ b/packages/react/test/reactrouterv6.test.tsx @@ -59,6 +59,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'url' }, }); @@ -96,6 +97,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'url' }, }); @@ -118,6 +120,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -142,6 +145,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about/us', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -166,6 +170,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about/:page', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -192,6 +197,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/stores/:storeId/products/:productId', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -226,6 +232,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/projects/:projectId/views/:viewId', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -255,6 +262,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'url' }, }); @@ -307,6 +315,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'url' }, }); @@ -338,6 +347,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -375,6 +385,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about/us', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -412,6 +423,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/about/:page', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -455,6 +467,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/stores/:storeId/products/:productId', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); @@ -522,6 +535,7 @@ describe('React Router v6', () => { expect(mockStartTransaction).toHaveBeenLastCalledWith({ name: '/projects/:projectId/views/:viewId', op: 'navigation', + origin: 'auto.navigation.react.reactrouterv6', tags: { 'routing.instrumentation': 'react-router-v6' }, metadata: { source: 'route' }, }); diff --git a/packages/remix/src/client/performance.tsx b/packages/remix/src/client/performance.tsx index a3f7815b7bdc..ed7dea13cfc3 100644 --- a/packages/remix/src/client/performance.tsx +++ b/packages/remix/src/client/performance.tsx @@ -65,6 +65,7 @@ export function remixRouterInstrumentation(useEffect: UseEffect, useLocation: Us activeTransaction = customStartTransaction({ name: initPathName, op: 'pageload', + origin: 'auto.pageload.remix', tags: DEFAULT_TAGS, metadata: { source: 'url', @@ -142,6 +143,7 @@ export function withSentry

, R extends React.FC activeTransaction = _customStartTransaction({ name: matches[matches.length - 1].id, op: 'navigation', + origin: 'auto.navigation.remix', tags: DEFAULT_TAGS, metadata: { source: 'route', diff --git a/packages/remix/src/utils/instrumentServer.ts b/packages/remix/src/utils/instrumentServer.ts index b0ba45f69c26..e588ae74ccad 100644 --- a/packages/remix/src/utils/instrumentServer.ts +++ b/packages/remix/src/utils/instrumentServer.ts @@ -140,6 +140,7 @@ function makeWrappedDocumentRequestFunction( try { const span = activeTransaction?.startChild({ op: 'function.remix.document_request', + origin: 'auto.function.remix', description: activeTransaction.name, tags: { method: request.method, @@ -182,6 +183,7 @@ function makeWrappedDataFunction(origFn: DataFunction, id: string, name: 'action try { const span = activeTransaction?.startChild({ op: `function.remix.${name}`, + origin: 'auto.ui.remix', description: id, tags: { name, @@ -325,6 +327,7 @@ export function startRequestHandlerTransaction( const transaction = hub.startTransaction({ name, op: 'http.server', + origin: 'auto.http.remix', tags: { method: request.method, }, diff --git a/packages/serverless/src/awslambda.ts b/packages/serverless/src/awslambda.ts index b5cf41af5e90..b5aa9200b524 100644 --- a/packages/serverless/src/awslambda.ts +++ b/packages/serverless/src/awslambda.ts @@ -292,6 +292,7 @@ export function wrapHandler( const transaction = hub.startTransaction({ name: context.functionName, op: 'function.aws.lambda', + origin: 'auto.function.serverless', ...traceparentData, metadata: { dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext, diff --git a/packages/serverless/src/awsservices.ts b/packages/serverless/src/awsservices.ts index 55c6741ffb69..f5ba74fd52b2 100644 --- a/packages/serverless/src/awsservices.ts +++ b/packages/serverless/src/awsservices.ts @@ -68,6 +68,7 @@ function wrapMakeRequest( span = transaction.startChild({ description: describe(this, operation, params), op: 'http.client', + origin: 'auto.http.serverless', }); } }); diff --git a/packages/serverless/src/gcpfunction/cloud_events.ts b/packages/serverless/src/gcpfunction/cloud_events.ts index f20f7f941ee2..83725ffbb840 100644 --- a/packages/serverless/src/gcpfunction/cloud_events.ts +++ b/packages/serverless/src/gcpfunction/cloud_events.ts @@ -35,6 +35,7 @@ function _wrapCloudEventFunction( const transaction = hub.startTransaction({ name: context.type || '', op: 'function.gcp.cloud_event', + origin: 'auto.function.serverless.gcp_cloud_event', metadata: { source: 'component' }, }) as ReturnType | undefined; diff --git a/packages/serverless/src/gcpfunction/events.ts b/packages/serverless/src/gcpfunction/events.ts index f6485de054d7..e2342d1fe905 100644 --- a/packages/serverless/src/gcpfunction/events.ts +++ b/packages/serverless/src/gcpfunction/events.ts @@ -37,6 +37,7 @@ function _wrapEventFunction const transaction = hub.startTransaction({ name: context.eventType, op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }) as ReturnType | undefined; diff --git a/packages/serverless/src/gcpfunction/http.ts b/packages/serverless/src/gcpfunction/http.ts index d3b24f5ba743..1c265fe9fb64 100644 --- a/packages/serverless/src/gcpfunction/http.ts +++ b/packages/serverless/src/gcpfunction/http.ts @@ -77,6 +77,7 @@ function _wrapHttpFunction(fn: HttpFunction, wrapOptions: Partial { diff --git a/packages/serverless/src/google-cloud-http.ts b/packages/serverless/src/google-cloud-http.ts index 0dd4f1f60ccb..b781a8c4c9c5 100644 --- a/packages/serverless/src/google-cloud-http.ts +++ b/packages/serverless/src/google-cloud-http.ts @@ -62,6 +62,7 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { span = transaction.startChild({ description: `${httpMethod} ${reqOpts.uri}`, op: `http.client.${identifyService(this.apiEndpoint)}`, + origin: 'auto.http.serverless', }); } orig.call(this, reqOpts, (...args: Parameters) => { diff --git a/packages/serverless/test/awslambda.test.ts b/packages/serverless/test/awslambda.test.ts index f2cff6e9b9c4..53770927c4a5 100644 --- a/packages/serverless/test/awslambda.test.ts +++ b/packages/serverless/test/awslambda.test.ts @@ -194,6 +194,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', metadata: { source: 'component' }, }; @@ -221,6 +222,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', metadata: { source: 'component' }, }; @@ -261,6 +263,7 @@ describe('AWSLambda', () => { parentSpanId: '1121201211212012', parentSampled: false, op: 'function.aws.lambda', + origin: 'auto.function.serverless', name: 'functionName', traceId: '12312012123120121231201212312012', metadata: { @@ -295,6 +298,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', traceId: '12312012123120121231201212312012', parentSpanId: '1121201211212012', parentSampled: false, @@ -325,6 +329,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', metadata: { source: 'component' }, }; @@ -363,6 +368,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', metadata: { source: 'component' }, }; @@ -405,6 +411,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', metadata: { source: 'component' }, }; @@ -443,6 +450,7 @@ describe('AWSLambda', () => { const fakeTransactionContext = { name: 'functionName', op: 'function.aws.lambda', + origin: 'auto.function.serverless', metadata: { source: 'component' }, }; diff --git a/packages/serverless/test/awsservices.test.ts b/packages/serverless/test/awsservices.test.ts index 63051773ea04..b37f9aa527f0 100644 --- a/packages/serverless/test/awsservices.test.ts +++ b/packages/serverless/test/awsservices.test.ts @@ -33,6 +33,7 @@ describe('AWSServices', () => { // @ts-ignore see "Why @ts-ignore" note expect(SentryNode.fakeTransaction.startChild).toBeCalledWith({ op: 'http.client', + origin: 'auto.http.serverless', description: 'aws.s3.getObject foo', }); // @ts-ignore see "Why @ts-ignore" note @@ -50,6 +51,7 @@ describe('AWSServices', () => { // @ts-ignore see "Why @ts-ignore" note expect(SentryNode.fakeTransaction.startChild).toBeCalledWith({ op: 'http.client', + origin: 'auto.http.serverless', description: 'aws.s3.getObject foo', }); }); @@ -65,6 +67,7 @@ describe('AWSServices', () => { // @ts-ignore see "Why @ts-ignore" note expect(SentryNode.fakeTransaction.startChild).toBeCalledWith({ op: 'http.client', + origin: 'auto.http.serverless', description: 'aws.lambda.invoke foo', }); }); diff --git a/packages/serverless/test/gcpfunction.test.ts b/packages/serverless/test/gcpfunction.test.ts index a203ceef4797..74939f1f574a 100644 --- a/packages/serverless/test/gcpfunction.test.ts +++ b/packages/serverless/test/gcpfunction.test.ts @@ -114,6 +114,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'POST /path', op: 'function.gcp.http', + origin: 'auto.function.serverless.gcp_http', metadata: { source: 'route' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -147,6 +148,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'POST /path', op: 'function.gcp.http', + origin: 'auto.function.serverless.gcp_http', traceId: '12312012123120121231201212312012', parentSpanId: '1121201211212012', parentSampled: false, @@ -183,6 +185,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'POST /path', op: 'function.gcp.http', + origin: 'auto.function.serverless.gcp_http', traceId: '12312012123120121231201212312012', parentSpanId: '1121201211212012', parentSampled: false, @@ -276,6 +279,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -303,6 +307,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -335,6 +340,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -366,6 +372,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -395,6 +402,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -422,6 +430,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -450,6 +459,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.event', + origin: 'auto.function.serverless.gcp_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -489,6 +499,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.cloud_event', + origin: 'auto.function.serverless.gcp_cloud_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -516,6 +527,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.cloud_event', + origin: 'auto.function.serverless.gcp_cloud_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -545,6 +557,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.cloud_event', + origin: 'auto.function.serverless.gcp_cloud_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -572,6 +585,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.cloud_event', + origin: 'auto.function.serverless.gcp_cloud_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note @@ -600,6 +614,7 @@ describe('GCPFunction', () => { const fakeTransactionContext = { name: 'event.type', op: 'function.gcp.cloud_event', + origin: 'auto.function.serverless.gcp_cloud_event', metadata: { source: 'component' }, }; // @ts-ignore see "Why @ts-ignore" note diff --git a/packages/serverless/test/google-cloud-grpc.test.ts b/packages/serverless/test/google-cloud-grpc.test.ts index ec8dcfe8c77b..212faefa111f 100644 --- a/packages/serverless/test/google-cloud-grpc.test.ts +++ b/packages/serverless/test/google-cloud-grpc.test.ts @@ -129,6 +129,7 @@ describe('GoogleCloudGrpc tracing', () => { // @ts-ignore see "Why @ts-ignore" note expect(SentryNode.fakeTransaction.startChild).toBeCalledWith({ op: 'grpc.pubsub', + origin: 'auto.grpc.serverless', description: 'unary call publish', }); await pubsub.close(); diff --git a/packages/serverless/test/google-cloud-http.test.ts b/packages/serverless/test/google-cloud-http.test.ts index f1fb19bad9ac..b2201f1728d7 100644 --- a/packages/serverless/test/google-cloud-http.test.ts +++ b/packages/serverless/test/google-cloud-http.test.ts @@ -60,11 +60,13 @@ describe('GoogleCloudHttp tracing', () => { // @ts-ignore see "Why @ts-ignore" note expect(SentryNode.fakeTransaction.startChild).toBeCalledWith({ op: 'http.client.bigquery', + origin: 'auto.http.serverless', description: 'POST /jobs', }); // @ts-ignore see "Why @ts-ignore" note expect(SentryNode.fakeTransaction.startChild).toBeCalledWith({ op: 'http.client.bigquery', + origin: 'auto.http.serverless', description: expect.stringMatching(new RegExp('^GET /queries/.+')), }); }); diff --git a/packages/svelte/src/performance.ts b/packages/svelte/src/performance.ts index 8bcafb8d9ed8..2230db18f9a4 100644 --- a/packages/svelte/src/performance.ts +++ b/packages/svelte/src/performance.ts @@ -50,6 +50,7 @@ function recordInitSpan(transaction: Transaction, componentName: string): Span { const initSpan = transaction.startChild({ op: UI_SVELTE_INIT, description: componentName, + origin: 'auto.ui.svelte', }); onMount(() => { @@ -77,6 +78,7 @@ function recordUpdateSpans(componentName: string, initSpan?: Span): void { updateSpan = parentSpan.startChild({ op: UI_SVELTE_UPDATE, description: componentName, + origin: 'auto.ui.svelte', }); }); diff --git a/packages/svelte/test/performance.test.ts b/packages/svelte/test/performance.test.ts index 1e02eb549d5f..c92492d0d943 100644 --- a/packages/svelte/test/performance.test.ts +++ b/packages/svelte/test/performance.test.ts @@ -65,11 +65,13 @@ describe('Sentry.trackComponent()', () => { expect(testTransaction.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.svelte.init', + origin: 'auto.ui.svelte', }); expect(testInitSpan.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.svelte.update', + origin: 'auto.ui.svelte', }); expect(testInitSpan.finish).toHaveBeenCalledTimes(1); @@ -96,6 +98,7 @@ describe('Sentry.trackComponent()', () => { expect(testTransaction.startChild).toHaveBeenLastCalledWith({ description: '', op: 'ui.svelte.update', + origin: 'auto.ui.svelte', }); expect(testTransaction.spans.length).toEqual(3); }); @@ -106,6 +109,7 @@ describe('Sentry.trackComponent()', () => { expect(testTransaction.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.svelte.init', + origin: 'auto.ui.svelte', }); expect(testInitSpan.startChild).not.toHaveBeenCalled(); @@ -120,6 +124,7 @@ describe('Sentry.trackComponent()', () => { expect(testTransaction.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.svelte.update', + origin: 'auto.ui.svelte', }); expect(testInitSpan.startChild).not.toHaveBeenCalled(); @@ -144,11 +149,13 @@ describe('Sentry.trackComponent()', () => { expect(testTransaction.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.svelte.init', + origin: 'auto.ui.svelte', }); expect(testInitSpan.startChild).toHaveBeenCalledWith({ description: '', op: 'ui.svelte.update', + origin: 'auto.ui.svelte', }); expect(testInitSpan.finish).toHaveBeenCalledTimes(1); @@ -187,6 +194,7 @@ describe('Sentry.trackComponent()', () => { expect(testTransaction.startChild).toHaveBeenLastCalledWith({ description: '', op: 'ui.svelte.init', + origin: 'auto.ui.svelte', }); expect(testTransaction.spans.length).toEqual(2); }); diff --git a/packages/sveltekit/src/client/load.ts b/packages/sveltekit/src/client/load.ts index 44430a3b9b1c..673941d76488 100644 --- a/packages/sveltekit/src/client/load.ts +++ b/packages/sveltekit/src/client/load.ts @@ -75,6 +75,7 @@ export function wrapLoadWithSentry any>(origLoad: T) return trace( { op: 'function.sveltekit.load', + origin: 'auto.function.sveltekit', name: routeId ? routeId : event.url.pathname, status: 'ok', metadata: { diff --git a/packages/sveltekit/src/client/router.ts b/packages/sveltekit/src/client/router.ts index 64125bdbdbd4..1883e5587c08 100644 --- a/packages/sveltekit/src/client/router.ts +++ b/packages/sveltekit/src/client/router.ts @@ -38,6 +38,7 @@ function instrumentPageload(startTransactionFn: (context: TransactionContext) => const pageloadTransaction = startTransactionFn({ name: initialPath, op: 'pageload', + origin: 'auto.pageload.sveltekit', description: initialPath, tags: { ...DEFAULT_TAGS, @@ -102,6 +103,7 @@ function instrumentNavigations(startTransactionFn: (context: TransactionContext) activeTransaction = startTransactionFn({ name: parameterizedRouteDestination || rawRouteDestination || 'unknown', op: 'navigation', + origin: 'auto.navigation.sveltekit', metadata: { source: parameterizedRouteDestination ? 'route' : 'url' }, tags: { ...DEFAULT_TAGS, @@ -117,6 +119,7 @@ function instrumentNavigations(startTransactionFn: (context: TransactionContext) routingSpan = activeTransaction.startChild({ op: 'ui.sveltekit.routing', description: 'SvelteKit Route Change', + origin: 'auto.ui.sveltekit', }); activeTransaction.setTag('from', parameterizedRouteOrigin); } diff --git a/packages/sveltekit/src/server/handle.ts b/packages/sveltekit/src/server/handle.ts index 332dea4925df..245fcee9658e 100644 --- a/packages/sveltekit/src/server/handle.ts +++ b/packages/sveltekit/src/server/handle.ts @@ -129,6 +129,7 @@ function instrumentHandle({ event, resolve }: Parameters[0], options: Se return trace( { op: 'http.server', + origin: 'auto.http.sveltekit', name: `${event.request.method} ${event.route?.id || event.url.pathname}`, status: 'ok', ...traceparentData, diff --git a/packages/sveltekit/src/server/load.ts b/packages/sveltekit/src/server/load.ts index 04d0137062c6..c286ad5e3834 100644 --- a/packages/sveltekit/src/server/load.ts +++ b/packages/sveltekit/src/server/load.ts @@ -72,6 +72,7 @@ export function wrapLoadWithSentry any>(origLoad: T) const traceLoadContext: TransactionContext = { op: 'function.sveltekit.load', + origin: 'auto.function.sveltekit', name: routeId ? routeId : event.url.pathname, status: 'ok', metadata: { @@ -130,6 +131,7 @@ export function wrapServerLoadWithSentry any>(origSe const traceLoadContext: TransactionContext = { op: 'function.sveltekit.server.load', + origin: 'auto.function.sveltekit', name: routeId ? routeId : event.url.pathname, status: 'ok', metadata: { diff --git a/packages/sveltekit/test/client/load.test.ts b/packages/sveltekit/test/client/load.test.ts index 01c2377ddbf2..64b5ef70fe3b 100644 --- a/packages/sveltekit/test/client/load.test.ts +++ b/packages/sveltekit/test/client/load.test.ts @@ -108,6 +108,7 @@ describe('wrapLoadWithSentry', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.load', + origin: 'auto.function.sveltekit', name: '/users/[id]', status: 'ok', metadata: { @@ -136,6 +137,7 @@ describe('wrapLoadWithSentry', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.load', + origin: 'auto.function.sveltekit', name: '/users/123', status: 'ok', metadata: { diff --git a/packages/sveltekit/test/client/router.test.ts b/packages/sveltekit/test/client/router.test.ts index 0b95a7195176..65bc39d5cdbb 100644 --- a/packages/sveltekit/test/client/router.test.ts +++ b/packages/sveltekit/test/client/router.test.ts @@ -53,6 +53,7 @@ describe('sveltekitRoutingInstrumentation', () => { expect(mockedStartTransaction).toHaveBeenCalledWith({ name: '/', op: 'pageload', + origin: 'auto.pageload.sveltekit', description: '/', tags: { 'routing.instrumentation': '@sentry/sveltekit', @@ -105,6 +106,7 @@ describe('sveltekitRoutingInstrumentation', () => { expect(mockedStartTransaction).toHaveBeenCalledWith({ name: '/users/[id]', op: 'navigation', + origin: 'auto.navigation.sveltekit', metadata: { source: 'route', }, @@ -115,6 +117,7 @@ describe('sveltekitRoutingInstrumentation', () => { expect(returnedTransaction?.startChild).toHaveBeenCalledWith({ op: 'ui.sveltekit.routing', + origin: 'auto.ui.sveltekit', description: 'SvelteKit Route Change', }); @@ -154,6 +157,7 @@ describe('sveltekitRoutingInstrumentation', () => { expect(mockedStartTransaction).toHaveBeenCalledWith({ name: '/users/[id]', op: 'navigation', + origin: 'auto.navigation.sveltekit', metadata: { source: 'route', }, @@ -164,6 +168,7 @@ describe('sveltekitRoutingInstrumentation', () => { expect(returnedTransaction?.startChild).toHaveBeenCalledWith({ op: 'ui.sveltekit.routing', + origin: 'auto.ui.sveltekit', description: 'SvelteKit Route Change', }); diff --git a/packages/sveltekit/test/server/load.test.ts b/packages/sveltekit/test/server/load.test.ts index 90980204cf68..6e27829f4004 100644 --- a/packages/sveltekit/test/server/load.test.ts +++ b/packages/sveltekit/test/server/load.test.ts @@ -230,6 +230,7 @@ describe('wrapLoadWithSentry calls trace', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.load', + origin: 'auto.function.sveltekit', name: '/users/[id]', status: 'ok', metadata: { @@ -249,6 +250,7 @@ describe('wrapLoadWithSentry calls trace', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.load', + origin: 'auto.function.sveltekit', name: '/users/123', status: 'ok', metadata: { @@ -283,6 +285,7 @@ describe('wrapServerLoadWithSentry calls trace', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.server.load', + origin: 'auto.function.sveltekit', name: '/users/[id]', parentSampled: true, parentSpanId: '1234567890abcdef', @@ -317,6 +320,7 @@ describe('wrapServerLoadWithSentry calls trace', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.server.load', + origin: 'auto.function.sveltekit', name: '/users/[id]', status: 'ok', data: { @@ -339,6 +343,7 @@ describe('wrapServerLoadWithSentry calls trace', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.server.load', + origin: 'auto.function.sveltekit', name: '/users/[id]', parentSampled: true, parentSpanId: '1234567890abcdef', @@ -368,6 +373,7 @@ describe('wrapServerLoadWithSentry calls trace', () => { expect(mockTrace).toHaveBeenCalledWith( { op: 'function.sveltekit.server.load', + origin: 'auto.function.sveltekit', name: '/users/123', parentSampled: true, parentSpanId: '1234567890abcdef', diff --git a/packages/tracing-internal/src/browser/metrics/index.ts b/packages/tracing-internal/src/browser/metrics/index.ts index f8cf44894d74..56fc793d21f7 100644 --- a/packages/tracing-internal/src/browser/metrics/index.ts +++ b/packages/tracing-internal/src/browser/metrics/index.ts @@ -77,6 +77,7 @@ export function startTrackingLongTasks(): void { transaction.startChild({ description: 'Main UI thread blocked', op: 'ui.long-task', + origin: 'auto.ui.browser.metrics', startTimestamp: startTime, endTimestamp: startTime + duration, }); @@ -104,6 +105,7 @@ export function startTrackingInteractions(): void { transaction.startChild({ description: htmlTreeAsString(entry.target), op: `ui.interaction.${entry.name}`, + origin: 'auto.ui.browser.metrics', startTimestamp: startTime, endTimestamp: startTime + duration, }); @@ -274,6 +276,7 @@ export function addPerformanceEntries(transaction: Transaction): void { description: 'first input delay', endTimestamp: fidMark.value + msToSec(_measurements['fid'].value), op: 'ui.action', + origin: 'auto.ui.browser.metrics', startTimestamp: fidMark.value, }); @@ -319,6 +322,7 @@ export function _addMeasureSpans( description: entry.name as string, endTimestamp: measureEndTimestamp, op: entry.entryType as string, + origin: 'auto.resource.browser.metrics', startTimestamp: measureStartTimestamp, }); @@ -354,6 +358,7 @@ function _addPerformanceNavigationTiming( } _startChild(transaction, { op: 'browser', + origin: 'auto.browser.browser.metrics', description: description || event, startTimestamp: timeOrigin + msToSec(start), endTimestamp: timeOrigin + msToSec(end), @@ -365,6 +370,7 @@ function _addPerformanceNavigationTiming( function _addRequest(transaction: Transaction, entry: Record, timeOrigin: number): void { _startChild(transaction, { op: 'browser', + origin: 'auto.browser.browser.metrics', description: 'request', startTimestamp: timeOrigin + msToSec(entry.requestStart as number), endTimestamp: timeOrigin + msToSec(entry.responseEnd as number), @@ -372,6 +378,7 @@ function _addRequest(transaction: Transaction, entry: Record, timeO _startChild(transaction, { op: 'browser', + origin: 'auto.browser.browser.metrics', description: 'response', startTimestamp: timeOrigin + msToSec(entry.responseStart as number), endTimestamp: timeOrigin + msToSec(entry.responseEnd as number), @@ -423,6 +430,7 @@ export function _addResourceSpans( description: resourceName, endTimestamp, op: entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other', + origin: 'auto.resource.browser.metrics', startTimestamp, data, }); diff --git a/packages/tracing-internal/src/browser/request.ts b/packages/tracing-internal/src/browser/request.ts index 7c64484ce54b..a6ccfefd1508 100644 --- a/packages/tracing-internal/src/browser/request.ts +++ b/packages/tracing-internal/src/browser/request.ts @@ -335,6 +335,7 @@ export function fetchCallback( }, description: `${method} ${url}`, op: 'http.client', + origin: 'auto.http.browser', }) : undefined; @@ -491,6 +492,7 @@ export function xhrCallback( }, description: `${sentryXhrData.method} ${sentryXhrData.url}`, op: 'http.client', + origin: 'auto.http.browser', }) : undefined; diff --git a/packages/tracing-internal/src/browser/router.ts b/packages/tracing-internal/src/browser/router.ts index ef3c0b7a6257..c796e44d3783 100644 --- a/packages/tracing-internal/src/browser/router.ts +++ b/packages/tracing-internal/src/browser/router.ts @@ -25,6 +25,7 @@ export function instrumentRoutingWithDefaults( // pageload should always start at timeOrigin (and needs to be in s, not ms) startTimestamp: browserPerformanceTimeOrigin ? browserPerformanceTimeOrigin / 1000 : undefined, op: 'pageload', + origin: 'auto.pageload.browser', metadata: { source: 'url' }, }); } @@ -55,6 +56,7 @@ export function instrumentRoutingWithDefaults( activeTransaction = customStartTransaction({ name: WINDOW.location.pathname, op: 'navigation', + origin: 'auto.navigation.browser', metadata: { source: 'url' }, }); } diff --git a/packages/tracing-internal/src/node/integrations/apollo.ts b/packages/tracing-internal/src/node/integrations/apollo.ts index f004d6533c61..945cde0d4a7c 100644 --- a/packages/tracing-internal/src/node/integrations/apollo.ts +++ b/packages/tracing-internal/src/node/integrations/apollo.ts @@ -192,6 +192,7 @@ function wrapResolver( const span = parentSpan?.startChild({ description: `${resolverGroupName}.${resolverName}`, op: 'graphql.resolve', + origin: 'auto.graphql.apollo', }); const rv = orig.call(this, ...args); diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index 154ad1546b15..047236381269 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -156,6 +156,7 @@ function wrap(fn: Function, method: Method): (...args: any[]) => void { const span = transaction.startChild({ description: fn.name, op: `middleware.express.${method}`, + origin: 'auto.middleware.express', }); res.once('finish', () => { span.finish(); @@ -175,6 +176,7 @@ function wrap(fn: Function, method: Method): (...args: any[]) => void { const span = transaction?.startChild({ description: fn.name, op: `middleware.express.${method}`, + origin: 'auto.middleware.express', }); fn.call(this, req, res, function (this: NodeJS.Global, ...args: unknown[]): void { span?.finish(); @@ -194,6 +196,7 @@ function wrap(fn: Function, method: Method): (...args: any[]) => void { const span = transaction?.startChild({ description: fn.name, op: `middleware.express.${method}`, + origin: 'auto.middleware.express', }); fn.call(this, err, req, res, function (this: NodeJS.Global, ...args: unknown[]): void { span?.finish(); diff --git a/packages/tracing-internal/src/node/integrations/graphql.ts b/packages/tracing-internal/src/node/integrations/graphql.ts index fc9852afd58f..fc9bf5aece57 100644 --- a/packages/tracing-internal/src/node/integrations/graphql.ts +++ b/packages/tracing-internal/src/node/integrations/graphql.ts @@ -56,6 +56,7 @@ export class GraphQL implements LazyLoadedIntegration { const span = parentSpan?.startChild({ description: 'execute', op: 'graphql.execute', + origin: 'auto.graphql.graphql', }); scope?.setSpan(span); diff --git a/packages/tracing-internal/src/node/integrations/mongo.ts b/packages/tracing-internal/src/node/integrations/mongo.ts index c462ea4dcdf2..df460520b87b 100644 --- a/packages/tracing-internal/src/node/integrations/mongo.ts +++ b/packages/tracing-internal/src/node/integrations/mongo.ts @@ -237,6 +237,7 @@ export class Mongo implements LazyLoadedIntegration { const spanContext: SpanContext = { op: 'db', // TODO v8: Use `${collection.collectionName}.${operation}` + origin: 'auto.db.mongo', description: operation, data, }; diff --git a/packages/tracing-internal/src/node/integrations/mysql.ts b/packages/tracing-internal/src/node/integrations/mysql.ts index 77ce6a66cd32..9c11165c643e 100644 --- a/packages/tracing-internal/src/node/integrations/mysql.ts +++ b/packages/tracing-internal/src/node/integrations/mysql.ts @@ -94,6 +94,7 @@ export class Mysql implements LazyLoadedIntegration { const span = parentSpan?.startChild({ description: typeof options === 'string' ? options : (options as { sql: string }).sql, op: 'db', + origin: 'auto.db.mysql', data: { ...spanDataFromConfig(), 'db.system': 'mysql', diff --git a/packages/tracing-internal/src/node/integrations/postgres.ts b/packages/tracing-internal/src/node/integrations/postgres.ts index f226c9264938..6a92e76b059c 100644 --- a/packages/tracing-internal/src/node/integrations/postgres.ts +++ b/packages/tracing-internal/src/node/integrations/postgres.ts @@ -109,6 +109,7 @@ export class Postgres implements LazyLoadedIntegration { const span = parentSpan?.startChild({ description: typeof config === 'string' ? config : (config as { text: string }).text, op: 'db', + origin: 'auto.db.postgres', data, }); diff --git a/packages/tracing-internal/src/node/integrations/prisma.ts b/packages/tracing-internal/src/node/integrations/prisma.ts index b8cb6ebff7b3..bf98be00e163 100644 --- a/packages/tracing-internal/src/node/integrations/prisma.ts +++ b/packages/tracing-internal/src/node/integrations/prisma.ts @@ -102,6 +102,7 @@ export class Prisma implements Integration { { name: model ? `${model} ${action}` : action, op: 'db.sql.prisma', + origin: 'auto.db.prisma', data: { ...clientData, 'db.operation': action }, }, () => next(params), diff --git a/packages/tracing-internal/test/browser/metrics/index.test.ts b/packages/tracing-internal/test/browser/metrics/index.test.ts index c196fbd2467c..41b4cd9c1940 100644 --- a/packages/tracing-internal/test/browser/metrics/index.test.ts +++ b/packages/tracing-internal/test/browser/metrics/index.test.ts @@ -32,6 +32,7 @@ describe('_addMeasureSpans', () => { startTimestamp: timeOrigin + startTime, endTimestamp: timeOrigin + startTime + duration, op: 'measure', + origin: 'auto.resource.browser.metrics', }); }); }); @@ -99,6 +100,7 @@ describe('_addResourceSpans', () => { description: '/assets/to/css', endTimestamp: timeOrigin + startTime + duration, op: 'resource.css', + origin: 'auto.resource.browser.metrics', startTimestamp: timeOrigin + startTime, }); }); diff --git a/packages/tracing-internal/test/browser/router.test.ts b/packages/tracing-internal/test/browser/router.test.ts index 8ad414a97b80..aa123154caa3 100644 --- a/packages/tracing-internal/test/browser/router.test.ts +++ b/packages/tracing-internal/test/browser/router.test.ts @@ -46,6 +46,7 @@ conditionalTest({ min: 16 })('instrumentRoutingWithDefaults', () => { expect(customStartTransaction).toHaveBeenLastCalledWith({ name: 'blank', op: 'pageload', + origin: 'auto.pageload.browser', metadata: { source: 'url' }, startTimestamp: expect.any(Number), }); @@ -67,6 +68,7 @@ conditionalTest({ min: 16 })('instrumentRoutingWithDefaults', () => { expect(customStartTransaction).not.toHaveBeenLastCalledWith({ name: 'blank', op: 'navigation', + origin: 'auto.navigation.browser', metadata: { source: 'url' }, }); }); @@ -80,6 +82,7 @@ conditionalTest({ min: 16 })('instrumentRoutingWithDefaults', () => { expect(customStartTransaction).toHaveBeenLastCalledWith({ name: 'blank', op: 'navigation', + origin: 'auto.navigation.browser', metadata: { source: 'url' }, }); }); diff --git a/packages/tracing/test/integrations/apollo-nestjs.test.ts b/packages/tracing/test/integrations/apollo-nestjs.test.ts index cf5733ad979d..703edcaad23d 100644 --- a/packages/tracing/test/integrations/apollo-nestjs.test.ts +++ b/packages/tracing/test/integrations/apollo-nestjs.test.ts @@ -93,6 +93,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'Query.res_1', op: 'graphql.resolve', + origin: 'auto.graphql.apollo', }); expect(childSpan.finish).toBeCalled(); }); @@ -103,6 +104,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'Mutation.res_2', op: 'graphql.resolve', + origin: 'auto.graphql.apollo', }); expect(childSpan.finish).toBeCalled(); }); diff --git a/packages/tracing/test/integrations/apollo.test.ts b/packages/tracing/test/integrations/apollo.test.ts index 9b50fbaa1adc..90da1f8e0b21 100644 --- a/packages/tracing/test/integrations/apollo.test.ts +++ b/packages/tracing/test/integrations/apollo.test.ts @@ -93,6 +93,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'Query.res_1', op: 'graphql.resolve', + origin: 'auto.graphql.apollo', }); expect(childSpan.finish).toBeCalled(); }); @@ -103,6 +104,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'Mutation.res_2', op: 'graphql.resolve', + origin: 'auto.graphql.apollo', }); expect(childSpan.finish).toBeCalled(); }); diff --git a/packages/tracing/test/integrations/graphql.test.ts b/packages/tracing/test/integrations/graphql.test.ts index fa5a026d653a..c61f287c3e86 100644 --- a/packages/tracing/test/integrations/graphql.test.ts +++ b/packages/tracing/test/integrations/graphql.test.ts @@ -55,6 +55,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'execute', op: 'graphql.execute', + origin: 'auto.graphql.graphql', }); expect(childSpan.finish).toBeCalled(); expect(scope.setSpan).toHaveBeenCalledTimes(2); diff --git a/packages/tracing/test/integrations/node/mongo.test.ts b/packages/tracing/test/integrations/node/mongo.test.ts index 4e866f608cb8..30e5c76563bd 100644 --- a/packages/tracing/test/integrations/node/mongo.test.ts +++ b/packages/tracing/test/integrations/node/mongo.test.ts @@ -81,6 +81,7 @@ describe('patchOperation()', () => { 'db.system': 'mongodb', }, op: 'db', + origin: 'auto.db.mongo', description: 'insertOne', }); expect(childSpan.finish).toBeCalled(); @@ -100,6 +101,7 @@ describe('patchOperation()', () => { 'db.system': 'mongodb', }, op: 'db', + origin: 'auto.db.mongo', description: 'insertOne', }); expect(childSpan.finish).toBeCalled(); @@ -116,6 +118,7 @@ describe('patchOperation()', () => { 'db.system': 'mongodb', }, op: 'db', + origin: 'auto.db.mongo', description: 'initializeOrderedBulkOp', }); expect(childSpan.finish).toBeCalled(); diff --git a/packages/tracing/test/integrations/node/postgres.test.ts b/packages/tracing/test/integrations/node/postgres.test.ts index d1b1f03b7914..bb735ca40d8b 100644 --- a/packages/tracing/test/integrations/node/postgres.test.ts +++ b/packages/tracing/test/integrations/node/postgres.test.ts @@ -72,6 +72,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'SELECT NOW()', op: 'db', + origin: 'auto.db.postgres', data: { 'db.system': 'postgresql', }, @@ -87,6 +88,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'SELECT NOW()', op: 'db', + origin: 'auto.db.postgres', data: { 'db.system': 'postgresql', }, @@ -102,6 +104,7 @@ describe('setupOnce', () => { expect(parentSpan.startChild).toBeCalledWith({ description: 'SELECT NOW()', op: 'db', + origin: 'auto.db.postgres', data: { 'db.system': 'postgresql', }, diff --git a/packages/tracing/test/integrations/node/prisma.test.ts b/packages/tracing/test/integrations/node/prisma.test.ts index 43d7fe6b5570..4b2034f37a01 100644 --- a/packages/tracing/test/integrations/node/prisma.test.ts +++ b/packages/tracing/test/integrations/node/prisma.test.ts @@ -56,6 +56,7 @@ describe('setupOnce', function () { { name: 'user create', op: 'db.sql.prisma', + origin: 'auto.db.prisma', data: { 'db.system': 'postgresql', 'db.prisma.version': '3.1.2', 'db.operation': 'create' }, }, expect.any(Function), diff --git a/packages/tracing/test/span.test.ts b/packages/tracing/test/span.test.ts index e6e35e105508..ca16a1395e3e 100644 --- a/packages/tracing/test/span.test.ts +++ b/packages/tracing/test/span.test.ts @@ -164,6 +164,7 @@ describe('Span', () => { parent_span_id: 'b', span_id: 'd', trace_id: 'c', + origin: 'manual', }); }); }); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 5b9490045a02..8a93681aa938 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -88,7 +88,7 @@ export type { // eslint-disable-next-line deprecation/deprecation export type { Severity, SeverityLevel } from './severity'; -export type { Span, SpanContext } from './span'; +export type { Span, SpanContext, SpanOrigin } from './span'; export type { StackFrame } from './stackframe'; export type { Stacktrace, StackParser, StackLineParser, StackLineParserFn } from './stacktrace'; export type { TextEncoderInternal } from './textencoder'; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index a689590c499e..7485bbf88d72 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -2,6 +2,16 @@ import type { Instrumenter } from './instrumenter'; import type { Primitive } from './misc'; import type { Transaction } from './transaction'; +type SpanOriginType = 'manual' | 'auto'; +type SpanOriginCategory = string; // e.g. http, db, ui, .... +type SpanOriginIntegrationName = string; +type SpanOriginIntegrationPart = string; +export type SpanOrigin = + | SpanOriginType + | `${SpanOriginType}.${SpanOriginCategory}` + | `${SpanOriginType}.${SpanOriginCategory}.${SpanOriginIntegrationName}` + | `${SpanOriginType}.${SpanOriginCategory}.${SpanOriginIntegrationName}.${SpanOriginIntegrationPart}`; + /** Interface holding all properties that can be set on a Span on creation. */ export interface SpanContext { /** @@ -69,6 +79,11 @@ export interface SpanContext { * The instrumenter that created this span. */ instrumenter?: Instrumenter; + + /** + * The origin of the span, giving context about what created the span. + */ + origin?: SpanOrigin; } /** Span holding trace_id, span_id */ diff --git a/packages/vue/src/router.ts b/packages/vue/src/router.ts index 25408f24f6b6..641a4344fd4c 100644 --- a/packages/vue/src/router.ts +++ b/packages/vue/src/router.ts @@ -70,6 +70,7 @@ export function vueRouterInstrumentation( startTransaction({ name: WINDOW.location.pathname, op: 'pageload', + origin: 'auto.pageload.vue', tags, metadata: { source: 'url', @@ -121,6 +122,7 @@ export function vueRouterInstrumentation( startTransaction({ name: transactionName, op: 'navigation', + origin: 'auto.navigation.vue', tags, data, metadata: { diff --git a/packages/vue/src/tracing.ts b/packages/vue/src/tracing.ts index 1be68b26b61e..100ff4aeb126 100644 --- a/packages/vue/src/tracing.ts +++ b/packages/vue/src/tracing.ts @@ -76,6 +76,7 @@ export const createTracingMixins = (options: TracingOptions): Mixins => { activeTransaction.startChild({ description: 'Application Render', op: `${VUE_OP}.render`, + origin: 'auto.ui.vue', }); } } @@ -109,6 +110,7 @@ export const createTracingMixins = (options: TracingOptions): Mixins => { this.$_sentrySpans[operation] = activeTransaction.startChild({ description: `Vue <${name}>`, op: `${VUE_OP}.${operation}`, + origin: 'auto.ui.vue', }); } } else { diff --git a/packages/vue/test/router.test.ts b/packages/vue/test/router.test.ts index 044228181f50..a1d6dd4a6713 100644 --- a/packages/vue/test/router.test.ts +++ b/packages/vue/test/router.test.ts @@ -108,6 +108,7 @@ describe('vueRouterInstrumentation()', () => { query: to.query, }, op: 'navigation', + origin: 'auto.navigation.vue', tags: { 'routing.instrumentation': 'vue-router', }, @@ -148,6 +149,7 @@ describe('vueRouterInstrumentation()', () => { source: 'url', }, op: 'pageload', + origin: 'auto.pageload.vue', tags: { 'routing.instrumentation': 'vue-router', }, @@ -194,6 +196,7 @@ describe('vueRouterInstrumentation()', () => { query: to.query, }, op: 'navigation', + origin: 'auto.navigation.vue', tags: { 'routing.instrumentation': 'vue-router', }, @@ -225,6 +228,7 @@ describe('vueRouterInstrumentation()', () => { query: to.query, }, op: 'navigation', + origin: 'auto.navigation.vue', tags: { 'routing.instrumentation': 'vue-router', }, @@ -259,6 +263,7 @@ describe('vueRouterInstrumentation()', () => { source: 'url', }, op: 'pageload', + origin: 'auto.pageload.vue', tags: { 'routing.instrumentation': 'vue-router', }, @@ -345,6 +350,7 @@ describe('vueRouterInstrumentation()', () => { query: to.query, }, op: 'navigation', + origin: 'auto.navigation.vue', tags: { 'routing.instrumentation': 'vue-router', }, From fe2c801c1e6f986e9e8fa2adbc13cfdb186a3b51 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 29 Aug 2023 14:35:38 +0100 Subject: [PATCH 6/7] fix(nextjs): Fix `package.json` exports (#8895) --- packages/nextjs/package.json | 10 ---------- packages/nextjs/src/config/loaders/wrappingLoader.ts | 2 +- .../src/config/templates/requestAsyncStorageShim.ts | 6 ------ .../config/templates/serverComponentWrapperTemplate.ts | 2 +- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 9190bb3d28dd..507cb763372b 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -13,16 +13,6 @@ "module": "build/esm/index.server.js", "browser": "build/esm/index.client.js", "types": "build/types/index.types.d.ts", - "exports": { - ".": { - "import": "./build/esm/index.server.js", - "require": "./build/cjs/index.server.js", - "types": "./build/types/index.types.d.ts" - }, - "./requestAsyncStorageShim": { - "import": "./build/esm/config/templates/requestAsyncStorageShim.js" - } - }, "typesVersions": { "<4.9": { "build/npm/types/index.d.ts": [ diff --git a/packages/nextjs/src/config/loaders/wrappingLoader.ts b/packages/nextjs/src/config/loaders/wrappingLoader.ts index 4cc2425a33c0..1731722de7bb 100644 --- a/packages/nextjs/src/config/loaders/wrappingLoader.ts +++ b/packages/nextjs/src/config/loaders/wrappingLoader.ts @@ -191,7 +191,7 @@ export default function wrappingLoader( } templateCode = templateCode.replace( /__SENTRY_NEXTJS_REQUEST_ASYNC_STORAGE_SHIM__/g, - '@sentry/nextjs/requestAsyncStorageShim', + '@sentry/nextjs/build/esm/config/templates/requestAsyncStorageShim.js', ); } diff --git a/packages/nextjs/src/config/templates/requestAsyncStorageShim.ts b/packages/nextjs/src/config/templates/requestAsyncStorageShim.ts index bc0e23000815..44222403d026 100644 --- a/packages/nextjs/src/config/templates/requestAsyncStorageShim.ts +++ b/packages/nextjs/src/config/templates/requestAsyncStorageShim.ts @@ -7,9 +7,3 @@ export interface RequestAsyncStorage { } | undefined; } - -export const requestAsyncStorage: RequestAsyncStorage = { - getStore: () => { - return undefined; - }, -}; diff --git a/packages/nextjs/src/config/templates/serverComponentWrapperTemplate.ts b/packages/nextjs/src/config/templates/serverComponentWrapperTemplate.ts index 3f5ef8349c30..7ebf29099f3a 100644 --- a/packages/nextjs/src/config/templates/serverComponentWrapperTemplate.ts +++ b/packages/nextjs/src/config/templates/serverComponentWrapperTemplate.ts @@ -28,7 +28,7 @@ if (typeof serverComponent === 'function') { let sentryTraceHeader: string | undefined | null = undefined; let baggageHeader: string | undefined | null = undefined; - // We try-catch here just in case the API around `requestAsyncStorage` changes unexpectedly since it is not public API + // We try-catch here just in `requestAsyncStorage` is undefined since it may not be defined try { const requestAsyncStore = requestAsyncStorage.getStore(); sentryTraceHeader = requestAsyncStore?.headers.get('sentry-trace'); From cf95612593254f3a1de7df09c018f261c5f12ef4 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 29 Aug 2023 13:37:07 +0000 Subject: [PATCH 7/7] meta(changelog): Update changelog for 7.66.0 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89eb3b20a452..95d043c5a6ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 7.66.0 + +- fix: Defer tracing decision to downstream SDKs when using SDK without performance (#8839) +- fix(nextjs): Fix `package.json` exports (#8895) +- fix(sveltekit): Ensure target file exists before applying auto instrumentation (#8881) +- ref: Use consistent console instrumentation (#8879) +- ref(browser): Refactor sentry breadcrumb to use hook (#8892) +- ref(tracing): Add `origin` to spans (#8765) + ## 7.65.0 - build: Remove build-specific polyfills (#8809)