From fb0032d7723e8afc17905daacf10c4e0ecaa0813 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 8 Nov 2023 12:02:16 +0100 Subject: [PATCH 1/5] feat(tracing): Add span `origin` to trace context (#9472) This adds the span `origin` to transactions being sent via the trace context. --- packages/core/src/tracing/span.ts | 1 + .../tests/propagation.test.ts | 4 ++ .../tests/transactions.test.ts | 1 + .../test/integration/scope.test.ts | 1 + .../test/integration/transactions.test.ts | 60 ++++--------------- .../test/custom/transaction.test.ts | 2 + .../test/integration/scope.test.ts | 1 + .../test/integration/transactions.test.ts | 48 ++++----------- packages/tracing/test/span.test.ts | 1 + packages/tracing/test/transaction.test.ts | 2 + packages/types/src/context.ts | 2 + 11 files changed, 37 insertions(+), 86 deletions(-) diff --git a/packages/core/src/tracing/span.ts b/packages/core/src/tracing/span.ts index 27cd287a017e..be4e420fc8bc 100644 --- a/packages/core/src/tracing/span.ts +++ b/packages/core/src/tracing/span.ts @@ -332,6 +332,7 @@ export class Span implements SpanInterface { status: this.status, tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, trace_id: this.traceId, + origin: this.origin, }); } diff --git a/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts b/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts index 8dbcb590b331..d069fd299682 100644 --- a/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts +++ b/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts @@ -71,6 +71,7 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'http.status_code': 200, }, trace_id: traceId, + origin: 'auto.http.otel.http', }, }), }), @@ -93,6 +94,7 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'http.status_code': 200, }, trace_id: traceId, + origin: 'auto.http.otel.http', }, }), }), @@ -162,6 +164,7 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'http.status_code': 200, }, trace_id: traceId, + origin: 'auto.http.otel.http', }, }), }), @@ -184,6 +187,7 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'http.status_code': 200, }, trace_id: traceId, + origin: 'auto.http.otel.http', }, }), }), diff --git a/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts b/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts index f34beaa63926..b9241d5a2569 100644 --- a/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts +++ b/packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts @@ -36,6 +36,7 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'http.status_code': 200, }, trace_id: expect.any(String), + origin: 'auto.http.otel.http', }, }), diff --git a/packages/node-experimental/test/integration/scope.test.ts b/packages/node-experimental/test/integration/scope.test.ts index 5beb1b7ec06f..78579701e47e 100644 --- a/packages/node-experimental/test/integration/scope.test.ts +++ b/packages/node-experimental/test/integration/scope.test.ts @@ -92,6 +92,7 @@ describe('Integration | Scope', () => { span_id: spanId, status: 'ok', trace_id: traceId, + origin: 'manual', }, }), spans: [], diff --git a/packages/node-experimental/test/integration/transactions.test.ts b/packages/node-experimental/test/integration/transactions.test.ts index 2f6cea23c0fd..45dafa88916c 100644 --- a/packages/node-experimental/test/integration/transactions.test.ts +++ b/packages/node-experimental/test/integration/transactions.test.ts @@ -37,10 +37,6 @@ describe('Integration | Transactions', () => { metadata: { requestPath: 'test-path' }, }, span => { - if (!span) { - return; - } - Sentry.addBreadcrumb({ message: 'test breadcrumb 2', timestamp: 123456 }); span.setAttributes({ @@ -48,15 +44,11 @@ describe('Integration | Transactions', () => { }); const subSpan = Sentry.startInactiveSpan({ name: 'inner span 1' }); - subSpan?.end(); + subSpan.end(); Sentry.setTag('test.tag', 'test value'); Sentry.startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - Sentry.addBreadcrumb({ message: 'test breadcrumb 3', timestamp: 123456 }); innerSpan.setAttributes({ @@ -97,6 +89,7 @@ describe('Integration | Transactions', () => { span_id: expect.any(String), status: 'ok', trace_id: expect.any(String), + origin: 'auto.test', }, }, environment: 'production', @@ -189,10 +182,6 @@ describe('Integration | Transactions', () => { Sentry.addBreadcrumb({ message: 'test breadcrumb 1', timestamp: 123456 }); Sentry.startSpan({ op: 'test op', name: 'test name', source: 'task', origin: 'auto.test' }, span => { - if (!span) { - return; - } - Sentry.addBreadcrumb({ message: 'test breadcrumb 2', timestamp: 123456 }); span.setAttributes({ @@ -200,15 +189,11 @@ describe('Integration | Transactions', () => { }); const subSpan = Sentry.startInactiveSpan({ name: 'inner span 1' }); - subSpan?.end(); + subSpan.end(); Sentry.setTag('test.tag', 'test value'); Sentry.startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - Sentry.addBreadcrumb({ message: 'test breadcrumb 3', timestamp: 123456 }); innerSpan.setAttributes({ @@ -218,10 +203,6 @@ describe('Integration | Transactions', () => { }); Sentry.startSpan({ op: 'test op b', name: 'test name b' }, span => { - if (!span) { - return; - } - Sentry.addBreadcrumb({ message: 'test breadcrumb 2b', timestamp: 123456 }); span.setAttributes({ @@ -229,15 +210,11 @@ describe('Integration | Transactions', () => { }); const subSpan = Sentry.startInactiveSpan({ name: 'inner span 1b' }); - subSpan?.end(); + subSpan.end(); Sentry.setTag('test.tag', 'test value b'); Sentry.startSpan({ name: 'inner span 2b' }, innerSpan => { - if (!innerSpan) { - return; - } - Sentry.addBreadcrumb({ message: 'test breadcrumb 3b', timestamp: 123456 }); innerSpan.setAttributes({ @@ -268,6 +245,7 @@ describe('Integration | Transactions', () => { span_id: expect.any(String), status: 'ok', trace_id: expect.any(String), + origin: 'auto.test', }, }), spans: [ @@ -309,6 +287,7 @@ describe('Integration | Transactions', () => { span_id: expect.any(String), status: 'ok', trace_id: expect.any(String), + origin: 'manual', }, }), spans: [ @@ -362,19 +341,11 @@ describe('Integration | Transactions', () => { context.with( trace.setSpanContext(setPropagationContextOnContext(context.active(), propagationContext), spanContext), () => { - Sentry.startSpan({ op: 'test op', name: 'test name', source: 'task', origin: 'auto.test' }, span => { - if (!span) { - return; - } - + Sentry.startSpan({ op: 'test op', name: 'test name', source: 'task', origin: 'auto.test' }, () => { const subSpan = Sentry.startInactiveSpan({ name: 'inner span 1' }); - subSpan?.end(); + subSpan.end(); - Sentry.startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - }); + Sentry.startSpan({ name: 'inner span 2' }, () => {}); }); }, ); @@ -395,6 +366,7 @@ describe('Integration | Transactions', () => { parent_span_id: parentSpanId, status: 'ok', trace_id: traceId, + origin: 'auto.test', }, }), // spans are circular (they have a reference to the transaction), which leads to jest choking on this @@ -481,20 +453,12 @@ describe('Integration | Transactions', () => { let innerSpan1Id: string | undefined; let innerSpan2Id: string | undefined; - void Sentry.startSpan({ name: 'test name' }, async span => { - if (!span) { - return; - } - + void Sentry.startSpan({ name: 'test name' }, async () => { const subSpan = Sentry.startInactiveSpan({ name: 'inner span 1' }); innerSpan1Id = subSpan?.spanContext().spanId; - subSpan?.end(); + subSpan.end(); Sentry.startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - innerSpan2Id = innerSpan.spanContext().spanId; }); diff --git a/packages/opentelemetry/test/custom/transaction.test.ts b/packages/opentelemetry/test/custom/transaction.test.ts index 65f5f79a87eb..1c4f9f3eea81 100644 --- a/packages/opentelemetry/test/custom/transaction.test.ts +++ b/packages/opentelemetry/test/custom/transaction.test.ts @@ -28,6 +28,7 @@ describe('NodeExperimentalTransaction', () => { trace: { span_id: expect.any(String), trace_id: expect.any(String), + origin: 'manual', }, }, spans: [], @@ -106,6 +107,7 @@ describe('NodeExperimentalTransaction', () => { trace: { span_id: expect.any(String), trace_id: expect.any(String), + origin: 'manual', }, }, spans: [], diff --git a/packages/opentelemetry/test/integration/scope.test.ts b/packages/opentelemetry/test/integration/scope.test.ts index c028e1893d7a..16ff5e85ae37 100644 --- a/packages/opentelemetry/test/integration/scope.test.ts +++ b/packages/opentelemetry/test/integration/scope.test.ts @@ -98,6 +98,7 @@ describe('Integration | Scope', () => { span_id: spanId, status: 'ok', trace_id: traceId, + origin: 'manual', }, }), diff --git a/packages/opentelemetry/test/integration/transactions.test.ts b/packages/opentelemetry/test/integration/transactions.test.ts index 2a4de232cc1b..5174b577611a 100644 --- a/packages/opentelemetry/test/integration/transactions.test.ts +++ b/packages/opentelemetry/test/integration/transactions.test.ts @@ -37,10 +37,6 @@ describe('Integration | Transactions', () => { metadata: { requestPath: 'test-path' }, }, span => { - if (!span) { - return; - } - addBreadcrumb({ message: 'test breadcrumb 2', timestamp: 123456 }); span.setAttributes({ @@ -48,15 +44,11 @@ describe('Integration | Transactions', () => { }); const subSpan = startInactiveSpan({ name: 'inner span 1' }); - subSpan?.end(); + subSpan.end(); setTag('test.tag', 'test value'); startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - addBreadcrumb({ message: 'test breadcrumb 3', timestamp: 123456 }); innerSpan.setAttributes({ @@ -96,6 +88,7 @@ describe('Integration | Transactions', () => { span_id: expect.any(String), status: 'ok', trace_id: expect.any(String), + origin: 'auto.test', }, }, environment: 'production', @@ -186,10 +179,6 @@ describe('Integration | Transactions', () => { addBreadcrumb({ message: 'test breadcrumb 1', timestamp: 123456 }); startSpan({ op: 'test op', name: 'test name', source: 'task', origin: 'auto.test' }, span => { - if (!span) { - return; - } - addBreadcrumb({ message: 'test breadcrumb 2', timestamp: 123456 }); span.setAttributes({ @@ -197,15 +186,11 @@ describe('Integration | Transactions', () => { }); const subSpan = startInactiveSpan({ name: 'inner span 1' }); - subSpan?.end(); + subSpan.end(); setTag('test.tag', 'test value'); startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - addBreadcrumb({ message: 'test breadcrumb 3', timestamp: 123456 }); innerSpan.setAttributes({ @@ -215,10 +200,6 @@ describe('Integration | Transactions', () => { }); startSpan({ op: 'test op b', name: 'test name b' }, span => { - if (!span) { - return; - } - addBreadcrumb({ message: 'test breadcrumb 2b', timestamp: 123456 }); span.setAttributes({ @@ -226,15 +207,11 @@ describe('Integration | Transactions', () => { }); const subSpan = startInactiveSpan({ name: 'inner span 1b' }); - subSpan?.end(); + subSpan.end(); setTag('test.tag', 'test value b'); startSpan({ name: 'inner span 2b' }, innerSpan => { - if (!innerSpan) { - return; - } - addBreadcrumb({ message: 'test breadcrumb 3b', timestamp: 123456 }); innerSpan.setAttributes({ @@ -265,6 +242,7 @@ describe('Integration | Transactions', () => { span_id: expect.any(String), status: 'ok', trace_id: expect.any(String), + origin: 'auto.test', }, }), spans: [ @@ -306,6 +284,7 @@ describe('Integration | Transactions', () => { span_id: expect.any(String), status: 'ok', trace_id: expect.any(String), + origin: 'manual', }, }), spans: [ @@ -359,19 +338,11 @@ describe('Integration | Transactions', () => { context.with( trace.setSpanContext(setPropagationContextOnContext(context.active(), propagationContext), spanContext), () => { - startSpan({ op: 'test op', name: 'test name', source: 'task', origin: 'auto.test' }, span => { - if (!span) { - return; - } - + startSpan({ op: 'test op', name: 'test name', source: 'task', origin: 'auto.test' }, () => { const subSpan = startInactiveSpan({ name: 'inner span 1' }); - subSpan?.end(); + subSpan.end(); - startSpan({ name: 'inner span 2' }, innerSpan => { - if (!innerSpan) { - return; - } - }); + startSpan({ name: 'inner span 2' }, () => {}); }); }, ); @@ -392,6 +363,7 @@ describe('Integration | Transactions', () => { parent_span_id: parentSpanId, status: 'ok', trace_id: traceId, + origin: 'auto.test', }, }), // spans are circular (they have a reference to the transaction), which leads to jest choking on this diff --git a/packages/tracing/test/span.test.ts b/packages/tracing/test/span.test.ts index ca16a1395e3e..ffa57d615d7b 100644 --- a/packages/tracing/test/span.test.ts +++ b/packages/tracing/test/span.test.ts @@ -327,6 +327,7 @@ describe('Span', () => { expect(context).toStrictEqual({ span_id: 'd', trace_id: 'c', + origin: 'manual', }); }); }); diff --git a/packages/tracing/test/transaction.test.ts b/packages/tracing/test/transaction.test.ts index fed6a63ea684..a8a8557150a1 100644 --- a/packages/tracing/test/transaction.test.ts +++ b/packages/tracing/test/transaction.test.ts @@ -153,6 +153,7 @@ describe('`Transaction` class', () => { trace: { span_id: transaction.spanId, trace_id: transaction.traceId, + origin: 'manual', }, }, }), @@ -179,6 +180,7 @@ describe('`Transaction` class', () => { trace: { span_id: transaction.spanId, trace_id: transaction.traceId, + origin: 'manual', }, }, }), diff --git a/packages/types/src/context.ts b/packages/types/src/context.ts index d52b674e2cbe..8dadb959a97d 100644 --- a/packages/types/src/context.ts +++ b/packages/types/src/context.ts @@ -1,4 +1,5 @@ import type { Primitive } from './misc'; +import type { SpanOrigin } from './span'; export type Context = Record; @@ -101,6 +102,7 @@ export interface TraceContext extends Record { status?: string; tags?: { [key: string]: Primitive }; trace_id: string; + origin?: SpanOrigin; } export interface CloudResourceContext extends Record { From 62e562eea68f33f3738d285c84477f77399fbe00 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 8 Nov 2023 15:30:46 +0100 Subject: [PATCH 2/5] fix(nextjs): Flush servercomponent events for edge (#9487) --- .../app/edge-server-components/error/page.tsx | 7 +++++++ .../nextjs-app-dir/tests/edge.test.ts | 12 ++++++++++++ .../src/common/wrapServerComponentWithSentry.ts | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/app/edge-server-components/error/page.tsx create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/app/edge-server-components/error/page.tsx b/packages/e2e-tests/test-applications/nextjs-app-dir/app/edge-server-components/error/page.tsx new file mode 100644 index 000000000000..35d15616fd1c --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/app/edge-server-components/error/page.tsx @@ -0,0 +1,7 @@ +export const dynamic = 'force-dynamic'; + +export const runtime = 'edge'; + +export default async function Page() { + throw new Error('Edge Server Component Error'); +} diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts new file mode 100644 index 000000000000..26a9e7fed310 --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge.test.ts @@ -0,0 +1,12 @@ +import { test, expect } from '@playwright/test'; +import { waitForError } from '../event-proxy-server'; + +test('Should record exceptions for faulty edge server components', async ({ page }) => { + const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Edge Server Component Error'; + }); + + await page.goto('/edge-server-components/error'); + + expect(await errorEventPromise).toBeDefined(); +}); diff --git a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts index b39ca674af6e..360b169c7b37 100644 --- a/packages/nextjs/src/common/wrapServerComponentWithSentry.ts +++ b/packages/nextjs/src/common/wrapServerComponentWithSentry.ts @@ -1,6 +1,7 @@ import { addTracingExtensions, captureException, + flush, getCurrentHub, runWithAsyncContext, startTransaction, @@ -81,6 +82,7 @@ export function wrapServerComponentWithSentry any> maybePromiseResult = originalFunction.apply(thisArg, args); } catch (e) { handleErrorCase(e); + void flush(); throw e; } @@ -94,12 +96,14 @@ export function wrapServerComponentWithSentry any> handleErrorCase(e); }, ); + void flush(); // It is very important that we return the original promise here, because Next.js attaches various properties // to that promise and will throw if they are not on the returned value. return maybePromiseResult; } else { transaction.finish(); + void flush(); return maybePromiseResult; } }); From 8f862a901f2d086a5c3a9d4f3740ff72ec9f69b6 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 8 Nov 2023 15:31:12 +0100 Subject: [PATCH 3/5] fix(deno): Emit .mjs files (#9485) --- packages/deno/package.json | 3 +-- packages/deno/rollup.config.js | 2 +- packages/deno/test/example.ts | 2 +- packages/deno/test/mod.test.ts | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/deno/package.json b/packages/deno/package.json index 0628ba62a73e..9390486edb15 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -6,7 +6,6 @@ "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/deno", "author": "Sentry", "license": "MIT", - "main": "build/index.js", "module": "build/index.js", "types": "build/index.d.ts", "publishConfig": { @@ -51,7 +50,7 @@ "pretest": "run-s deno-types test:build", "test": "run-s install:deno test:types test:unit", "test:build": "tsc -p tsconfig.test.types.json && rollup -c rollup.test.config.js", - "test:types": "deno check ./build/index.js", + "test:types": "deno check ./build/index.mjs", "test:unit": "deno test --allow-read --allow-run", "test:unit:update": "deno test --allow-read --allow-write --allow-run -- --update", "yalc:publish": "ts-node ../../scripts/prepack.ts && yalc publish build --push" diff --git a/packages/deno/rollup.config.js b/packages/deno/rollup.config.js index d79b77478053..bf76973b9801 100644 --- a/packages/deno/rollup.config.js +++ b/packages/deno/rollup.config.js @@ -7,7 +7,7 @@ export default defineConfig({ input: ['src/index.ts'], treeshake: 'smallest', output: { - dir: 'build', + file: 'build/index.mjs', sourcemap: true, preserveModules: false, strict: false, diff --git a/packages/deno/test/example.ts b/packages/deno/test/example.ts index 6f93bd288afd..0ac351f1fc50 100644 --- a/packages/deno/test/example.ts +++ b/packages/deno/test/example.ts @@ -1,4 +1,4 @@ -import * as Sentry from '../build/index.js'; +import * as Sentry from '../build/index.mjs'; Sentry.init({ dsn: 'https://1234@some-domain.com/4505526893805568', diff --git a/packages/deno/test/mod.test.ts b/packages/deno/test/mod.test.ts index f457033efe96..cf093af034fe 100644 --- a/packages/deno/test/mod.test.ts +++ b/packages/deno/test/mod.test.ts @@ -3,7 +3,7 @@ import { assertSnapshot } from 'https://deno.land/std@0.202.0/testing/snapshot.t import type { sentryTypes } from '../build-test/index.js'; import { sentryUtils } from '../build-test/index.js'; -import { defaultIntegrations, DenoClient, Hub, Scope } from '../build/index.js'; +import { defaultIntegrations, DenoClient, Hub, Scope } from '../build/index.mjs'; import { getNormalizedEvent } from './normalize.ts'; import { makeTestTransport } from './transport.ts'; From 7bb2161d0d8b155696df33604c0d742cbccc6270 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 8 Nov 2023 15:31:25 +0100 Subject: [PATCH 4/5] docs: Update Deno SDK readme (#9486) --- packages/deno/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/deno/README.md b/packages/deno/README.md index 5be987a249af..4246a367ad81 100644 --- a/packages/deno/README.md +++ b/packages/deno/README.md @@ -12,6 +12,7 @@ ## Links +- [SDK on Deno registry](https://deno.land/x/sentry) - [Official SDK Docs](https://docs.sentry.io/quickstart/) - [TypeDoc](http://getsentry.github.io/sentry-javascript/) @@ -23,6 +24,10 @@ To use this SDK, call `Sentry.init(options)` as early as possible in the main en hook into the environment. Note that you can turn off almost all side effects using the respective options. ```javascript +// Import from the Deno registry +import * as Sentry from "https://deno.land/x/sentry/index.mjs"; + +// or import from npm registry import * as Sentry from 'npm:@sentry/deno'; Sentry.init({ @@ -31,7 +36,7 @@ Sentry.init({ }); ``` -To set context information or send manual events, use the exported functions of `@sentry/deno`. Note that these +To set context information or send manual events, use the exported functions of the Deno SDK. Note that these functions will not perform any action before you have called `init()`: ```javascript From 3b09ca99f0d1ddc7a0486dcf563e3f670015174b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 8 Nov 2023 15:53:55 +0100 Subject: [PATCH 5/5] meta: Update CHANGELOG for 7.79.0 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cd0a7a30c7d..a231f2e7e854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 7.79.0 + +- feat(tracing): Add span `origin` to trace context (#9472) +- fix(deno): Emit .mjs files (#9485) +- fix(nextjs): Flush servercomponent events for edge (#9487) + ## 7.78.0 ### Important Changes