Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
86 lines
4.0 KiB
Plaintext
86 lines
4.0 KiB
Plaintext
import { context } from '@opentelemetry/api';
|
|
import { ATTR_HTTP_REQUEST_METHOD, SEMATTRS_HTTP_METHOD, ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
|
|
import { spanToJSON, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getIsolationScope, getCapturedScopesOnSpan, getCurrentScope, setCapturedScopesOnSpan } from '@sentry/core';
|
|
import { getScopesFromContext } from '@sentry/opentelemetry';
|
|
import { ATTR_NEXT_ROUTE, ATTR_NEXT_SPAN_TYPE, ATTR_NEXT_SPAN_NAME } from '../common/nextSpanAttributes.js';
|
|
import { addHeadersAsAttributes } from '../common/utils/addHeadersAsAttributes.js';
|
|
import { dropMiddlewareTunnelRequests } from '../common/utils/dropMiddlewareTunnelRequests.js';
|
|
import { maybeEnhanceServerComponentSpanName } from '../common/utils/tracingUtils.js';
|
|
import { maybeStartCronCheckIn } from './vercelCronsMonitoring.js';
|
|
|
|
/**
|
|
* Handles the on span start event for Next.js spans.
|
|
* This function is used to enhance the span with additional information such as the route, the method, the headers, etc.
|
|
* It is called for every span that is started by Next.js.
|
|
* @param span The span that is starting.
|
|
*/
|
|
function handleOnSpanStart(span) {
|
|
const spanAttributes = spanToJSON(span).data;
|
|
const rootSpan = getRootSpan(span);
|
|
const rootSpanAttributes = spanToJSON(rootSpan).data;
|
|
const isRootSpan = span === rootSpan;
|
|
|
|
dropMiddlewareTunnelRequests(span, spanAttributes);
|
|
|
|
// What we do in this glorious piece of code, is hoist any information about parameterized routes from spans emitted
|
|
// by Next.js via the `next.route` attribute, up to the transaction by setting the http.route attribute.
|
|
if (typeof spanAttributes?.[ATTR_NEXT_ROUTE] === 'string') {
|
|
// Only hoist the http.route attribute if the transaction doesn't already have it
|
|
if (
|
|
// eslint-disable-next-line deprecation/deprecation
|
|
(rootSpanAttributes?.[ATTR_HTTP_REQUEST_METHOD] || rootSpanAttributes?.[SEMATTRS_HTTP_METHOD]) &&
|
|
!rootSpanAttributes?.[ATTR_HTTP_ROUTE]
|
|
) {
|
|
const route = spanAttributes[ATTR_NEXT_ROUTE].replace(/\/route$/, '');
|
|
rootSpan.updateName(route);
|
|
rootSpan.setAttribute(ATTR_HTTP_ROUTE, route);
|
|
// Preserving the original attribute despite internally not depending on it
|
|
rootSpan.setAttribute(ATTR_NEXT_ROUTE, route);
|
|
|
|
// Check if this is a Vercel cron request and start a check-in
|
|
maybeStartCronCheckIn(rootSpan, route);
|
|
}
|
|
}
|
|
|
|
if (spanAttributes?.[ATTR_NEXT_SPAN_TYPE] === 'Middleware.execute') {
|
|
const middlewareName = spanAttributes[ATTR_NEXT_SPAN_NAME];
|
|
if (typeof middlewareName === 'string') {
|
|
rootSpan.updateName(middlewareName);
|
|
rootSpan.setAttribute(ATTR_HTTP_ROUTE, middlewareName);
|
|
rootSpan.setAttribute(ATTR_NEXT_SPAN_NAME, middlewareName);
|
|
}
|
|
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto');
|
|
}
|
|
|
|
// We want to skip span data inference for any spans generated by Next.js. Reason being that Next.js emits spans
|
|
// with patterns (e.g. http.server spans) that will produce confusing data.
|
|
if (spanAttributes?.[ATTR_NEXT_SPAN_TYPE] !== undefined) {
|
|
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto');
|
|
}
|
|
|
|
if (isRootSpan) {
|
|
const headers = getIsolationScope().getScopeData().sdkProcessingMetadata?.normalizedRequest?.headers;
|
|
addHeadersAsAttributes(headers, rootSpan);
|
|
}
|
|
|
|
// We want to fork the isolation scope for incoming requests
|
|
if (spanAttributes?.[ATTR_NEXT_SPAN_TYPE] === 'BaseServer.handleRequest' && isRootSpan) {
|
|
const scopes = getCapturedScopesOnSpan(span);
|
|
|
|
const isolationScope = (scopes.isolationScope || getIsolationScope()).clone();
|
|
const scope = scopes.scope || getCurrentScope();
|
|
|
|
const currentScopesPointer = getScopesFromContext(context.active());
|
|
if (currentScopesPointer) {
|
|
currentScopesPointer.isolationScope = isolationScope;
|
|
}
|
|
|
|
setCapturedScopesOnSpan(span, scope, isolationScope);
|
|
}
|
|
|
|
maybeEnhanceServerComponentSpanName(span, spanAttributes, rootSpanAttributes);
|
|
}
|
|
|
|
export { handleOnSpanStart };
|
|
//# sourceMappingURL=handleOnSpanStart.js.map
|