@sentry/nextjs
Version:
Official Sentry SDK for Next.js
125 lines (121 loc) • 6.82 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const attributes = require('@sentry/conventions/attributes');
const op = require('@sentry/conventions/op');
const core = require('@sentry/core');
const enhanceMiddlewareRootSpan = require('../common/enhanceMiddlewareRootSpan.js');
const nextSpanAttributes = require('../common/nextSpanAttributes.js');
const spanAttributesWithLogicAttached = require('../common/span-attributes-with-logic-attached.js');
const addHeadersAsAttributes = require('../common/utils/addHeadersAsAttributes.js');
const backfillHttpServerStatus = require('../common/utils/backfillHttpServerStatus.js');
const dropMiddlewareTunnelRequests = require('../common/utils/dropMiddlewareTunnelRequests.js');
const liveRootSpanAdapter = require('../common/utils/liveRootSpanAdapter.js');
const forkIsolationScopeForRootSpan = require('../common/utils/forkIsolationScopeForRootSpan.js');
const setUrlProcessingMetadata = require('../common/utils/setUrlProcessingMetadata.js');
const tracingUtils = require('../common/utils/tracingUtils.js');
const enhanceHandleRequestRootSpan = require('./enhanceHandleRequestRootSpan.js');
const vercelCronsMonitoring = require('./vercelCronsMonitoring.js');
const vercelQueuesMonitoring = require('./vercelQueuesMonitoring.js');
const NEXTJS_ERROR_PAGE_ROUTES = ["/500", "/_error"];
const NEXTJS_SERVER_IGNORE_SPANS = [
// Static assets (matches `_next/static` anywhere in the name to handle custom basePath)
/^GET (\/.*)?\/_next\/static\//,
// Dev source-map fetch endpoints
/\/__nextjs_original-stack-frame/,
// Pages router /404
/^\/404$/,
// App router /404 and /_not-found segments (any HTTP method)
/^(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH) \/(404|_not-found)$/,
// Root transactions named "NextServer.getRequestHandler" containing useless tracing
/^NextServer\.getRequestHandler$/,
// Spans flagged via TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION
// (set in `dropMiddlewareTunnelRequests` during `spanStart`)
{ attributes: { [spanAttributesWithLogicAttached.TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION]: true } }
];
function addNextjsServerSpanHooks(client) {
client.on("spanStart", (span) => handleOnSpanStart(span, client));
client.on("spanEnd", (span) => {
if (span !== core.getRootSpan(span)) {
return;
}
const mutableRootSpan = liveRootSpanAdapter.createLiveRootSpanAdapter(span);
enhanceHandleRequestRootSpan.enhanceHandleRequestRootSpan(mutableRootSpan);
enhanceMiddlewareRootSpan.enhanceMiddlewareRootSpan(mutableRootSpan);
backfillHttpServerStatus.backfillHttpServerStatus(span);
});
client.on("spanEnd", vercelCronsMonitoring.maybeCompleteCronCheckIn);
client.on("spanEnd", vercelQueuesMonitoring.maybeCleanupQueueSpan);
client.on("preprocessEvent", (event) => {
setUrlProcessingMetadata.setUrlProcessingMetadata(event);
});
}
function maybeHoistRouteToRootSpan(spanAttributes, rootSpan, rootSpanAttributes) {
if (typeof spanAttributes?.[nextSpanAttributes.ATTR_NEXT_ROUTE] !== "string") {
return;
}
const route = spanAttributes[nextSpanAttributes.ATTR_NEXT_ROUTE].replace(/\/route$/, "");
const isErrorPageBehindMiddleware = NEXTJS_ERROR_PAGE_ROUTES.includes(route) && rootSpanAttributes?.[attributes.SENTRY_SEGMENT_NAME_SOURCE] === "route";
const method = rootSpanAttributes?.[attributes.HTTP_REQUEST_METHOD] || rootSpanAttributes?.[attributes.HTTP_METHOD];
if (!method || rootSpanAttributes?.[attributes.HTTP_ROUTE] || isErrorPageBehindMiddleware) {
return;
}
const name = typeof method === "string" ? `${method} ${route}` : route;
rootSpan.updateName(name);
rootSpan.setAttributes({
[attributes.HTTP_ROUTE]: route,
// Preserving the original attribute despite internally not depending on it
[nextSpanAttributes.ATTR_NEXT_ROUTE]: route,
[attributes.SENTRY_SEGMENT_NAME_SOURCE]: "route"
});
core.getIsolationScope().setTransactionName(name);
vercelCronsMonitoring.maybeStartCronCheckIn(rootSpan, route);
vercelQueuesMonitoring.maybeEnrichQueueConsumerSpan(rootSpan);
}
function handleMiddlewareSpanStart(span, spanAttributes, rootSpan, rootSpanAttributes) {
const middlewareName = spanAttributes?.[nextSpanAttributes.ATTR_NEXT_SPAN_NAME];
if (rootSpanAttributes?.[nextSpanAttributes.ATTR_NEXT_SPAN_TYPE] === void 0) {
span.setAttribute(attributes.SENTRY_OP, op.MIDDLEWARE);
if (typeof middlewareName === "string" && !rootSpanAttributes?.[attributes.HTTP_ROUTE]) {
rootSpan.updateName(middlewareName);
rootSpan.setAttribute(attributes.SENTRY_SEGMENT_NAME_SOURCE, "route");
}
} else if (typeof middlewareName === "string") {
rootSpan.updateName(middlewareName);
rootSpan.setAttributes({
[attributes.HTTP_ROUTE]: middlewareName,
[nextSpanAttributes.ATTR_NEXT_SPAN_NAME]: middlewareName,
[attributes.SENTRY_SEGMENT_NAME_SOURCE]: "route"
});
}
span.setAttribute(attributes.SENTRY_ORIGIN, "auto");
}
function handleOnSpanStart(span, client) {
const spanAttributes = core.spanToJSON(span).attributes;
const rootSpan = core.getRootSpan(span);
const rootSpanAttributes = core.spanToJSON(rootSpan).attributes;
const isRootSpan = span === rootSpan;
dropMiddlewareTunnelRequests.dropMiddlewareTunnelRequests(span, spanAttributes);
if (isRootSpan && spanAttributes?.[nextSpanAttributes.ATTR_NEXT_SPAN_TYPE] === "BaseServer.handleRequest" && core.hasSpanStreamingEnabled(client)) {
const method = spanAttributes[attributes.HTTP_REQUEST_METHOD] ?? spanAttributes[attributes.HTTP_METHOD];
liveRootSpanAdapter.createLiveRootSpanAdapter(span).setName(
(typeof method === "string" ? method.toUpperCase() : "") || core.HTTP_SPAN_NAME_FALLBACK
);
}
maybeHoistRouteToRootSpan(spanAttributes, rootSpan, rootSpanAttributes);
if (spanAttributes?.[nextSpanAttributes.ATTR_NEXT_SPAN_TYPE] === "Middleware.execute") {
handleMiddlewareSpanStart(span, spanAttributes, rootSpan, rootSpanAttributes);
}
if (spanAttributes?.[nextSpanAttributes.ATTR_NEXT_SPAN_TYPE] !== void 0) {
span.setAttribute(attributes.SENTRY_ORIGIN, "auto");
}
if (isRootSpan) {
const headers = core.getIsolationScope().getScopeData().sdkProcessingMetadata?.normalizedRequest?.headers;
addHeadersAsAttributes.addHeadersAsAttributes(headers, rootSpan);
}
forkIsolationScopeForRootSpan.maybeForkIsolationScopeForRootSpan(span, spanAttributes);
tracingUtils.maybeEnhanceServerComponentSpanName(span, spanAttributes, rootSpanAttributes, client);
vercelQueuesMonitoring.maybeEnrichQueueProducerSpan(span);
}
exports.NEXTJS_SERVER_IGNORE_SPANS = NEXTJS_SERVER_IGNORE_SPANS;
exports.addNextjsServerSpanHooks = addNextjsServerSpanHooks;
exports.handleOnSpanStart = handleOnSpanStart;
//# sourceMappingURL=serverSpanHooks.js.map