From 0f05fea45bf195b1a4fec4d23993bbf8a1f9c971 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 22 Jul 2026 15:20:58 +0200 Subject: [PATCH 1/2] feat: Add `url.full` and `url.path` attributes to `http.server` spans --- .../tests/tracing.server.test.ts | 2 ++ packages/astro/src/server/middleware.ts | 3 +++ .../src/integrations/http/server-subscription.ts | 7 ++++++- packages/elysia/package.json | 3 ++- packages/elysia/src/withElysia.ts | 3 +++ .../wrapApiHandlerWithSentry.ts | 7 +++++++ .../nextjs/src/edge/wrapApiHandlerWithSentry.ts | 15 +++++++++++++++ .../http/httpServerSpansIntegration.ts | 4 ++++ .../src/server/createServerInstrumentation.ts | 2 ++ packages/remix/src/server/instrumentServer.ts | 5 ++++- .../src/server/integrations/tracing-channel.ts | 15 ++++++++++++++- packages/sveltekit/src/server-common/handle.ts | 6 ++++++ 12 files changed, 68 insertions(+), 4 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/tests/tracing.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/tests/tracing.server.test.ts index c6de70d0e6a1..9c2668a7c6c8 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/tests/tracing.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/tests/tracing.server.test.ts @@ -82,6 +82,8 @@ test('server pageload request span has nested request span for sub request', asy 'http.method': 'GET', 'http.route': '/api/users', 'http.url': 'http://localhost:3030/api/users', + 'url.full': 'http://localhost:3030/api/users', + 'url.path': '/api/users', 'sentry.op': 'http.server', 'sentry.origin': 'auto.http.sveltekit', 'sentry.source': 'route', diff --git a/packages/astro/src/server/middleware.ts b/packages/astro/src/server/middleware.ts index fc606654e389..5631338bd63b 100644 --- a/packages/astro/src/server/middleware.ts +++ b/packages/astro/src/server/middleware.ts @@ -1,4 +1,5 @@ /* eslint-disable max-lines */ +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import type { Span, SpanAttributes } from '@sentry/core'; import { addNonEnumerableProperty, @@ -218,6 +219,8 @@ async function instrumentRequestStartHttpServerSpan( [SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method, // This is here for backwards compatibility, we used to set this here before method, + [URL_FULL]: ctx.url.href, + [URL_PATH]: ctx.url.pathname, url: stripUrlQueryAndFragment(ctx.url.href), ...httpHeadersToSpanAttributes( winterCGHeadersToDict(request.headers), diff --git a/packages/core/src/integrations/http/server-subscription.ts b/packages/core/src/integrations/http/server-subscription.ts index 86d7359aa119..7517b88509c9 100644 --- a/packages/core/src/integrations/http/server-subscription.ts +++ b/packages/core/src/integrations/http/server-subscription.ts @@ -1,3 +1,4 @@ +// oxlint-disable max-lines /** * Provide the `http.server.request.start` subscription function that we use * to instrument incoming HTTP requests that use the `node:http` module. @@ -40,6 +41,7 @@ import { safeMathRandom } from '../../utils/randomSafeContext'; import { SPAN_KIND } from '../../spanKind'; import type { SpanAttributes } from '../../types/span'; import type { SpanStatus } from '../../types/spanStatus'; +import { HTTP_URL, URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; // Tree-shakable guard to remove all code related to tracing declare const __SENTRY_TRACING__: boolean; @@ -298,7 +300,10 @@ function buildServerSpanWrap( 'net.peer.port': remotePort, 'sentry.http.prefetch': isKnownPrefetchRequest(request) || undefined, // Old Semantic Conventions attributes for compatibility - 'http.url': fullUrl, + [URL_FULL]: fullUrl, + [URL_PATH]: urlObj?.pathname ?? httpTargetWithoutQueryFragment, + // oxlint-disable-next-line typescript-eslint(no-deprecated) + [HTTP_URL]: fullUrl, 'http.method': method, 'http.target': urlObj ? `${urlObj.pathname}${urlObj.search}` : httpTargetWithoutQueryFragment, 'http.host': host, diff --git a/packages/elysia/package.json b/packages/elysia/package.json index 932279f74b22..8919adf3cf2b 100644 --- a/packages/elysia/package.json +++ b/packages/elysia/package.json @@ -33,7 +33,8 @@ }, "dependencies": { "@sentry/bun": "10.67.0", - "@sentry/core": "10.67.0" + "@sentry/core": "10.67.0", + "@sentry/conventions": "^0.16.0" }, "peerDependencies": { "elysia": "^1.4.0" diff --git a/packages/elysia/src/withElysia.ts b/packages/elysia/src/withElysia.ts index 84a496300d01..9deaf3706c19 100644 --- a/packages/elysia/src/withElysia.ts +++ b/packages/elysia/src/withElysia.ts @@ -1,3 +1,4 @@ +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import type { Span } from '@sentry/core'; import { captureException, @@ -198,6 +199,8 @@ export function withElysia(app: T, options: ElysiaHandlerOp attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN, [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', + [URL_FULL]: request.url, + [URL_PATH]: new URL(request.url).pathname, }, }, rootSpan => { diff --git a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts index 60a9b0d617f7..809459790a14 100644 --- a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts @@ -5,7 +5,9 @@ import { getActiveSpan, httpRequestToRequestData, isString, + isURLObjectRelative, objectify, + parseStringToURLObject, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, setHttpStatus, @@ -16,6 +18,7 @@ import type { NextApiRequest } from 'next'; import type { AugmentedNextApiResponse, NextApiHandler } from '../types'; import { flushSafelyWithTimeout, waitUntil } from '../utils/responseEnd'; import { dropNextjsRootContext, escapeNextjsTracing } from '../utils/tracingUtils'; +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; export type AugmentedNextApiRequest = NextApiRequest & { __withSentry_applied__?: boolean; @@ -78,6 +81,8 @@ export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameteriz isolationScope.setSDKProcessingMetadata({ normalizedRequest }); isolationScope.setTransactionName(`${reqMethod}${parameterizedRoute}`); + const urlObject = req.url ? parseStringToURLObject(req.url) : undefined; + return startSpanManual( { name: `${reqMethod}${parameterizedRoute}`, @@ -86,6 +91,8 @@ export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameteriz attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nextjs', + [URL_FULL]: urlObject && !isURLObjectRelative(urlObject) ? urlObject.href : undefined, + [URL_PATH]: urlObject?.pathname, }, }, async span => { diff --git a/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts index 528c174e45fa..1aac5499130f 100644 --- a/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts @@ -4,10 +4,13 @@ import { getCurrentScope, getRootSpan, handleCallbackErrors, + isURLObjectRelative, + parseStringToURLObject, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, setCapturedScopesOnSpan, + spanToJSON, startSpan, winterCGRequestToRequestData, withIsolationScope, @@ -15,6 +18,7 @@ import { import { addHeadersAsAttributes } from '../common/utils/addHeadersAsAttributes'; import { flushSafelyWithTimeout, waitUntil } from '../common/utils/responseEnd'; import type { EdgeRouteHandler } from './types'; +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; /** * Wraps a Next.js edge route handler with Sentry error and performance instrumentation. @@ -48,6 +52,13 @@ export function wrapApiHandlerWithSentry( // If there is an active span, it likely means that the automatic Next.js OTEL instrumentation worked and we can // rely on that for parameterization. + const urlObject = req instanceof Request ? parseStringToURLObject(req.url) : undefined; + + const urlAttributes = { + [URL_FULL]: urlObject && !isURLObjectRelative(urlObject) ? urlObject.href : undefined, + [URL_PATH]: urlObject?.pathname, + }; + const activeSpan = getActiveSpan(); if (activeSpan) { spanName = `handler (${parameterizedRoute})`; @@ -55,12 +66,15 @@ export function wrapApiHandlerWithSentry( const rootSpan = getRootSpan(activeSpan); if (rootSpan) { + const rootSpanAttributes = spanToJSON(rootSpan).data; rootSpan.updateName( req instanceof Request ? `${req.method} ${parameterizedRoute}` : `handler ${parameterizedRoute}`, ); rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', + [URL_FULL]: rootSpanAttributes[URL_FULL] ?? urlAttributes[URL_FULL], + [URL_PATH]: rootSpanAttributes[URL_PATH] ?? urlAttributes[URL_PATH], ...headerAttributes, }); setCapturedScopesOnSpan(rootSpan, currentScope, isolationScope); @@ -78,6 +92,7 @@ export function wrapApiHandlerWithSentry( attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.wrap_api_handler', + ...urlAttributes, ...headerAttributes, }, }, diff --git a/packages/node/src/integrations/http/httpServerSpansIntegration.ts b/packages/node/src/integrations/http/httpServerSpansIntegration.ts index 33e02c6cc9e9..a09a1759fd84 100644 --- a/packages/node/src/integrations/http/httpServerSpansIntegration.ts +++ b/packages/node/src/integrations/http/httpServerSpansIntegration.ts @@ -23,6 +23,8 @@ import { NET_PEER_PORT, NET_TRANSPORT, SENTRY_HTTP_PREFETCH, + URL_FULL, + URL_PATH, } from '@sentry/conventions/attributes'; import type { Event, @@ -172,6 +174,8 @@ const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.http', [SENTRY_HTTP_PREFETCH]: isKnownPrefetchRequest(request) || undefined, + [URL_FULL]: fullUrl, + [URL_PATH]: urlObj?.pathname ?? httpTargetWithoutQueryFragment, // Old Semantic Conventions attributes - added for compatibility with what `@opentelemetry/instrumentation-http` output before /* eslint-disable typescript/no-deprecated */ [HTTP_URL]: fullUrl, diff --git a/packages/react-router/src/server/createServerInstrumentation.ts b/packages/react-router/src/server/createServerInstrumentation.ts index 982345db691d..be826c3d7f5d 100644 --- a/packages/react-router/src/server/createServerInstrumentation.ts +++ b/packages/react-router/src/server/createServerInstrumentation.ts @@ -65,6 +65,8 @@ export function createSentryServerInstrumentation( [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', + [URL_FULL]: info.request.url, + [URL_PATH]: pathname, }); try { diff --git a/packages/remix/src/server/instrumentServer.ts b/packages/remix/src/server/instrumentServer.ts index a9003c925803..8c157d697687 100644 --- a/packages/remix/src/server/instrumentServer.ts +++ b/packages/remix/src/server/instrumentServer.ts @@ -40,6 +40,7 @@ import { createRoutes, getTransactionName, isCloudflareEnv } from '../utils/util import { extractData, isResponse, json } from '../utils/vendor/response'; import { captureRemixServerException, errorHandleDataFunction } from './errors'; import { generateSentryServerTimingHeader, injectServerTimingHeaderValue } from './serverTimingTracePropagation'; +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; type AppData = unknown; type RemixRequest = Parameters[0]; @@ -337,8 +338,8 @@ function wrapRequestHandler ServerBuild | Promise DEBUG_BUILD && debug.warn('Failed to normalize Remix request'); } + const url = new URL(request.url); if (options?.instrumentTracing && resolvedRoutes) { - const url = new URL(request.url); [name, source] = getTransactionName(resolvedRoutes, url); isolationScope.setTransactionName(name); @@ -375,6 +376,8 @@ function wrapRequestHandler ServerBuild | Promise [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.remix', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source, [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', + [URL_FULL]: url.href, + [URL_PATH]: url.pathname, method: request.method, ...httpHeadersToSpanAttributes( winterCGHeadersToDict(request.headers), diff --git a/packages/remix/src/server/integrations/tracing-channel.ts b/packages/remix/src/server/integrations/tracing-channel.ts index 624ab8dad39c..04d5e4a21269 100644 --- a/packages/remix/src/server/integrations/tracing-channel.ts +++ b/packages/remix/src/server/integrations/tracing-channel.ts @@ -3,6 +3,8 @@ import type { Span, SpanAttributes } from '@sentry/core'; import { getActiveSpan, isObjectLike, + isURLObjectRelative, + parseStringToURLObject, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_KIND, @@ -10,7 +12,15 @@ import { waitForTracingChannelBinding, } from '@sentry/core'; import { bindTracingChannelToSpan } from '@sentry/server-utils'; -import { CODE_FUNCTION, HTTP_METHOD, HTTP_ROUTE, HTTP_STATUS_CODE, HTTP_URL } from '@sentry/conventions/attributes'; +import { + CODE_FUNCTION, + HTTP_METHOD, + HTTP_ROUTE, + HTTP_STATUS_CODE, + HTTP_URL, + URL_FULL, + URL_PATH, +} from '@sentry/conventions/attributes'; import { remixChannels } from '@sentry/server-utils/orchestrion'; const ORIGIN = 'auto.http.orchestrion.remix'; @@ -64,6 +74,9 @@ function getRequestAttributes(request: unknown): SpanAttributes { if (typeof url === 'string') { // oxlint-disable-next-line typescript/no-deprecated attributes[HTTP_URL] = url; + const urlObject = parseStringToURLObject(url); + attributes[URL_FULL] = urlObject && !isURLObjectRelative(urlObject) ? urlObject.href : undefined; + attributes[URL_PATH] = urlObject?.pathname; } return attributes; } diff --git a/packages/sveltekit/src/server-common/handle.ts b/packages/sveltekit/src/server-common/handle.ts index 2e30253aaaf2..5ebdbf97d98b 100644 --- a/packages/sveltekit/src/server-common/handle.ts +++ b/packages/sveltekit/src/server-common/handle.ts @@ -23,6 +23,7 @@ import { import type { Handle, ResolveOptions } from '@sveltejs/kit'; import { DEBUG_BUILD } from '../common/debug-build'; import { getTracePropagationData, sendErrorToSentry } from './utils'; +import { HTTP_URL, URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; export type SentryHandleOptions = { /** @@ -178,6 +179,9 @@ async function instrumentHandle( [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeName ? 'route' : 'url', 'sveltekit.tracing.original_name': originalName, + // oxlint-disable-next-line typescript-eslint(no-deprecated) + [URL_FULL]: kitRootSpanAttributes[URL_FULL] ?? kitRootSpanAttributes[HTTP_URL] ?? event.url.href, + [URL_PATH]: kitRootSpanAttributes[URL_PATH] ?? event.url.pathname, ...httpHeadersToSpanAttributes( winterCGHeadersToDict(event.request.headers), getClient()?.getDataCollectionOptions() ?? false, @@ -207,6 +211,8 @@ async function instrumentHandle( [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url', 'http.method': event.request.method, + [URL_FULL]: event.url.href, + [URL_PATH]: event.url.pathname, ...httpHeadersToSpanAttributes( winterCGHeadersToDict(event.request.headers), getClient()?.getDataCollectionOptions() ?? false, From 40b17428e10c3bdc7203cce65fa256d298b66510 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 22 Jul 2026 17:50:33 +0200 Subject: [PATCH 2/2] test: Update HTTP server URL attribute expectations Assert url.full and url.path across HTTP server tests so expectations match the new span attributes. Use normalized Next.js request data when constructing absolute URL attributes. Co-Authored-By: GPT-5.6 Sol Co-authored-by: Cursor --- .../nestjs-11/tests/transactions.test.ts | 2 ++ .../nestjs-8/tests/transactions.test.ts | 2 ++ .../nestjs-basic/tests/transactions.test.ts | 2 ++ .../tests/propagation.test.ts | 8 ++++++++ .../tests/transactions.test.ts | 2 ++ .../tests/transactions.test.ts | 2 ++ .../tests/transactions.test.ts | 2 ++ .../tests/transactions.test.ts | 2 ++ .../node-express-v5/tests/transactions.test.ts | 2 ++ .../node-express/tests/transactions.test.ts | 2 ++ .../node-fastify-3/tests/propagation.test.ts | 8 ++++++++ .../node-fastify-3/tests/transactions.test.ts | 2 ++ .../node-fastify-4/tests/propagation.test.ts | 8 ++++++++ .../node-fastify-4/tests/transactions.test.ts | 2 ++ .../node-fastify-5/tests/propagation.test.ts | 8 ++++++++ .../node-fastify-5/tests/transactions.test.ts | 2 ++ .../node-hapi/tests/transactions.test.ts | 2 ++ .../node-koa/tests/propagation.test.ts | 8 ++++++++ .../node-koa/tests/transactions.test.ts | 2 ++ .../tests/sampling.test.ts | 2 ++ .../tests/transactions.test.ts | 2 ++ .../node-otel/tests/transactions.test.ts | 2 ++ .../tsx-express/tests/transactions.test.ts | 2 ++ .../suites/tracing/httpIntegration/test.ts | 5 +++++ packages/astro/test/server/middleware.test.ts | 5 +++++ .../http/server-subscription.test.ts | 3 +++ .../wrapApiHandlerWithSentry.ts | 3 ++- packages/nextjs/test/config/withSentry.test.ts | 18 ++++++++++++++---- .../server/createServerInstrumentation.test.ts | 3 +++ 29 files changed, 108 insertions(+), 5 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts index 375c56a845d6..31fd0c8f6970 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts index 7270ad211909..23a11f67b0a3 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts index d56ddf007e9c..d6bec81e67db 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts @@ -49,6 +49,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts index 0a23c1766b38..1da006fca893 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts @@ -64,6 +64,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -103,6 +105,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -193,6 +197,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -232,6 +238,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts index 9ca18ec0888f..344d2440a9da 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction from module', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/example-module/transaction', + 'url.full': 'http://localhost:3030/example-module/transaction', + 'url.path': '/example-module/transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts index ddfcb1192edf..b0b9e71a4bfe 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction from module', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/example-module/transaction', + 'url.full': 'http://localhost:3030/example-module/transaction', + 'url.path': '/example-module/transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-express-orchestrion-cjs/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-express-orchestrion-cjs/tests/transactions.test.ts index 9dbce2a05ac9..1b9d488958c7 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-orchestrion-cjs/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-orchestrion-cjs/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-express-orchestrion/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-express-orchestrion/tests/transactions.test.ts index fb11235943b2..cf1790853c86 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-orchestrion/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-orchestrion/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts index ba9632aaf952..c44da1ed290f 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts index c0c286da3345..5d995d844f93 100644 --- a/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts index 1cdfd67a4851..41028122b492 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts @@ -64,6 +64,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -103,6 +105,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -193,6 +197,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -232,6 +238,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts index 6c53f21bd869..22b12c322169 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts @@ -28,6 +28,8 @@ test.skip('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts index 6e6b20b916e8..4b3e79b8b21d 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts @@ -64,6 +64,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -103,6 +105,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -193,6 +197,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -232,6 +238,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts index b9a41cd4e572..7209031eb53c 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts index 4e903edf05b5..c7f833701f52 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts @@ -64,6 +64,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -103,6 +105,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -193,6 +197,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -232,6 +238,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts index b4460cde2a21..f90bcf06b717 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts index bd6540b088d3..bfd71c2be730 100644 --- a/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts @@ -22,6 +22,8 @@ test('Sends successful transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-success', + 'url.full': 'http://localhost:3030/test-success', + 'url.path': '/test-success', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts index 592c5a4717f4..dcb952069bef 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts @@ -63,6 +63,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, + 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -102,6 +104,8 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -192,6 +196,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, + 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', @@ -231,6 +237,8 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, + 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts index f86901e0dee4..8952ec88a8ae 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/tests/sampling.test.ts b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/tests/sampling.test.ts index 49d35cb9e85f..12753312cdb2 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/tests/sampling.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/tests/sampling.test.ts @@ -21,6 +21,8 @@ test('Sends a sampled API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/task', + 'url.full': 'http://localhost:3030/task', + 'url.path': '/task', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/tests/transactions.test.ts index 299d3c2b80ec..b128a537b856 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/tests/transactions.test.ts @@ -35,6 +35,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/node-otel/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-otel/tests/transactions.test.ts index ba77e6a3b294..b77c0a610512 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-otel/tests/transactions.test.ts @@ -35,6 +35,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts index 35fe8f17bd94..c76c7653d30f 100644 --- a/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts @@ -23,6 +23,8 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'otel.kind': 'SERVER', 'http.response.status_code': 200, 'http.url': 'http://localhost:3030/test-transaction', + 'url.full': 'http://localhost:3030/test-transaction', + 'url.path': '/test-transaction', 'http.host': 'localhost:3030', 'net.host.name': 'localhost', 'http.method': 'GET', diff --git a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts index ac0ac3780a38..69740b8bdaf4 100644 --- a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts @@ -1,4 +1,5 @@ import { createTestServer } from '@sentry-internal/test-utils'; +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import { afterAll, describe, expect, test } from 'vitest'; import { cleanupChildProcesses, createEsmAndCjsTests, createRunner } from '../../../utils/runner'; @@ -130,6 +131,8 @@ describe('httpIntegration', () => { 'sentry.sample_rate': 1, 'sentry.source': 'route', url: `http://localhost:${port}/test`, + [URL_FULL]: `http://localhost:${port}/test?a=1&b=2`, + [URL_PATH]: '/test', ...getCommonHttpRequestHeaders(), }); }, @@ -172,6 +175,8 @@ describe('httpIntegration', () => { 'sentry.sample_rate': 1, 'sentry.source': 'route', url: `http://localhost:${port}/test`, + [URL_FULL]: `http://localhost:${port}/test?a=1&b=2`, + [URL_PATH]: '/test', 'http.request.header.content_length': '9', 'http.request.header.content_type': 'text/plain;charset=UTF-8', ...getCommonHttpRequestHeaders(), diff --git a/packages/astro/test/server/middleware.test.ts b/packages/astro/test/server/middleware.test.ts index 205cfb7e757f..9f051ebd703e 100644 --- a/packages/astro/test/server/middleware.test.ts +++ b/packages/astro/test/server/middleware.test.ts @@ -1,3 +1,4 @@ +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import type { Client, Span } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; import * as SentryCore from '@sentry/core'; @@ -117,6 +118,8 @@ describe('sentryMiddleware', () => { 'sentry.origin': 'auto.http.astro', method: 'GET', url: 'https://mydomain.io/users/123/details', + [URL_FULL]: 'https://mydomain.io/users/123/details', + [URL_PATH]: '/users/123/details', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [SentryCore.SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: 'GET', 'http.route': '/users/[id]/details', @@ -154,6 +157,8 @@ describe('sentryMiddleware', () => { 'sentry.origin': 'auto.http.astro', method: 'GET', url: 'http://localhost:1234/a%xx', + [URL_FULL]: 'http://localhost:1234/a%xx', + [URL_PATH]: 'a%xx', [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', [SentryCore.SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: 'GET', }, diff --git a/packages/core/test/lib/integrations/http/server-subscription.test.ts b/packages/core/test/lib/integrations/http/server-subscription.test.ts index 6be81c51f210..8c1fc3594403 100644 --- a/packages/core/test/lib/integrations/http/server-subscription.test.ts +++ b/packages/core/test/lib/integrations/http/server-subscription.test.ts @@ -1,3 +1,4 @@ +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import * as http from 'node:http'; import type { AddressInfo } from 'node:net'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -107,6 +108,8 @@ describe('getHttpServerSubscriptions', () => { 'sentry.op': 'http.server', 'sentry.origin': 'auto.http.server', 'sentry.source': 'url', + [URL_FULL]: expect.stringMatching(/\/users\/42\?foo=bar$/), + [URL_PATH]: '/users/42', }), }), ); diff --git a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts index 809459790a14..406965ee696a 100644 --- a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts +++ b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentry.ts @@ -81,7 +81,8 @@ export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameteriz isolationScope.setSDKProcessingMetadata({ normalizedRequest }); isolationScope.setTransactionName(`${reqMethod}${parameterizedRoute}`); - const urlObject = req.url ? parseStringToURLObject(req.url) : undefined; + const requestUrl = normalizedRequest.url || req.url; + const urlObject = requestUrl ? parseStringToURLObject(requestUrl) : undefined; return startSpanManual( { diff --git a/packages/nextjs/test/config/withSentry.test.ts b/packages/nextjs/test/config/withSentry.test.ts index 5b6643358f57..bcc19a1ef568 100644 --- a/packages/nextjs/test/config/withSentry.test.ts +++ b/packages/nextjs/test/config/withSentry.test.ts @@ -1,4 +1,5 @@ import * as SentryCore from '@sentry/core'; +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; import type { NextApiRequest, NextApiResponse } from 'next'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -17,7 +18,13 @@ describe('withSentry', () => { const wrappedHandlerNoError = wrapApiHandlerWithSentry(origHandlerNoError, '/my-parameterized-route'); beforeEach(() => { - req = { url: 'http://dogs.are.great' } as NextApiRequest; + req = { + headers: { + host: 'dogs.are.great', + 'x-forwarded-proto': 'https', + }, + url: '/api/dogs?good=true', + } as NextApiRequest; res = { send: function (this: AugmentedNextApiResponse) { this.end(); @@ -36,17 +43,20 @@ describe('withSentry', () => { }); describe('tracing', () => { - it('starts a transaction when tracing is enabled', async () => { + it('starts a transaction with normalized request URL attributes', async () => { await wrappedHandlerNoError(req, res); expect(startSpanManualSpy).toHaveBeenCalledWith( - expect.objectContaining({ + { name: 'GET /my-parameterized-route', op: 'http.server', + forceTransaction: true, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nextjs', + [URL_FULL]: 'https://dogs.are.great/api/dogs?good=true', + [URL_PATH]: '/api/dogs', }, - }), + }, expect.any(Function), ); }); diff --git a/packages/react-router/test/server/createServerInstrumentation.test.ts b/packages/react-router/test/server/createServerInstrumentation.test.ts index 32152b5b6bc0..80b1a4597901 100644 --- a/packages/react-router/test/server/createServerInstrumentation.test.ts +++ b/packages/react-router/test/server/createServerInstrumentation.test.ts @@ -1,4 +1,5 @@ import * as otelApi from '@opentelemetry/api'; +import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import * as core from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { @@ -116,6 +117,8 @@ describe('createSentryServerInstrumentation', () => { 'sentry.op': 'http.server', 'sentry.origin': 'auto.http.react_router.instrumentation_api', 'sentry.source': 'url', + [URL_FULL]: 'http://example.com/test-path', + [URL_PATH]: '/test-path', }); expect(mockHandleRequest).toHaveBeenCalled(); expect(core.flushIfServerless).toHaveBeenCalled();