-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathsdk.ts
275 lines (253 loc) · 8.62 KB
/
sdk.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/* eslint-disable max-lines */
import { getCurrentHub, getIntegrationsToSetup, initAndBind, Integrations as CoreIntegrations } from '@sentry/core';
import { getMainCarrier, setHubOnCarrier } from '@sentry/hub';
import { SessionStatus, StackParser } from '@sentry/types';
import {
createStackParser,
getGlobalObject,
logger,
nodeStackLineParser,
stackParserFromStackParserOptions,
} from '@sentry/utils';
import * as domain from 'domain';
import { NodeClient } from './client';
import {
Console,
Context,
ContextLines,
Http,
LinkedErrors,
Modules,
OnUncaughtException,
OnUnhandledRejection,
} from './integrations';
import { getModule } from './module';
import { makeNodeTransport } from './transports';
import { NodeClientOptions, NodeOptions } from './types';
export const defaultIntegrations = [
// Common
new CoreIntegrations.InboundFilters(),
new CoreIntegrations.FunctionToString(),
// Native Wrappers
new Console(),
new Http(),
// Global Handlers
new OnUncaughtException(),
new OnUnhandledRejection(),
// Event Info
new ContextLines(),
new Context(),
new Modules(),
// 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.
*/
export function init(options: NodeOptions = {}): void {
const carrier = getMainCarrier();
const autoloadedIntegrations = carrier.__SENTRY__?.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;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
if ((domain as any).active) {
setHubOnCarrier(carrier, getCurrentHub());
}
// TODO(v7): Refactor this to reduce the logic above
const clientOptions: NodeClientOptions = {
...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.
*/
export function lastEventId(): string | undefined {
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).
*/
export async function flush(timeout?: number): Promise<boolean> {
const client = getCurrentHub().getClient<NodeClient>();
if (client) {
return client.flush(timeout);
}
__DEBUG_BUILD__ && 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).
*/
export async function close(timeout?: number): Promise<boolean> {
const client = getCurrentHub().getClient<NodeClient>();
if (client) {
return client.close(timeout);
}
__DEBUG_BUILD__ && 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
*/
export function isAutoSessionTrackingEnabled(client?: NodeClient): boolean {
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.
*/
export function getSentryRelease(fallback?: string): string | undefined {
// 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
const global = getGlobalObject();
if (global.SENTRY_RELEASE && global.SENTRY_RELEASE.id) {
return global.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 */
export const defaultStackParser: StackParser = createStackParser(nodeStackLineParser(getModule));
/**
* Enable automatic Session Tracking for the node process.
*/
function startSessionTracking(): void {
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 = hub.getScope()?.getSession();
const terminalStates: SessionStatus[] = ['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();
});
}