-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathexports.ts
336 lines (301 loc) · 10.7 KB
/
exports.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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
import { getClient, getCurrentScope, getIsolationScope, withIsolationScope } from './currentScopes';
import { DEBUG_BUILD } from './debug-build';
import type { CaptureContext } from './scope';
import { closeSession, makeSession, updateSession } from './session';
import type {
CheckIn,
Event,
EventHint,
EventProcessor,
Extra,
Extras,
FinishedCheckIn,
MonitorConfig,
Primitive,
Session,
SessionContext,
SeverityLevel,
User,
} from './types-hoist';
import { isThenable } from './utils-hoist/is';
import { logger } from './utils-hoist/logger';
import { uuid4 } from './utils-hoist/misc';
import { timestampInSeconds } from './utils-hoist/time';
import { GLOBAL_OBJ } from './utils-hoist/worldwide';
import type { ExclusiveEventHintOrCaptureContext } from './utils/prepareEvent';
import { parseEventHintOrCaptureContext } from './utils/prepareEvent';
/**
* Captures an exception event and sends it to Sentry.
*
* @param exception The exception to capture.
* @param hint Optional additional data to attach to the Sentry event.
* @returns the id of the captured Sentry event.
*/
export function captureException(exception: unknown, hint?: ExclusiveEventHintOrCaptureContext): string {
return getCurrentScope().captureException(exception, parseEventHintOrCaptureContext(hint));
}
/**
* Captures a message event and sends it to Sentry.
*
* @param message The message to send to Sentry.
* @param captureContext Define the level of the message or pass in additional data to attach to the message.
* @returns the id of the captured message.
*/
export function captureMessage(message: string, captureContext?: CaptureContext | SeverityLevel): string {
// This is necessary to provide explicit scopes upgrade, without changing the original
// arity of the `captureMessage(message, level)` method.
const level = typeof captureContext === 'string' ? captureContext : undefined;
const context = typeof captureContext !== 'string' ? { captureContext } : undefined;
return getCurrentScope().captureMessage(message, level, context);
}
/**
* Captures a manually created event and sends it to Sentry.
*
* @param event The event to send to Sentry.
* @param hint Optional additional data to attach to the Sentry event.
* @returns the id of the captured event.
*/
export function captureEvent(event: Event, hint?: EventHint): string {
return getCurrentScope().captureEvent(event, hint);
}
/**
* Sets context data with the given name.
* @param name of the context
* @param context Any kind of data. This data will be normalized.
*/
export function setContext(name: string, context: { [key: string]: unknown } | null): void {
getIsolationScope().setContext(name, context);
}
/**
* Set an object that will be merged sent as extra data with the event.
* @param extras Extras object to merge into current context.
*/
export function setExtras(extras: Extras): void {
getIsolationScope().setExtras(extras);
}
/**
* Set key:value that will be sent as extra data with the event.
* @param key String of extra
* @param extra Any kind of data. This data will be normalized.
*/
export function setExtra(key: string, extra: Extra): void {
getIsolationScope().setExtra(key, extra);
}
/**
* Set an object that will be merged sent as tags data with the event.
* @param tags Tags context object to merge into current context.
*/
export function setTags(tags: { [key: string]: Primitive }): void {
getIsolationScope().setTags(tags);
}
/**
* Set key:value that will be sent as tags data with the event.
*
* Can also be used to unset a tag, by passing `undefined`.
*
* @param key String key of tag
* @param value Value of tag
*/
export function setTag(key: string, value: Primitive): void {
getIsolationScope().setTag(key, value);
}
/**
* Updates user context information for future events.
*
* @param user User context object to be set in the current context. Pass `null` to unset the user.
*/
export function setUser(user: User | null): void {
getIsolationScope().setUser(user);
}
/**
* The last error event id of the isolation scope.
*
* Warning: This function really returns the last recorded error event id on the current
* isolation scope. If you call this function after handling a certain error and another error
* is captured in between, the last one is returned instead of the one you might expect.
* Also, ids of events that were never sent to Sentry (for example because
* they were dropped in `beforeSend`) could be returned.
*
* @returns The last event id of the isolation scope.
*/
export function lastEventId(): string | undefined {
return getIsolationScope().lastEventId();
}
/**
* Create a cron monitor check in and send it to Sentry.
*
* @param checkIn An object that describes a check in.
* @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want
* to create a monitor automatically when sending a check in.
*/
export function captureCheckIn(checkIn: CheckIn, upsertMonitorConfig?: MonitorConfig): string {
const scope = getCurrentScope();
const client = getClient();
if (!client) {
DEBUG_BUILD && logger.warn('Cannot capture check-in. No client defined.');
} else if (!client.captureCheckIn) {
DEBUG_BUILD && logger.warn('Cannot capture check-in. Client does not support sending check-ins.');
} else {
return client.captureCheckIn(checkIn, upsertMonitorConfig, scope);
}
return uuid4();
}
/**
* Wraps a callback with a cron monitor check in. The check in will be sent to Sentry when the callback finishes.
*
* @param monitorSlug The distinct slug of the monitor.
* @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want
* to create a monitor automatically when sending a check in.
*/
export function withMonitor<T>(
monitorSlug: CheckIn['monitorSlug'],
callback: () => T,
upsertMonitorConfig?: MonitorConfig,
): T {
const checkInId = captureCheckIn({ monitorSlug, status: 'in_progress' }, upsertMonitorConfig);
const now = timestampInSeconds();
function finishCheckIn(status: FinishedCheckIn['status']): void {
captureCheckIn({ monitorSlug, status, checkInId, duration: timestampInSeconds() - now });
}
return withIsolationScope(() => {
let maybePromiseResult: T;
try {
maybePromiseResult = callback();
} catch (e) {
finishCheckIn('error');
throw e;
}
if (isThenable(maybePromiseResult)) {
Promise.resolve(maybePromiseResult).then(
() => {
finishCheckIn('ok');
},
e => {
finishCheckIn('error');
throw e;
},
);
} else {
finishCheckIn('ok');
}
return maybePromiseResult;
});
}
/**
* 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 = getClient();
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 = getClient();
if (client) {
return client.close(timeout);
}
DEBUG_BUILD && logger.warn('Cannot flush events and disable SDK. No client defined.');
return Promise.resolve(false);
}
/**
* Returns true if Sentry has been properly initialized.
*/
export function isInitialized(): boolean {
return !!getClient();
}
/** If the SDK is initialized & enabled. */
export function isEnabled(): boolean {
const client = getClient();
return client?.getOptions().enabled !== false && !!client?.getTransport();
}
/**
* Add an event processor.
* This will be added to the current isolation scope, ensuring any event that is processed in the current execution
* context will have the processor applied.
*/
export function addEventProcessor(callback: EventProcessor): void {
getIsolationScope().addEventProcessor(callback);
}
/**
* Start a session on the current isolation scope.
*
* @param context (optional) additional properties to be applied to the returned session object
*
* @returns the new active session
*/
export function startSession(context?: SessionContext): Session {
const isolationScope = getIsolationScope();
const currentScope = getCurrentScope();
// Will fetch userAgent if called from browser sdk
const { userAgent } = GLOBAL_OBJ.navigator || {};
const session = makeSession({
user: currentScope.getUser() || isolationScope.getUser(),
...(userAgent && { userAgent }),
...context,
});
// End existing session if there's one
const currentSession = isolationScope.getSession();
if (currentSession?.status === 'ok') {
updateSession(currentSession, { status: 'exited' });
}
endSession();
// Afterwards we set the new session on the scope
isolationScope.setSession(session);
return session;
}
/**
* End the session on the current isolation scope.
*/
export function endSession(): void {
const isolationScope = getIsolationScope();
const currentScope = getCurrentScope();
const session = currentScope.getSession() || isolationScope.getSession();
if (session) {
closeSession(session);
}
_sendSessionUpdate();
// the session is over; take it off of the scope
isolationScope.setSession();
}
/**
* Sends the current Session on the scope
*/
function _sendSessionUpdate(): void {
const isolationScope = getIsolationScope();
const client = getClient();
const session = isolationScope.getSession();
if (session && client) {
client.captureSession(session);
}
}
/**
* Sends the current session on the scope to Sentry
*
* @param end If set the session will be marked as exited and removed from the scope.
* Defaults to `false`.
*/
export function captureSession(end: boolean = false): void {
// both send the update and pull the session from the scope
if (end) {
endSession();
return;
}
// only send the update
_sendSessionUpdate();
}