From b6a7208bfd9e61f4ce0400f782c4581724dc6a16 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Thu, 16 Apr 2026 13:39:58 +0200 Subject: [PATCH 1/2] first benchmark --- packages/core/package.json | 1 + .../test/bench/capture-exception.bench.ts | 53 +++++++++++++ packages/core/test/bench/startSpan.bench.ts | 75 +++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 packages/core/test/bench/capture-exception.bench.ts create mode 100644 packages/core/test/bench/startSpan.bench.ts diff --git a/packages/core/package.json b/packages/core/package.json index f898caa41e31..f54a5e984958 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -54,6 +54,7 @@ "lint:fix": "OXLINT_TSGOLINT_DANGEROUSLY_SUPPRESS_PROGRAM_DIAGNOSTICS=true oxlint . --fix --type-aware", "lint": "OXLINT_TSGOLINT_DANGEROUSLY_SUPPRESS_PROGRAM_DIAGNOSTICS=true oxlint . --type-aware", "lint:es-compatibility": "es-check es2020 ./build/cjs/*.js && es-check es2020 ./build/esm/*.js --module", + "bench": "vitest bench", "test": "vitest run", "test:watch": "vitest --watch", "yalc:publish": "yalc publish --push --sig" diff --git a/packages/core/test/bench/capture-exception.bench.ts b/packages/core/test/bench/capture-exception.bench.ts new file mode 100644 index 000000000000..a4f8dab1697f --- /dev/null +++ b/packages/core/test/bench/capture-exception.bench.ts @@ -0,0 +1,53 @@ +import { bench, describe } from 'vitest'; +import { + addBreadcrumb, + captureException, + getCurrentScope, + getIsolationScope, + setCurrentClient, +} from '../../src'; +import { getDefaultTestClientOptions, TestClient } from '../mocks/client'; +import { clearGlobalScope } from '../testutils'; + +function setupClient() { + clearGlobalScope(); + getCurrentScope().clear(); + getIsolationScope().clear(); + + const client = new TestClient( + getDefaultTestClientOptions({ + dsn: 'https://username@domain/123', + enableSend: true, + release: '1.0.0', + environment: 'production', + }), + ); + setCurrentClient(client); + client.init(); + return client; +} + +describe('captureException - minimal scope', () => { + setupClient(); + + bench('captureException(new Error(...))', () => { + captureException(new Error('Something went wrong')); + }); +}); + +describe('captureException - realistic scope', () => { + setupClient(); + + getCurrentScope().setUser({ id: '123', email: 'user@example.com' }); + getCurrentScope().setTag('service', 'api-gateway'); + getCurrentScope().setTag('region', 'us-east-1'); + getCurrentScope().setTag('version', '2.1.0'); + getCurrentScope().setExtra('request_id', 'req-abc-123'); + for (let i = 0; i < 10; i++) { + addBreadcrumb({ message: `Action ${i}`, category: 'http', level: 'info' }); + } + + bench('captureException(new Error(...))', () => { + captureException(new Error('Something went wrong')); + }); +}); diff --git a/packages/core/test/bench/startSpan.bench.ts b/packages/core/test/bench/startSpan.bench.ts new file mode 100644 index 000000000000..9f002c005109 --- /dev/null +++ b/packages/core/test/bench/startSpan.bench.ts @@ -0,0 +1,75 @@ +import { bench, describe } from 'vitest'; +import { + addBreadcrumb, + getCurrentScope, + getIsolationScope, + setCurrentClient, + startSpan, +} from '../../src'; +import { getDefaultTestClientOptions, TestClient } from '../mocks/client'; +import { clearGlobalScope } from '../testutils'; + +function setupClient() { + clearGlobalScope(); + getCurrentScope().clear(); + getIsolationScope().clear(); + + const client = new TestClient( + getDefaultTestClientOptions({ + dsn: 'https://username@domain/123', + enableSend: true, + tracesSampleRate: 1, + release: '1.0.0', + environment: 'production', + }), + ); + setCurrentClient(client); + client.init(); + return client; +} + +function addRealisticScopeData() { + getCurrentScope().setUser({ id: '123', email: 'user@example.com' }); + getCurrentScope().setTag('service', 'api-gateway'); + getCurrentScope().setTag('region', 'us-east-1'); + getCurrentScope().setTag('version', '2.1.0'); + getCurrentScope().setExtra('request_id', 'req-abc-123'); + for (let i = 0; i < 10; i++) { + addBreadcrumb({ message: `Action ${i}`, category: 'http', level: 'info' }); + } +} + +describe('startSpan pipeline - realistic scope', () => { + setupClient(); + addRealisticScopeData(); + + bench('single root span', () => { + startSpan({ name: 'GET /api/users', op: 'http.server' }, () => { + // span lifecycle only + }); + }); + + bench('root span + 5 child spans', () => { + startSpan({ name: 'GET /api/users', op: 'http.server' }, () => { + for (let i = 0; i < 5; i++) { + startSpan({ name: `SELECT * FROM users WHERE id = $${i + 1}`, op: 'db' }, span => { + span.setAttribute('db.system', 'postgresql'); + span.setAttribute('db.name', 'mydb'); + }); + } + }); + }); + + bench('root span + 10 child spans', () => { + startSpan({ name: 'GET /api/users', op: 'http.server' }, () => { + for (let i = 0; i < 10; i++) { + startSpan( + { name: i < 5 ? `db.query.${i}` : `http.request.${i}`, op: i < 5 ? 'db' : 'http.client' }, + span => { + span.setAttribute('key', 'value'); + }, + ); + } + }); + }); +}); From b6570e22708da13d46371158df8dffda166a5c5c Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Thu, 16 Apr 2026 13:46:53 +0200 Subject: [PATCH 2/2] scenarios with more spans --- packages/core/test/bench/startSpan.bench.ts | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/core/test/bench/startSpan.bench.ts b/packages/core/test/bench/startSpan.bench.ts index 9f002c005109..b090d13c994a 100644 --- a/packages/core/test/bench/startSpan.bench.ts +++ b/packages/core/test/bench/startSpan.bench.ts @@ -72,4 +72,34 @@ describe('startSpan pipeline - realistic scope', () => { } }); }); + + bench('root span + 100 child spans', () => { + startSpan({ name: 'GET /api/users', op: 'http.server' }, () => { + for (let i = 0; i < 100; i++) { + startSpan({ name: `operation.${i}`, op: 'db' }, span => { + span.setAttribute('db.system', 'postgresql'); + }); + } + }); + }); + + bench('root span + 1000 child spans', () => { + startSpan({ name: 'GET /api/users', op: 'http.server' }, () => { + for (let i = 0; i < 1000; i++) { + startSpan({ name: `operation.${i}`, op: 'db' }, span => { + span.setAttribute('db.system', 'postgresql'); + }); + } + }); + }); + + bench('root span + 10000 child spans', () => { + startSpan({ name: 'GET /api/users', op: 'http.server' }, () => { + for (let i = 0; i < 10000; i++) { + startSpan({ name: `operation.${i}`, op: 'db' }, span => { + span.setAttribute('db.system', 'postgresql'); + }); + } + }); + }); });