diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index 19911f7be91f..8e7844d23988 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -7,6 +7,9 @@ import type { Span } from './span'; /** * Wraps a function with a transaction/span and finishes the span after the function is done. * + * Note that if you have not enabled tracing extensions via `addTracingExtensions`, this function + * will not generate spans, and the `span` returned from the callback may be undefined. + * * This function is meant to be used internally and may break at any time. Use at your own risk. * * @internal @@ -14,7 +17,7 @@ import type { Span } from './span'; */ export function trace( context: TransactionContext, - callback: (span: Span) => T, + callback: (span?: Span) => T, // eslint-disable-next-line @typescript-eslint/no-empty-function onError: (error: unknown) => void = () => {}, ): T { @@ -32,7 +35,7 @@ export function trace( scope.setSpan(activeSpan); function finishAndSetSpan(): void { - activeSpan.finish(); + activeSpan && activeSpan.finish(); hub.getScope().setSpan(parentSpan); } @@ -40,7 +43,7 @@ export function trace( try { maybePromiseResult = callback(activeSpan); } catch (e) { - activeSpan.setStatus('internal_error'); + activeSpan && activeSpan.setStatus('internal_error'); onError(e); finishAndSetSpan(); throw e; @@ -52,7 +55,7 @@ export function trace( finishAndSetSpan(); }, e => { - activeSpan.setStatus('internal_error'); + activeSpan && activeSpan.setStatus('internal_error'); onError(e); finishAndSetSpan(); }, diff --git a/packages/core/test/lib/tracing/trace.test.ts b/packages/core/test/lib/tracing/trace.test.ts index 8a7aa4e09191..064c41dc123a 100644 --- a/packages/core/test/lib/tracing/trace.test.ts +++ b/packages/core/test/lib/tracing/trace.test.ts @@ -47,6 +47,21 @@ describe('trace', () => { } }); + it('should return the same value as the callback if transactions are undefined', async () => { + // @ts-ignore we are force overriding the transaction return to be undefined + // The `startTransaction` types are actually wrong - it can return undefined + // if tracingExtensions are not enabled + jest.spyOn(hub, 'startTransaction').mockReturnValue(undefined); + try { + const result = await trace({ name: 'GET users/[id]' }, () => { + return callback(); + }); + expect(result).toEqual(expected); + } catch (e) { + expect(e).toEqual(expected); + } + }); + it('creates a transaction', async () => { let ref: any = undefined; client.on('finishTransaction', transaction => { @@ -99,7 +114,9 @@ describe('trace', () => { }); try { await trace({ name: 'GET users/[id]' }, span => { - span.op = 'http.server'; + if (span) { + span.op = 'http.server'; + } return callback(); }); } catch (e) { @@ -138,7 +155,9 @@ describe('trace', () => { try { await trace({ name: 'GET users/[id]', parentSampled: true }, () => { return trace({ name: 'SELECT * from users' }, childSpan => { - childSpan.op = 'db.query'; + if (childSpan) { + childSpan.op = 'db.query'; + } return callback(); }); });