@sentry/node
Version:
Official Sentry SDK for Node.js
277 lines (252 loc) • 9.46 kB
JavaScript
import { _optionalChain } from '@sentry/utils/esm/buildPolyfills';
import { Integrations, getMainCarrier, setHubOnCarrier, getCurrentHub, getIntegrationsToSetup, initAndBind } from '@sentry/core';
import { createStackParser, nodeStackLineParser, stackParserFromStackParserOptions, logger, GLOBAL_OBJ } from '@sentry/utils';
import * as domain from 'domain';
import { NodeClient } from './client.js';
import { Console } from './integrations/console.js';
import { Http } from './integrations/http.js';
import { OnUncaughtException } from './integrations/onuncaughtexception.js';
import { OnUnhandledRejection } from './integrations/onunhandledrejection.js';
import { LinkedErrors } from './integrations/linkederrors.js';
import { Modules } from './integrations/modules.js';
import { ContextLines } from './integrations/contextlines.js';
import { Context } from './integrations/context.js';
import { RequestData } from './integrations/requestdata.js';
import { LocalVariables } from './integrations/localvariables.js';
import './integrations/undici/index.js';
import { getModule } from './module.js';
import { makeNodeTransport } from './transports/http.js';
/* eslint-disable max-lines */
const defaultIntegrations = [
// Common
new Integrations.InboundFilters(),
new Integrations.FunctionToString(),
// Native Wrappers
new Console(),
new Http(),
// Global Handlers
new OnUncaughtException(),
new OnUnhandledRejection(),
// Event Info
new ContextLines(),
new LocalVariables(),
new Context(),
new Modules(),
new RequestData(),
// Misc
new LinkedErrors(),
];
/**
* The Sentry Node SDK Client.
*
* To use this SDK, call the {@link init} function as early as possible in the
* main entry module. To set context information or send manual events, use the
* provided methods.
*
* @example
* ```
*
* const { init } = require('@sentry/node');
*
* init({
* dsn: '__DSN__',
* // ...
* });
* ```
*
* @example
* ```
*
* const { configureScope } = require('@sentry/node');
* configureScope((scope: Scope) => {
* scope.setExtra({ battery: 0.7 });
* scope.setTag({ user_mode: 'admin' });
* scope.setUser({ id: '4711' });
* });
* ```
*
* @example
* ```
*
* const { addBreadcrumb } = require('@sentry/node');
* addBreadcrumb({
* message: 'My Breadcrumb',
* // ...
* });
* ```
*
* @example
* ```
*
* const Sentry = require('@sentry/node');
* Sentry.captureMessage('Hello, world!');
* Sentry.captureException(new Error('Good bye'));
* Sentry.captureEvent({
* message: 'Manual',
* stacktrace: [
* // ...
* ],
* });
* ```
*
* @see {@link NodeOptions} for documentation on configuration options.
*/
function init(options = {}) {
const carrier = getMainCarrier();
const autoloadedIntegrations = _optionalChain([carrier, 'access', _ => _.__SENTRY__, 'optionalAccess', _2 => _2.integrations]) || [];
options.defaultIntegrations =
options.defaultIntegrations === false
? []
: [
...(Array.isArray(options.defaultIntegrations) ? options.defaultIntegrations : defaultIntegrations),
...autoloadedIntegrations,
];
if (options.dsn === undefined && process.env.SENTRY_DSN) {
options.dsn = process.env.SENTRY_DSN;
}
if (options.tracesSampleRate === undefined && process.env.SENTRY_TRACES_SAMPLE_RATE) {
const tracesSampleRate = parseFloat(process.env.SENTRY_TRACES_SAMPLE_RATE);
if (isFinite(tracesSampleRate)) {
options.tracesSampleRate = tracesSampleRate;
}
}
if (options.release === undefined) {
const detectedRelease = getSentryRelease();
if (detectedRelease !== undefined) {
options.release = detectedRelease;
} else {
// If release is not provided, then we should disable autoSessionTracking
options.autoSessionTracking = false;
}
}
if (options.environment === undefined && process.env.SENTRY_ENVIRONMENT) {
options.environment = process.env.SENTRY_ENVIRONMENT;
}
if (options.autoSessionTracking === undefined && options.dsn !== undefined) {
options.autoSessionTracking = true;
}
if (options.instrumenter === undefined) {
options.instrumenter = 'sentry';
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
if ((domain ).active) {
setHubOnCarrier(carrier, getCurrentHub());
}
// TODO(v7): Refactor this to reduce the logic above
const clientOptions = {
...options,
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
integrations: getIntegrationsToSetup(options),
transport: options.transport || makeNodeTransport,
};
initAndBind(NodeClient, clientOptions);
if (options.autoSessionTracking) {
startSessionTracking();
}
}
/**
* This is the getter for lastEventId.
*
* @returns The last event id of a captured event.
*/
function lastEventId() {
return getCurrentHub().lastEventId();
}
/**
* Call `flush()` on the current client, if there is one. See {@link Client.flush}.
*
* @param timeout Maximum time in ms the client should wait to flush its event queue. Omitting this parameter will cause
* the client to wait until all events are sent before resolving the promise.
* @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it
* doesn't (or if there's no client defined).
*/
async function flush(timeout) {
const client = getCurrentHub().getClient();
if (client) {
return client.flush(timeout);
}
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Cannot flush events. No client defined.');
return Promise.resolve(false);
}
/**
* Call `close()` on the current client, if there is one. See {@link Client.close}.
*
* @param timeout Maximum time in ms the client should wait to flush its event queue before shutting down. Omitting this
* parameter will cause the client to wait until all events are sent before disabling itself.
* @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it
* doesn't (or if there's no client defined).
*/
async function close(timeout) {
const client = getCurrentHub().getClient();
if (client) {
return client.close(timeout);
}
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Cannot flush events and disable SDK. No client defined.');
return Promise.resolve(false);
}
/**
* Function that takes an instance of NodeClient and checks if autoSessionTracking option is enabled for that client
*/
function isAutoSessionTrackingEnabled(client) {
if (client === undefined) {
return false;
}
const clientOptions = client && client.getOptions();
if (clientOptions && clientOptions.autoSessionTracking !== undefined) {
return clientOptions.autoSessionTracking;
}
return false;
}
/**
* Returns a release dynamically from environment variables.
*/
function getSentryRelease(fallback) {
// Always read first as Sentry takes this as precedence
if (process.env.SENTRY_RELEASE) {
return process.env.SENTRY_RELEASE;
}
// This supports the variable that sentry-webpack-plugin injects
if (GLOBAL_OBJ.SENTRY_RELEASE && GLOBAL_OBJ.SENTRY_RELEASE.id) {
return GLOBAL_OBJ.SENTRY_RELEASE.id;
}
return (
// GitHub Actions - https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
process.env.GITHUB_SHA ||
// Netlify - https://docs.netlify.com/configure-builds/environment-variables/#build-metadata
process.env.COMMIT_REF ||
// Vercel - https://vercel.com/docs/v2/build-step#system-environment-variables
process.env.VERCEL_GIT_COMMIT_SHA ||
process.env.VERCEL_GITHUB_COMMIT_SHA ||
process.env.VERCEL_GITLAB_COMMIT_SHA ||
process.env.VERCEL_BITBUCKET_COMMIT_SHA ||
// Zeit (now known as Vercel)
process.env.ZEIT_GITHUB_COMMIT_SHA ||
process.env.ZEIT_GITLAB_COMMIT_SHA ||
process.env.ZEIT_BITBUCKET_COMMIT_SHA ||
fallback
);
}
/** Node.js stack parser */
const defaultStackParser = createStackParser(nodeStackLineParser(getModule));
/**
* Enable automatic Session Tracking for the node process.
*/
function startSessionTracking() {
const hub = getCurrentHub();
hub.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 = _optionalChain([hub, 'access', _3 => _3.getScope, 'call', _4 => _4(), 'optionalAccess', _5 => _5.getSession, 'call', _6 => _6()]);
const terminalStates = ['exited', 'crashed'];
// 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 && !terminalStates.includes(session.status)) hub.endSession();
});
}
export { close, defaultIntegrations, defaultStackParser, flush, getSentryRelease, init, isAutoSessionTrackingEnabled, lastEventId };
//# sourceMappingURL=sdk.js.map