通过前端的使用方法开始倒追源头,sentry js仓库地址为《传送门》
目录结构为
// 官方提供的react 初始化代码
import * as Sentry from '@sentry/react';
import {
BrowserTracing } from '@sentry/tracing';
Sentry.init({
dsn: 'https://[email protected]/123',
integrations: [new BrowserTracing()],
tracesSampleRate: 1.0,
});
由此,可以追溯Sentry.init,@sentry/react对应的就是packages/react目录,寻找src/index.js,找到init的引用地址。后续都一样,主要贴出一些关键代码。
// packages/react/src/sdk.ts
import {
BrowserOptions, init as browserInit, SDK_VERSION } from '@sentry/browser';
/**
* Inits the React SDK
*/
export function init(options: BrowserOptions): void {
options._metadata = options._metadata || {
};
options._metadata.sdk = options._metadata.sdk || {
name: 'sentry.javascript.react',
packages: [
{
name: 'npm:@sentry/react',
version: SDK_VERSION,
},
],
version: SDK_VERSION,
};
browserInit(options);
}
// packages/browser/src/sdk.ts
// 重点关注!!!
import {
Breadcrumbs, Dedupe, GlobalHandlers, HttpContext, LinkedErrors, TryCatch } from './integrations';
export const defaultIntegrations = [
new CoreIntegrations.InboundFilters(),
new CoreIntegrations.FunctionToString(),
new TryCatch(),
new Breadcrumbs(),
new GlobalHandlers(), // 重点关注!!!
new LinkedErrors(),
new Dedupe(),
new HttpContext(),
];
// 初始化时,补充配置项。
export function init(options: BrowserOptions = {
}): void {
// 各种错误监控的继承配置。
if (options.defaultIntegrations === undefined) {
options.defaultIntegrations = defaultIntegrations;
}
if (options.release === undefined) {
const window = getGlobalObject<Window>();
// This supports the variable that sentry-webpack-plugin injects
if (window.SENTRY_RELEASE && window.SENTRY_RELEASE.id) {
options.release = window.SENTRY_RELEASE.id;
}
}
if (options.autoSessionTracking === undefined) {
options.autoSessionTracking = true;
}
if (options.sendClientReports === undefined) {
options.sendClientReports = true;
}
const clientOptions: BrowserClientOptions = {
...options,
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
integrations: getIntegrationsToSetup(options),
transport: options.transport || (supportsFetch() ? makeFetchTransport : makeXHRTransport),
};
initAndBind(BrowserClient, clientOptions);
if (options.autoSessionTracking) {
startSessionTracking();
}
}
跳转至globalhandlers.ts进行查看前端的常用错误监控
/**
* Stores references functions to installing handlers. Will set to undefined
* after they have been run so that they are not used twice.
*/
private _installFunc: Record<GlobalHandlersIntegrationsOptionKeys, (() => void) | undefined> = {
onerror: _installGlobalOnErrorHandler,
onunhandledrejection: _installGlobalOnUnhandledRejectionHandler,
};
/** JSDoc */
function _installGlobalOnErrorHandler(): void {
addInstrumentationHandler(
'error',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(data: {
msg: any; url: any; line: any; column: any; error: any }) => {
const [hub, stackParser, attachStacktrace] = getHubAndOptions();
if (!hub.getIntegration(GlobalHandlers)) {
return;
}
const {
msg, url, line, column, error } = data;
if (shouldIgnoreOnError() || (error && error.__sentry_own_request__)) {
return;
}
const event =
error === undefined && isString(msg)
? _eventFromIncompleteOnError(msg, url, line, column)
: _enhanceEventWithInitialFrame(
eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false),
url,
line,
column,
);
event.level = 'error';
addMechanismAndCapture(hub, error, event, 'onerror');
},
);
}
/** JSDoc */
function _installGlobalOnUnhandledRejectionHandler(): void {
addInstrumentationHandler(
'unhandledrejection',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(e: any) => {
const [hub, stackParser, attachStacktrace] = getHubAndOptions();
if (!hub.getIntegration(GlobalHandlers)) {
return;
}
let error = e;
// dig the object of the rejection out of known event types
try {
// PromiseRejectionEvents store the object of the rejection under 'reason'
// see https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
if ('reason' in e) {
error = e.reason;
}
// something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents
// to CustomEvents, moving the `promise` and `reason` attributes of the PRE into
// the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec
// see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and
// https://github.com/getsentry/sentry-javascript/issues/2380
else if ('detail' in e && 'reason' in e.detail) {
error = e.detail.reason;
}
} catch (_oO) {
// no-empty
}
if (shouldIgnoreOnError() || (error && error.__sentry_own_request__)) {
return true;
}
const event = isPrimitive(error)
? _eventFromRejectionWithPrimitive(error)
: eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true);
event.level = 'error';
addMechanismAndCapture(hub, error, event, 'onunhandledrejection');
return;
},
);
}
/**
* Create an event from a promise rejection where the `reason` is a primitive.
*
* @param reason: The `reason` property of the promise rejection
* @returns An Event object with an appropriate `exception` value
*/
function _eventFromRejectionWithPrimitive(reason: Primitive): Event {
return {
exception: {
values: [
{
type: 'UnhandledRejection',
// String() is needed because the Primitive type includes symbols (which can't be automatically stringified)
value: `Non-Error promise rejection captured with value: ${
String(reason)}`,
},
],
},
};
}
/**
* This function creates a stack from an old, error-less onerror handler.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function _eventFromIncompleteOnError(msg: any, url: any, line: any, column: any): Event {
const ERROR_TYPES_RE =
/^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;
// If 'message' is ErrorEvent, get real message from inside
let message = isErrorEvent(msg) ? msg.message : msg;
let name = 'Error';
const groups = message.match(ERROR_TYPES_RE);
if (groups) {
name = groups[1];
message = groups[2];
}
const event = {
exception: {
values: [
{
type: name,
value: message,
},
],
},
};
return _enhanceEventWithInitialFrame(event, url, line, column);
}
/** JSDoc */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function _enhanceEventWithInitialFrame(event: Event, url: any, line: any, column: any): Event {
// event.exception
const e = (event.exception = event.exception || {
});
// event.exception.values
const ev = (e.values = e.values || []);
// event.exception.values[0]
const ev0 = (ev[0] = ev[0] || {
});
// event.exception.values[0].stacktrace
const ev0s = (ev0.stacktrace = ev0.stacktrace || {
});
// event.exception.values[0].stacktrace.frames
const ev0sf = (ev0s.frames = ev0s.frames || []);
const colno = isNaN(parseInt(column, 10)) ? undefined : column;
const lineno = isNaN(parseInt(line, 10)) ? undefined : line;
const filename = isString(url) && url.length > 0 ? url : getLocationHref();
// event.exception.values[0].stacktrace.frames
if (ev0sf.length === 0) {
ev0sf.push({
colno,
filename,
function: '?',
in_app: true,
lineno,
});
}
return event;
}