Sentry前端错误监控 源码小品

通过前端的使用方法开始倒追源头,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;
}

猜你喜欢

转载自blog.csdn.net/qq_28992047/article/details/125559956