Repository navigation
Expand file tree
/
Copy pathsentry.ts
More file actions
111 lines (101 loc) · 4.08 KB
/
Copy pathsentry.ts
File metadata and controls
111 lines (101 loc) · 4.08 KB
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
import { ErrorHandler, Injectable, Injector, isDevMode } from '@angular/core';
import { authority, isMock } from '@placeos/ts-client';
import { VERSION } from '../../env/version';
import { isHandledChunkLoadError } from './application';
import { log } from './general';
/** DSN for deployments that do not set `config.backoffice.sentry_dsn` */
const DEFAULT_SENTRY_DSN =
'https://7941b5b93d7c4712803604891cdfec23@o437082.ingest.sentry.io/5399124';
/** Most errors kept while Sentry loads */
const MAX_QUEUED_ERRORS = 20;
/** Release name. CI uploads source maps with this name. */
export const SENTRY_RELEASE = `backoffice@${VERSION.hash}`;
type ErrorReporter = (error: unknown) => void;
let _reporter: ErrorReporter | null = null;
let _queue: unknown[] | null = [];
/**
* Send an error to Sentry. Before Sentry loads, keep the error in a queue.
* After Sentry is turned off, drop it.
*/
export function reportError(error: unknown) {
if (_reporter) return _reporter(error);
if (_queue && _queue.length < MAX_QUEUED_ERRORS) _queue.push(error);
}
/**
* True for the error Monaco uses to cancel pending work. Monaco does not
* handle some of these rejections, for example when an editor is disposed
* while a word highlight is pending. They are not failures.
* Same check as Monaco's `isCancellationError`.
*/
function isMonacoCancellation(error: unknown) {
return (
error instanceof Error &&
error.name === 'Canceled' &&
error.message === 'Canceled'
);
}
/**
* Angular error handler. Logs errors to the console as the default handler
* does, and sends them to Sentry. Ignores Monaco cancellations and lazy route
* chunk failures that the router error handler already handled.
*/
@Injectable()
export class SentryReportingErrorHandler implements ErrorHandler {
public handleError(error: unknown) {
if (isMonacoCancellation(error) || isHandledChunkLoadError(error)) {
return;
}
console.error(error);
reportError(error);
}
}
/**
* DSN for this deployment. The authority can set `config.backoffice.sentry_dsn`
* to a different DSN, or to `''` or `false` to turn Sentry off.
*/
export function sentryDsn(): string {
const value = authority()?.config?.backoffice?.sentry_dsn;
if (value === undefined || value === null) return DEFAULT_SENTRY_DSN;
return typeof value === 'string' ? value : '';
}
/**
* Load and start Sentry. Call once after the authority and user load.
* Does nothing on localhost, in mock mode or when the DSN is empty.
*/
export async function initSentry(injector: Injector, user_id: string) {
const dsn = sentryDsn();
if (!dsn || isMock() || location.hostname === 'localhost') {
_queue = null;
return;
}
const Sentry = await import('@sentry/angular');
Sentry.init({
dsn,
release: SENTRY_RELEASE,
environment: isDevMode() ? 'development' : 'production',
// Chrome raises this when resize notifications move to the next frame.
// It does no harm. In dev mode Angular adds a prefix to the message,
// so Sentry's default filter does not match it.
ignoreErrors: [/ResizeObserver loop/],
integrations: (defaults) => [
// Angular's global error listeners already send window errors
// to the error handler. This prevents duplicate events.
...defaults.filter(({ name }) => name !== 'GlobalHandlers'),
Sentry.browserTracingIntegration(),
Sentry.replayIntegration(),
],
tracesSampleRate: isDevMode() ? 1 : 0.1,
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: 1,
});
// Starts the router spans for the tracing integration
injector.get(Sentry.TraceService);
Sentry.setUser({ id: user_id });
Sentry.setTag('domain', authority()?.domain || location.hostname);
const handler = Sentry.createErrorHandler({ logErrors: false });
_reporter = (error) => handler.handleError(error);
const queued = _queue || [];
_queue = null;
queued.forEach(_reporter);
log('Sentry', `Reporting errors for ${SENTRY_RELEASE}`);
}