@sentry/node
Version:
Sentry Node SDK using OpenTelemetry for performance instrumentation
314 lines (263 loc) • 10.2 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
const core = require('@sentry/core');
const opentelemetry = require('@sentry/opentelemetry');
const utils = require('@sentry/utils');
const debugBuild = require('../debug-build.js');
const console$1 = require('../integrations/console.js');
const context = require('../integrations/context.js');
const contextlines = require('../integrations/contextlines.js');
const http = require('../integrations/http.js');
const index = require('../integrations/local-variables/index.js');
const modules = require('../integrations/modules.js');
const nodeFetch = require('../integrations/node-fetch.js');
const onuncaughtexception = require('../integrations/onuncaughtexception.js');
const onunhandledrejection = require('../integrations/onunhandledrejection.js');
const spotlight = require('../integrations/spotlight.js');
const index$1 = require('../integrations/tracing/index.js');
const http$1 = require('../transports/http.js');
const commonjs = require('../utils/commonjs.js');
const api = require('./api.js');
const client = require('./client.js');
const initOtel = require('./initOtel.js');
function getCjsOnlyIntegrations() {
return commonjs.isCjs() ? [modules.modulesIntegration()] : [];
}
/**
* Get default integrations, excluding performance.
*/
function getDefaultIntegrationsWithoutPerformance() {
return [
// Common
core.inboundFiltersIntegration(),
core.functionToStringIntegration(),
core.linkedErrorsIntegration(),
core.requestDataIntegration(),
// Native Wrappers
console$1.consoleIntegration(),
http.httpIntegration(),
nodeFetch.nativeNodeFetchIntegration(),
// Global Handlers
onuncaughtexception.onUncaughtExceptionIntegration(),
onunhandledrejection.onUnhandledRejectionIntegration(),
// Event Info
contextlines.contextLinesIntegration(),
index.localVariablesIntegration(),
context.nodeContextIntegration(),
...getCjsOnlyIntegrations(),
];
}
/** Get the default integrations for the Node SDK. */
function getDefaultIntegrations(options) {
return [
...getDefaultIntegrationsWithoutPerformance(),
// We only add performance integrations if tracing is enabled
// Note that this means that without tracing enabled, e.g. `expressIntegration()` will not be added
// This means that generally request isolation will work (because that is done by httpIntegration)
// But `transactionName` will not be set automatically
...(shouldAddPerformanceIntegrations(options) ? index$1.getAutoPerformanceIntegrations() : []),
];
}
function shouldAddPerformanceIntegrations(options) {
if (!core.hasTracingEnabled(options)) {
return false;
}
// We want to ensure `tracesSampleRate` is not just undefined/null here
// eslint-disable-next-line deprecation/deprecation
return options.enableTracing || options.tracesSampleRate != null || 'tracesSampler' in options;
}
/**
* Initialize Sentry for Node.
*/
function init(options = {}) {
return _init(options, getDefaultIntegrations);
}
/**
* Initialize Sentry for Node, without any integrations added by default.
*/
function initWithoutDefaultIntegrations(options = {}) {
return _init(options, () => []);
}
/**
* Initialize Sentry for Node, without performance instrumentation.
*/
function _init(
_options = {},
getDefaultIntegrationsImpl,
) {
const options = getClientOptions(_options, getDefaultIntegrationsImpl);
if (options.debug === true) {
if (debugBuild.DEBUG_BUILD) {
utils.logger.enable();
} else {
// use `console.warn` rather than `logger.warn` since by non-debug bundles have all `logger.x` statements stripped
utils.consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn('[Sentry] Cannot initialize SDK with `debug` option using a non-debug bundle.');
});
}
}
if (!commonjs.isCjs() && options.registerEsmLoaderHooks !== false) {
initOtel.maybeInitializeEsmLoader(options.registerEsmLoaderHooks === true ? undefined : options.registerEsmLoaderHooks);
}
opentelemetry.setOpenTelemetryContextAsyncContextStrategy();
const scope = core.getCurrentScope();
scope.update(options.initialScope);
if (options.spotlight && !options.integrations.some(({ name }) => name === spotlight.INTEGRATION_NAME)) {
options.integrations.push(
spotlight.spotlightIntegration({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
}),
);
}
const client$1 = new client.NodeClient(options);
// The client is on the current scope, from where it generally is inherited
core.getCurrentScope().setClient(client$1);
client$1.init();
utils.logger.log(`Running in ${commonjs.isCjs() ? 'CommonJS' : 'ESM'} mode.`);
if (options.autoSessionTracking) {
startSessionTracking();
}
client$1.startClientReportTracking();
updateScopeFromEnvVariables();
// If users opt-out of this, they _have_ to set up OpenTelemetry themselves
// There is no way to use this SDK without OpenTelemetry!
if (!options.skipOpenTelemetrySetup) {
initOtel.initOpenTelemetry(client$1);
validateOpenTelemetrySetup();
}
opentelemetry.enhanceDscWithOpenTelemetryRootSpanName(client$1);
opentelemetry.setupEventContextTrace(client$1);
return client$1;
}
/**
* Validate that your OpenTelemetry setup is correct.
*/
function validateOpenTelemetrySetup() {
if (!debugBuild.DEBUG_BUILD) {
return;
}
const setup = opentelemetry.openTelemetrySetupCheck();
const required = ['SentryContextManager', 'SentryPropagator'];
if (core.hasTracingEnabled()) {
required.push('SentrySpanProcessor');
}
for (const k of required) {
if (!setup.includes(k)) {
utils.logger.error(
`You have to set up the ${k}. Without this, the OpenTelemetry & Sentry integration will not work properly.`,
);
}
}
if (!setup.includes('SentrySampler')) {
utils.logger.warn(
'You have to set up the SentrySampler. Without this, the OpenTelemetry & Sentry integration may still work, but sample rates set for the Sentry SDK will not be respected. If you use a custom sampler, make sure to use `wrapSamplingDecision`.',
);
}
}
function getClientOptions(
options,
getDefaultIntegrationsImpl,
) {
const release = getRelease(options.release);
const autoSessionTracking =
typeof release !== 'string'
? false
: options.autoSessionTracking === undefined
? true
: options.autoSessionTracking;
const tracesSampleRate = getTracesSampleRate(options.tracesSampleRate);
const baseOptions = utils.dropUndefinedKeys({
transport: http$1.makeNodeTransport,
dsn: process.env.SENTRY_DSN,
environment: process.env.SENTRY_ENVIRONMENT,
sendClientReports: true,
});
const overwriteOptions = utils.dropUndefinedKeys({
release,
autoSessionTracking,
tracesSampleRate,
});
const mergedOptions = {
...baseOptions,
...options,
...overwriteOptions,
};
if (options.defaultIntegrations === undefined) {
options.defaultIntegrations = getDefaultIntegrationsImpl(mergedOptions);
}
const clientOptions = {
...mergedOptions,
stackParser: utils.stackParserFromStackParserOptions(options.stackParser || api.defaultStackParser),
integrations: core.getIntegrationsToSetup({
defaultIntegrations: options.defaultIntegrations,
integrations: options.integrations,
}),
};
return clientOptions;
}
function getRelease(release) {
if (release !== undefined) {
return release;
}
const detectedRelease = api.getSentryRelease();
if (detectedRelease !== undefined) {
return detectedRelease;
}
return undefined;
}
function getTracesSampleRate(tracesSampleRate) {
if (tracesSampleRate !== undefined) {
return tracesSampleRate;
}
const sampleRateFromEnv = process.env.SENTRY_TRACES_SAMPLE_RATE;
if (!sampleRateFromEnv) {
return undefined;
}
const parsed = parseFloat(sampleRateFromEnv);
return isFinite(parsed) ? parsed : undefined;
}
/**
* Update scope and propagation context based on environmental variables.
*
* See https://github.com/getsentry/rfcs/blob/main/text/0071-continue-trace-over-process-boundaries.md
* for more details.
*/
function updateScopeFromEnvVariables() {
const sentryUseEnvironment = (process.env.SENTRY_USE_ENVIRONMENT || '').toLowerCase();
if (!['false', 'n', 'no', 'off', '0'].includes(sentryUseEnvironment)) {
const sentryTraceEnv = process.env.SENTRY_TRACE;
const baggageEnv = process.env.SENTRY_BAGGAGE;
const propagationContext = utils.propagationContextFromHeaders(sentryTraceEnv, baggageEnv);
core.getCurrentScope().setPropagationContext(propagationContext);
}
}
/**
* Enable automatic Session Tracking for the node process.
*/
function startSessionTracking() {
const client = core.getClient();
if (client && client.getOptions().autoSessionTracking) {
client.initSessionFlusher();
}
core.startSession();
// Emitted in the case of healthy sessions, error of `mechanism.handled: true` and unhandledrejections because
// The 'beforeExit' event is not emitted for conditions causing explicit termination,
// such as calling process.exit() or uncaught exceptions.
// Ref: https://nodejs.org/api/process.html#process_event_beforeexit
process.on('beforeExit', () => {
const session = core.getIsolationScope().getSession();
// Only call endSession, if the Session exists on Scope and SessionStatus is not a
// Terminal Status i.e. Exited or Crashed because
// "When a session is moved away from ok it must not be updated anymore."
// Ref: https://develop.sentry.dev/sdk/sessions/
if (session && session.status !== 'ok') {
core.endSession();
}
});
}
exports.getDefaultIntegrations = getDefaultIntegrations;
exports.getDefaultIntegrationsWithoutPerformance = getDefaultIntegrationsWithoutPerformance;
exports.init = init;
exports.initWithoutDefaultIntegrations = initWithoutDefaultIntegrations;
exports.validateOpenTelemetrySetup = validateOpenTelemetrySetup;
//# sourceMappingURL=index.js.map