diff --git a/packages/opentelemetry/src/index.ts b/packages/opentelemetry/src/index.ts index abf6640bca5c..8cae9b317837 100644 --- a/packages/opentelemetry/src/index.ts +++ b/packages/opentelemetry/src/index.ts @@ -1,4 +1,3 @@ -import { maybeCaptureExceptionForTimedEvent } from './utils/captureExceptionForTimedEvent'; import { getRequestSpanData } from './utils/getRequestSpanData'; export type { OpenTelemetryClient } from './types'; @@ -47,7 +46,6 @@ export { getClient } from '@sentry/core'; * @hidden */ const _INTERNAL = { - maybeCaptureExceptionForTimedEvent, getRequestSpanData, } as const; diff --git a/packages/opentelemetry/src/spanProcessor.ts b/packages/opentelemetry/src/spanProcessor.ts index 5dedcb464d58..210a2202ca27 100644 --- a/packages/opentelemetry/src/spanProcessor.ts +++ b/packages/opentelemetry/src/spanProcessor.ts @@ -8,7 +8,6 @@ import { logger } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; import { SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE } from './semanticAttributes'; import { SentrySpanExporter } from './spanExporter'; -import { maybeCaptureExceptionForTimedEvent } from './utils/captureExceptionForTimedEvent'; import { getScopesFromContext } from './utils/contextData'; import { setIsSetup } from './utils/setupCheck'; import { setSpanScopes } from './utils/spanData'; @@ -48,11 +47,6 @@ function onSpanStart(span: Span, parentContext: Context): void { } function onSpanEnd(span: Span): void { - // Capture exceptions as events - span.events.forEach(event => { - maybeCaptureExceptionForTimedEvent(event, span); - }); - const client = getClient(); client?.emit('spanEnd', span); } diff --git a/packages/opentelemetry/src/utils/captureExceptionForTimedEvent.ts b/packages/opentelemetry/src/utils/captureExceptionForTimedEvent.ts deleted file mode 100644 index d67e26a21475..000000000000 --- a/packages/opentelemetry/src/utils/captureExceptionForTimedEvent.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { Span as OtelSpan, TimedEvent } from '@opentelemetry/sdk-trace-base'; -import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; -import { captureException } from '@sentry/core'; -import { isString } from '@sentry/utils'; - -/** - * Maybe capture a Sentry exception for an OTEL timed event. - * This will check if the event is exception-like and in that case capture it as an exception. - */ -export function maybeCaptureExceptionForTimedEvent(event: TimedEvent, otelSpan?: OtelSpan): void { - if (event.name !== 'exception') { - return; - } - - const attributes = event.attributes; - if (!attributes) { - return; - } - - const message = attributes[SemanticAttributes.EXCEPTION_MESSAGE]; - - if (typeof message !== 'string') { - return; - } - - const syntheticError = new Error(message); - - const stack = attributes[SemanticAttributes.EXCEPTION_STACKTRACE]; - if (isString(stack)) { - syntheticError.stack = stack; - } - - const type = attributes[SemanticAttributes.EXCEPTION_TYPE]; - if (isString(type)) { - syntheticError.name = type; - } - - captureException(syntheticError, { - captureContext: otelSpan - ? { - contexts: { - otel: { - attributes: otelSpan.attributes, - resource: otelSpan.resource.attributes, - }, - trace: { - trace_id: otelSpan.spanContext().traceId, - span_id: otelSpan.spanContext().spanId, - parent_span_id: otelSpan.parentSpanId, - }, - }, - } - : undefined, - }); -} diff --git a/packages/opentelemetry/test/integration/otelTimedEvents.test.ts b/packages/opentelemetry/test/integration/otelTimedEvents.test.ts deleted file mode 100644 index f0e0fc109c80..000000000000 --- a/packages/opentelemetry/test/integration/otelTimedEvents.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; - -import { getClient } from '@sentry/core'; -import { startSpan } from '../../src/trace'; -import type { TestClientInterface } from '../helpers/TestClient'; -import { cleanupOtel, mockSdkInit } from '../helpers/mockSdkInit'; - -describe('Integration | OTEL TimedEvents', () => { - afterEach(() => { - cleanupOtel(); - }); - - it('captures TimedEvents with name `exception` as exceptions', async () => { - const beforeSend = jest.fn(() => null); - const beforeSendTransaction = jest.fn(() => null); - - mockSdkInit({ beforeSend, beforeSendTransaction, enableTracing: true }); - - const client = getClient() as TestClientInterface; - - startSpan({ name: 'test' }, span => { - span.addEvent('exception', { - [SemanticAttributes.EXCEPTION_MESSAGE]: 'test-message', - 'test-span-event-attr': 'test-span-event-attr-value', - }); - - span.addEvent('other', { - [SemanticAttributes.EXCEPTION_MESSAGE]: 'test-message-2', - 'test-span-event-attr': 'test-span-event-attr-value', - }); - }); - - await client.flush(); - - expect(beforeSend).toHaveBeenCalledTimes(1); - expect(beforeSend).toHaveBeenCalledWith( - expect.objectContaining({ - exception: { - values: [ - { - type: 'Error', - value: 'test-message', - }, - ], - }, - }), - { - event_id: expect.any(String), - originalException: expect.any(Error), - syntheticException: expect.any(Error), - captureContext: expect.any(Object), - }, - ); - }); -}); diff --git a/packages/opentelemetry/test/utils/captureExceptionForTimedEvent.test.ts b/packages/opentelemetry/test/utils/captureExceptionForTimedEvent.test.ts deleted file mode 100644 index 4e6103e9a7a8..000000000000 --- a/packages/opentelemetry/test/utils/captureExceptionForTimedEvent.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -import type { Span as OtelSpan, TimedEvent } from '@opentelemetry/sdk-trace-base'; -import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; -import * as SentryCore from '@sentry/core'; - -import { maybeCaptureExceptionForTimedEvent } from '../../src/utils/captureExceptionForTimedEvent'; - -describe('maybeCaptureExceptionForTimedEvent', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - it('ignores non-exception events', async () => { - const event: TimedEvent = { - time: [12345, 0], - name: 'test event', - }; - - const captureException = jest.spyOn(SentryCore, 'captureException'); - maybeCaptureExceptionForTimedEvent(event); - - expect(captureException).not.toHaveBeenCalled(); - }); - - it('ignores exception events without EXCEPTION_MESSAGE', async () => { - const event: TimedEvent = { - time: [12345, 0], - name: 'exception', - }; - - const captureException = jest.spyOn(SentryCore, 'captureException'); - maybeCaptureExceptionForTimedEvent(event); - - expect(captureException).not.toHaveBeenCalled(); - }); - - it('captures exception from event with EXCEPTION_MESSAGE', async () => { - const event: TimedEvent = { - time: [12345, 0], - name: 'exception', - attributes: { - [SemanticAttributes.EXCEPTION_MESSAGE]: 'test-message', - }, - }; - - const captureException = jest.spyOn(SentryCore, 'captureException'); - maybeCaptureExceptionForTimedEvent(event); - - expect(captureException).toHaveBeenCalledTimes(1); - expect(captureException).toHaveBeenCalledWith(expect.objectContaining({ message: 'test-message' }), { - captureContext: undefined, - }); - expect(captureException).toHaveBeenCalledWith(expect.any(Error), { - captureContext: undefined, - }); - }); - - it('captures stack and type, if available', async () => { - const event: TimedEvent = { - time: [12345, 0], - name: 'exception', - attributes: { - [SemanticAttributes.EXCEPTION_MESSAGE]: 'test-message', - [SemanticAttributes.EXCEPTION_STACKTRACE]: 'test-stack', - [SemanticAttributes.EXCEPTION_TYPE]: 'test-type', - }, - }; - - const captureException = jest.spyOn(SentryCore, 'captureException'); - maybeCaptureExceptionForTimedEvent(event); - - expect(captureException).toHaveBeenCalledTimes(1); - expect(captureException).toHaveBeenCalledWith( - expect.objectContaining({ message: 'test-message', name: 'test-type', stack: 'test-stack' }), - { - captureContext: undefined, - }, - ); - expect(captureException).toHaveBeenCalledWith(expect.any(Error), { - captureContext: undefined, - }); - }); - - it('captures span context, if available', async () => { - const event: TimedEvent = { - time: [12345, 0], - name: 'exception', - attributes: { - [SemanticAttributes.EXCEPTION_MESSAGE]: 'test-message', - }, - }; - - const span = { - parentSpanId: 'test-parent-span-id', - attributes: { - 'test-attr1': 'test-value1', - }, - resource: { - attributes: { - 'test-attr2': 'test-value2', - }, - }, - spanContext: () => { - return { spanId: 'test-span-id', traceId: 'test-trace-id' }; - }, - } as unknown as OtelSpan; - - const captureException = jest.spyOn(SentryCore, 'captureException'); - maybeCaptureExceptionForTimedEvent(event, span); - - expect(captureException).toHaveBeenCalledTimes(1); - expect(captureException).toHaveBeenCalledWith(expect.objectContaining({ message: 'test-message' }), { - captureContext: { - contexts: { - otel: { - attributes: { - 'test-attr1': 'test-value1', - }, - resource: { - 'test-attr2': 'test-value2', - }, - }, - trace: { - trace_id: 'test-trace-id', - span_id: 'test-span-id', - parent_span_id: 'test-parent-span-id', - }, - }, - }, - }); - }); -});