@sentry/nextjs
Version:
Official Sentry SDK for Next.js
218 lines (215 loc) • 11 kB
JavaScript
import { HTTP_TARGET, URL_QUERY } from '@sentry/conventions/attributes';
import { GLOBAL_OBJ, debug, applySdkMetadata, getGlobalScope, getClient, SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core';
import { experimentalUseDiagnosticsChannelInjection as experimentalUseDiagnosticsChannelInjection$1, getDefaultIntegrations, httpIntegration, isDiagnosticsChannelInjectionEnabled, init as init$1 } from '@sentry/node';
export * from '@sentry/node';
export { pinoIntegration } from '@sentry/node';
import { DEBUG_BUILD } from '../common/debug-build.js';
import { devErrorSymbolicationEventProcessor } from '../common/devErrorSymbolicationEventProcessor.js';
import { getVercelEnv } from '../common/getVercelEnv.js';
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../common/span-attributes-with-logic-attached.js';
import { isBuild } from '../common/utils/isBuild.js';
import { isCloudflareWaitUntilAvailable } from '../common/utils/responseEnd.js';
import { setUrlProcessingMetadata } from '../common/utils/setUrlProcessingMetadata.js';
import { distDirRewriteFramesIntegration } from './distDirRewriteFramesIntegration.js';
import { enhanceMiddlewareRootSpan } from '../common/enhanceMiddlewareRootSpan.js';
import { enhanceHandleRequestRootSpan } from './enhanceHandleRequestRootSpan.js';
import { handleOnSpanStart } from './handleOnSpanStart.js';
import { prepareSafeIdGeneratorContext } from './prepareSafeIdGeneratorContext.js';
import { maybeCompleteCronCheckIn } from './vercelCronsMonitoring.js';
import { maybeCleanupQueueSpan } from './vercelQueuesMonitoring.js';
export { captureUnderscoreErrorException } from '../common/pages-router-instrumentation/_error.js';
export { startInactiveSpan, startSpan, startSpanManual } from '../common/utils/nextSpan.js';
export { wrapGetStaticPropsWithSentry } from '../common/pages-router-instrumentation/wrapGetStaticPropsWithSentry.js';
export { wrapGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapGetInitialPropsWithSentry.js';
export { wrapAppGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapAppGetInitialPropsWithSentry.js';
export { wrapDocumentGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapDocumentGetInitialPropsWithSentry.js';
export { wrapErrorGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapErrorGetInitialPropsWithSentry.js';
export { wrapGetServerSidePropsWithSentry } from '../common/pages-router-instrumentation/wrapGetServerSidePropsWithSentry.js';
export { wrapServerComponentWithSentry } from '../common/wrapServerComponentWithSentry.js';
export { wrapRouteHandlerWithSentry } from '../common/wrapRouteHandlerWithSentry.js';
export { wrapApiHandlerWithSentryVercelCrons } from '../common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.js';
export { wrapMiddlewareWithSentry } from '../common/wrapMiddlewareWithSentry.js';
export { wrapPageComponentWithSentry } from '../common/pages-router-instrumentation/wrapPageComponentWithSentry.js';
export { wrapGenerationFunctionWithSentry } from '../common/wrapGenerationFunctionWithSentry.js';
export { withServerActionInstrumentation } from '../common/withServerActionInstrumentation.js';
export { captureRequestError } from '../common/captureRequestError.js';
export { wrapApiHandlerWithSentry } from '../common/pages-router-instrumentation/wrapApiHandlerWithSentry.js';
const globalWithInjectedValues = GLOBAL_OBJ;
function experimentalUseDiagnosticsChannelInjection() {
const tracingHooksDir = process.env._sentryOrchestrionTracingHooksDir || globalWithInjectedValues._sentryOrchestrionTracingHooksDir;
experimentalUseDiagnosticsChannelInjection$1(tracingHooksDir ? { tracingHooksDir } : void 0);
}
prepareSafeIdGeneratorContext();
const ErrorBoundary = (props) => {
if (!props.children) {
return null;
}
if (typeof props.children === "function") {
return props.children();
}
return props.children;
};
function createReduxEnhancer() {
return (createStore) => createStore;
}
function withErrorBoundary(WrappedComponent) {
return WrappedComponent;
}
function showReportDialog() {
return;
}
function getCloudflareRuntimeConfig() {
if (isCloudflareWaitUntilAvailable()) {
return { runtime: { name: "cloudflare" } };
}
return void 0;
}
function init(options) {
prepareSafeIdGeneratorContext();
if (isBuild()) {
return;
}
if (!DEBUG_BUILD && options.debug) {
console.warn(
"[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output."
);
}
const customDefaultIntegrations = getDefaultIntegrations(options).filter((integration) => integration.name !== "Http").concat(
// We are using the HTTP integration without instrumenting incoming HTTP requests because Next.js does that by itself.
httpIntegration({
disableIncomingRequestSpans: true
})
);
if (!options.skipOpenTelemetrySetup) {
process.env.NEXT_OTEL_FETCH_DISABLED = "1";
}
const distDirName = process.env._sentryRewriteFramesDistDir || globalWithInjectedValues._sentryRewriteFramesDistDir;
if (distDirName) {
customDefaultIntegrations.push(distDirRewriteFramesIntegration({ distDirName }));
}
const useDiagnosticsChannelInjection = process.env._sentryUseDiagnosticsChannelInjection || globalWithInjectedValues._sentryUseDiagnosticsChannelInjection;
if (DEBUG_BUILD && useDiagnosticsChannelInjection && !isDiagnosticsChannelInjectionEnabled()) {
debug.warn(
"[@sentry/nextjs] `useDiagnosticsChannelInjection` is enabled in `withSentryConfig`, but `Sentry.experimentalUseDiagnosticsChannelInjection()` was not called before `Sentry.init()`. Server DB spans will not be recorded."
);
}
const cloudflareConfig = getCloudflareRuntimeConfig();
const opts = {
environment: options.environment || process.env.SENTRY_ENVIRONMENT || getVercelEnv(false) || process.env.NODE_ENV,
release: process.env._sentryRelease || globalWithInjectedValues._sentryRelease,
defaultIntegrations: customDefaultIntegrations,
...options,
// Override runtime to 'cloudflare' when running on OpenNext/Cloudflare
...cloudflareConfig
};
const nextjsIgnoreSpans = [
// 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)$/,
// Next.js 13 root transactions named "NextServer.getRequestHandler" containing useless tracing
/^NextServer\.getRequestHandler$/,
// Spans flagged via TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION
// (set in `dropMiddlewareTunnelRequests` during `spanStart`)
{ attributes: { [TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION]: true } }
];
opts.ignoreSpans = [...opts.ignoreSpans || [], ...nextjsIgnoreSpans];
if (DEBUG_BUILD && opts.debug) {
debug.enable();
}
DEBUG_BUILD && debug.log("Initializing SDK...");
if (sdkAlreadyInitialized()) {
DEBUG_BUILD && debug.log("SDK already initialized");
return;
}
applySdkMetadata(opts, "nextjs", ["nextjs", cloudflareConfig ? "cloudflare" : "node"]);
const client = init$1(opts);
client?.on("beforeSampling", ({ spanAttributes }, samplingDecision) => {
if (
// eslint-disable-next-line typescript/no-deprecated
typeof spanAttributes[HTTP_TARGET] === "string" && // eslint-disable-next-line typescript/no-deprecated
spanAttributes[HTTP_TARGET].includes("sentry_key") && // eslint-disable-next-line typescript/no-deprecated
spanAttributes[HTTP_TARGET].includes("sentry_client") || typeof spanAttributes[URL_QUERY] === "string" && spanAttributes[URL_QUERY].includes("sentry_key") && spanAttributes[URL_QUERY].includes("sentry_client")
) {
samplingDecision.decision = false;
}
});
client?.on("spanStart", handleOnSpanStart);
client?.on("spanEnd", maybeCompleteCronCheckIn);
client?.on("spanEnd", maybeCleanupQueueSpan);
getGlobalScope().addEventProcessor(
Object.assign(
((event, hint) => {
if (event.type !== void 0) {
return event;
}
const originalException = hint.originalException;
const isPostponeError = typeof originalException === "object" && originalException !== null && "$$typeof" in originalException && originalException.$$typeof === /* @__PURE__ */ Symbol.for("react.postpone");
if (isPostponeError) {
return null;
}
const exceptionMessage = event.exception?.values?.[0]?.value;
if (exceptionMessage?.includes("Suspense Exception: This is not a real error!") || exceptionMessage?.includes("Suspense Exception: This is not a real error, and should not leak")) {
return null;
}
return event;
}),
{ id: "DropReactControlFlowErrors" }
)
);
client?.on("preprocessEvent", (event) => {
if (event.type === "transaction" && event.contexts?.trace?.data) {
const mutableRootSpan = {
attributes: event.contexts.trace.data,
getName: () => event.transaction,
setName: (name) => {
event.transaction = name;
},
setOp: (op) => {
event.contexts.trace.op = op;
}
};
enhanceHandleRequestRootSpan(mutableRootSpan);
enhanceMiddlewareRootSpan(mutableRootSpan);
}
setUrlProcessingMetadata(event);
});
client?.on("processSegmentSpan", (span) => {
const attributes = span.attributes ?? (span.attributes = {});
const mutableRootSpan = {
attributes,
getName: () => span.name,
setName: (name) => {
span.name = name;
},
// For streamed spans, op lives in `attributes['sentry.op']` - mirror it there so middleware
// overrides land somewhere readable (the legacy path uses a separate `event.contexts.trace.op`).
setOp: (op) => {
attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
}
};
enhanceHandleRequestRootSpan(mutableRootSpan);
enhanceMiddlewareRootSpan(mutableRootSpan);
});
if (process.env.NODE_ENV === "development") {
getGlobalScope().addEventProcessor(devErrorSymbolicationEventProcessor);
}
try {
if (process.turbopack) {
getGlobalScope().setTag("turbopack", true);
getGlobalScope().setAttribute("turbopack", true);
}
} catch {
}
DEBUG_BUILD && debug.log("SDK successfully initialized");
return client;
}
function sdkAlreadyInitialized() {
return !!getClient();
}
export { ErrorBoundary, createReduxEnhancer, experimentalUseDiagnosticsChannelInjection, init, showReportDialog, withErrorBoundary };
//# sourceMappingURL=index.js.map