@ogcio/o11y-sdk-node
Version:
Opentelemetry standard instrumentation SDK for NodeJS based project
77 lines (76 loc) • 3.48 kB
JavaScript
/**
* Enhances a NodeSDKConfig with Sentry integration for Next.js server-side.
*
* includes Next.js-specific integrations
* filters Next.js internal spans (static assets, _next routes, etc...)
* nextjs proper source map resolution
*/
export async function withSentryNextjs(config, options = {}) {
const { sentryOptions = {}, useSentrySampling = false } = options;
const components = await buildSentryNextjsComponents(sentryOptions, useSentrySampling);
return {
...config,
// Prepend SentrySpanProcessor so it processes spans before OTLP export
prependSpanProcessors: [
components.spanProcessor,
...(config.prependSpanProcessors ?? []),
],
// Wrap sampler with SentrySampler, using o11y's sampler as fallback
samplerWrapper: (defaultSampler) => {
// Chain with any existing wrapper
const baseSampler = config.samplerWrapper
? config.samplerWrapper(defaultSampler)
: defaultSampler;
return components.sampler(baseSampler);
},
// Add SentryPropagator for distributed tracing
additionalPropagators: [
components.propagator,
...(config.additionalPropagators ?? []),
],
// Use SentryContextManager for proper async context tracking
contextManager: config.contextManager ?? components.contextManager,
// Validate Sentry setup after SDK starts
onSdkStarted: (sdk) => {
components.validate();
config.onSdkStarted?.(sdk);
},
};
}
/**
* Builds Sentry OTEL components for Next.js by dynamically importing @sentry packages.
* This keeps @sentry/* as optional peer dependencies.
*/
async function buildSentryNextjsComponents(sentryOptions, useSentrySampling = false) {
// Dynamic imports to keep @sentry/* as optional peer dependencies
const Sentry = await import("@sentry/nextjs");
const SentryOtel = await import("@sentry/opentelemetry");
// Destructure common options to be defaulted, pass rest to Sentry.init
const { dsn, environment, tracesSampleRate, tracesSampler, integrations, sendDefaultPii, enableLogs, ...restOptions } = sentryOptions;
Sentry.init({
dsn: dsn ?? process.env.SENTRY_DSN,
environment: environment ?? process.env.SENTRY_ENV ?? process.env.NODE_ENV,
skipOpenTelemetrySetup: true,
// Sentry Next.js defaults (which include distDirRewriteFramesIntegration, httpIntegration, etc...)
integrations: integrations ?? [],
tracesSampleRate: useSentrySampling ? (tracesSampleRate ?? 1) : 1,
tracesSampler: useSentrySampling ? tracesSampler : undefined,
sendDefaultPii: sendDefaultPii ?? false,
enableLogs: enableLogs ?? true,
// Pass through any additional options
...restOptions,
});
const sentryClient = Sentry.getClient();
if (!sentryClient) {
console.warn("[@ogcio/o11y-sdk-node] Unable to initialize Sentry client for Next.js. Telemetry may not work as expected.");
}
return {
spanProcessor: new SentryOtel.SentrySpanProcessor(),
sampler: (fallbackSampler) => sentryClient
? new SentryOtel.SentrySampler(sentryClient)
: fallbackSampler,
propagator: new SentryOtel.SentryPropagator(),
contextManager: new Sentry.SentryContextManager(),
validate: Sentry.validateOpenTelemetrySetup,
};
}