From 97e79d9c07ccbcb6c34d35cd480285d07a2022d5 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Thu, 30 Oct 2025 12:20:59 +0100 Subject: [PATCH 1/2] test(node-core): Proof that withMonitor doesn't create a new trace --- .../test/integration/transactions.test.ts | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/packages/node-core/test/integration/transactions.test.ts b/packages/node-core/test/integration/transactions.test.ts index 7b13a400dedb..35a551aeecd5 100644 --- a/packages/node-core/test/integration/transactions.test.ts +++ b/packages/node-core/test/integration/transactions.test.ts @@ -1,5 +1,5 @@ import { context, trace, TraceFlags } from '@opentelemetry/api'; -import type { TransactionEvent } from '@sentry/core'; +import type { ErrorEvent, TransactionEvent } from '@sentry/core'; import { debug, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; import { afterEach, describe, expect, it, vi } from 'vitest'; import * as Sentry from '../../src'; @@ -674,4 +674,65 @@ describe('Integration | Transactions', () => { expect(spans).toContainEqual(expect.objectContaining({ description: 'inner span 1' })); expect(spans).toContainEqual(expect.objectContaining({ description: 'inner span 2' })); }); + + it('withMonitor should use the same traces for each monitor', async () => { + const sendEvents: ErrorEvent[] = []; + const transactionEvents: TransactionEvent[] = []; + const beforeSendTransaction = vi.fn((event: TransactionEvent) => { + transactionEvents.push(event); + return null; + }); + const beforeSend = vi.fn((event: ErrorEvent) => { + sendEvents.push(event); + return null; + }); + + mockSdkInit({ + tracesSampleRate: 1, + beforeSendTransaction, + beforeSend, + debug: true, + }); + + const client = Sentry.getClient(); + const errorMessage = 'Error outside withMonitor'; + + Sentry.startSpan({ name: 'span outside error' }, () => { + Sentry.withMonitor('cron-job-1', () => Sentry.startSpan({ name: 'inner span 1' }, () => undefined)); + + try { + throw new Error(errorMessage); + } catch (e) { + Sentry.startSpan({ name: 'span inside error' }, () => undefined); + Sentry.captureException(e); + } + + Sentry.withMonitor('cron-job-2', () => { + Sentry.startSpan({ name: 'inner span 2' }, () => undefined); + }); + }); + + await client?.flush(); + + const transactionTraceId = transactionEvents[0]?.contexts?.trace?.trace_id; + const errorTraceId = sendEvents[0]?.contexts?.trace?.trace_id; + + expect(beforeSendTransaction).toHaveBeenCalledTimes(1); + expect(beforeSend).toHaveBeenCalledTimes(1); + expect(transactionEvents).toHaveLength(1); + expect(transactionTraceId).toBe(errorTraceId); + expect(transactionEvents[0]?.spans).toHaveLength(3); + expect(transactionEvents).toMatchObject([ + { + spans: [{ description: 'inner span 1' }, { description: 'span inside error' }, { description: 'inner span 2' }], + }, + ]); + expect(sendEvents).toMatchObject([ + { + exception: { + values: [{ value: errorMessage }], + }, + }, + ]); + }); }); From 56a53c37d9a5ab5e50cff1b1371b074fd1520042 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Tue, 4 Nov 2025 16:24:38 +0100 Subject: [PATCH 2/2] test: useRealTimers after each test to reset fake timer --- packages/node-core/test/integration/transactions.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/node-core/test/integration/transactions.test.ts b/packages/node-core/test/integration/transactions.test.ts index 35a551aeecd5..e00cbc8580d1 100644 --- a/packages/node-core/test/integration/transactions.test.ts +++ b/packages/node-core/test/integration/transactions.test.ts @@ -9,6 +9,7 @@ describe('Integration | Transactions', () => { afterEach(() => { vi.restoreAllMocks(); cleanupOtel(); + vi.useRealTimers(); }); it('correctly creates transaction & spans', async () => {