From 0f3c597f0b34ec73d718d06af2e086c8cdd05c10 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Thu, 19 Mar 2026 01:28:08 +0530 Subject: [PATCH] fix(nextjs): correctly drop tunnel-route spans for full URLs --- .../utils/dropMiddlewareTunnelRequests.ts | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/src/common/utils/dropMiddlewareTunnelRequests.ts b/packages/nextjs/src/common/utils/dropMiddlewareTunnelRequests.ts index 9eb2e70c8a43..aefdde93edf4 100644 --- a/packages/nextjs/src/common/utils/dropMiddlewareTunnelRequests.ts +++ b/packages/nextjs/src/common/utils/dropMiddlewareTunnelRequests.ts @@ -54,12 +54,35 @@ function isTunnelRouteSpan(spanAttributes: Record): boolean { // eslint-disable-next-line deprecation/deprecation const httpTarget = spanAttributes[SEMATTRS_HTTP_TARGET]; - if (typeof httpTarget === 'string') { - // Extract pathname from the target (e.g., "/tunnel?o=123&p=456" -> "/tunnel") - const pathname = httpTarget.split('?')[0] || ''; + if (typeof httpTarget !== 'string') { + return false; + } + + // Next.js / OTel can sometimes report `http.target` as a full URL (including scheme/host), e.g. + // "https://example.com/monitoring/tunnel?o=...". In that case, comparing the raw string to the tunnel + // route path would fail. + const pathname = extractPathnameFromHttpTarget(httpTarget); + if (!pathname) { + return false; + } + + const normalizedTunnelPath = tunnelPath.startsWith('/') ? tunnelPath : `/${tunnelPath}`; + return pathname === normalizedTunnelPath || pathname.startsWith(normalizedTunnelPath + '/'); +} + +function extractPathnameFromHttpTarget(httpTarget: string): string { + if (!httpTarget) { + return ''; + } - return pathname.startsWith(tunnelPath); + if (httpTarget.startsWith('http://') || httpTarget.startsWith('https://')) { + try { + return new URL(httpTarget).pathname; + } catch { + // Fall back to best-effort parsing below. + } } - return false; + // Example: "/tunnel?o=123&p=456" -> "/tunnel" + return httpTarget.split('?')[0] || ''; }