天天看點

Sentry For React 完整接入詳解(2021 Sentry v21.8.x)前方高能預警!三萬字,慎入!

Sentry For React 完整接入詳解(2021 Sentry v21.8.x)前方高能預警!三萬字,慎入!

内容源于:https://docs.sentry.io/platforms/javascript/guides/react/

系列

  • 1 分鐘快速使用 Docker 上手最新版 Sentry-CLI - 建立版本
  • 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps

腦圖

Sentry For React 完整接入詳解(2021 Sentry v21.8.x)前方高能預警!三萬字,慎入!
公衆号:黑客下午茶
           

快速開始

Sentry

React SDK

支援自動報告錯誤和異常。

SDK

@sentry/browser

的包裝器,增加了與

React

相關的功能。

@sentry/browser

中可用的所有方法都可以從

@sentry/react

中導入。

安裝

Sentry

通過在應用程式

runtime

使用

SDK

捕獲資料。

# 使用 npm
npm install --save @sentry/react @sentry/tracing
# 使用 yarn
yarn add @sentry/react @sentry/tracing


export const _frontmatter = {}
           

配置

配置應該在應用程式的生命周期中盡早進行。

import React from "react";
import ReactDOM from "react-dom";
import * as Sentry from "@sentry/react";
import { Integrations } from "@sentry/tracing";
import App from "./App";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new Integrations.BrowserTracing()],

  // 我們建議在生産中調整此值,或使用 tracesSampler 進行更精細的控制
  tracesSampleRate: 1.0,
});

ReactDOM.render(<App />, document.getElementById("root"));

// 也可以與 React Concurrent Mode 一起使用
// ReactDOM.createRoot(document.getElementById('root')).render(<App />);
           

一旦完成,所有未處理的異常都會被

Sentry

自動捕獲。

添加 Error Boundary

如果您使用的是

React 16

或更高版本,則可以使用

Error Boundary

元件将元件樹内部的

Javascript

錯誤自動發送到

Sentry

,并設定回退

UI

設定 React Router

React Router 內建

旨在與我們的跟蹤包一起使用。請在下方

配置

部分了解有關

React Router Integration

及其選項的更多資訊。

應用 Redux

要将

Sentry

應用于

Redux

,請在下方

配置

部分了解有關

Redux Integration

及其選項的更多資訊。

驗證

此代碼段包含一個故意錯誤,是以您可以在設定後立即測試一切是否正常:

return <button onClick={methodDoesNotExist}>Break the world</button>;
           

元件

Sentry React SDK

公開自定義元件,以便與 React 架構進行一級內建。

React Error Boundary

React SDK

導出一個錯誤邊界元件,該元件利用

React component API

自動捕獲

JavaScript

錯誤并将其從

React

元件樹内部發送到

Sentry

import React from "react";
import * as Sentry from "@sentry/react";

<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
  <Example />
</Sentry.ErrorBoundary>;
           

Sentry Error Boundary

也可用作高階元件。

import React from "react";
import * as Sentry from "@sentry/react";

Sentry.withErrorBoundary(Example, { fallback: <p>an error has occurred</p> });
           
Note:在

development

模式下,

React

會重新抛出在錯誤邊界内捕獲的錯誤。 這将導緻使用上述設定向

Sentry

報告兩次錯誤,但這不會發生在您的生産版本中。

在下面的示例中,當

<Example />

元件遇到錯誤時,

<Sentry.ErrorBoundary>

元件會将有關該錯誤的資料群組件樹發送到

Sentry

,打開使用者回報對話框,并呈現

fallback UI

import React from "react";
import * as Sentry from "@sentry/react";

import { Example } from "../example";

function FallbackComponent() {
  return <div>An error has occurred</div>;
}

const myFallback = <FallbackComponent />;
// Alternatively:
// const myFallback = () => <FallbackComponent />;

class App extends React.Component {
  render() {
    return (
      <Sentry.ErrorBoundary fallback={myFallback} showDialog>
        <Example />
      </Sentry.ErrorBoundary>
    );
  }
}

export default App;
           

選項

ErrorBoundary

元件公開了各種可以傳入以進行額外配置的屬性。 沒有必需的選項,但我們強烈建議您設定

fallback

元件。

showDialog

(boolean)

  • Error Boundary

    捕捉到錯誤時,是否應呈現

    Sentry User Feedback Widget

dialogOptions

(Object)

  • 傳遞到

    Sentry User Feedback Widget

    的選項。在下方檢視所有可能的自定義選項。
    • https://docs.sentry.io/platforms/javascript/guides/react/enriching-events/user-feedback/#customizing-the-widget

fallback

(React.ReactNode or Function)

  • 當錯誤邊界捕獲錯誤時要呈現的

    React

    元素。可以是實際的

    React

    元素(即

    <Fallback />

    ),也可以是傳回

    React

    元素的函數。如果您提供一個函數,

    Sentry

    将使用附加資訊和幫助程式調用它(參見下面的示例)。

onError

(Function)

  • Error Boundary

    遇到錯誤時調用的函數。如果您想将錯誤傳播到

    Redux

    之類的狀态管理庫中,或者您想檢查由于錯誤而可能發生的任何副作用,

    onError

    非常有用。

onUnmount

(Function)

  • ErrorBoundary componentWillUnmount()

    上調用的函數。

beforeCapture

(Function)

*(

5.20.0

及以上版本可用)

  • 在将錯誤發送到

    Sentry

    之前調用的函數,允許将額外的标簽(

    tag

    )或上下文(

    context

    )添加到錯誤中。

示例

設定 Fallback 函數(渲染屬性)

下面是一個示例,其中使用渲染屬性方法的

fallback

屬性用于在錯誤時顯示

fallback UI

。使用元件通過渲染屬性提供的

resetError() API

重置時,

fallback UI

會傳回到标準元件狀态。

import React from "react";
import * as Sentry from "@sentry/react";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: "This is my app",
    };
  }

  render() {
    return (
      <Sentry.ErrorBoundary
        fallback={({ error, componentStack, resetError }) => (
          <React.Fragment>
            <div>You have encountered an error</div>
            <div>{error.toString()}</div>
            <div>{componentStack}</div>
            <button
              onClick={() => {
                this.setState({ message: "This is my app" });
                {/* When resetError() is called it will remove the Fallback component */}
                {/* and render the Sentry ErrorBoundary's children in their initial state */}
                resetError();
              }}
            >
              Click here to reset!
            </button>
          </React.Fragment>
        )}
      >
        <div>{this.state.message}</div>
        {/* on click, this button sets an Object as a message, not a string. */}
        {/* which will cause an error to occur in the component tree */}
        <button
          onClick={() => this.setState({ message: { text: "Hello World" } })}
        >
          Click here to change message!
        </button>
      </Sentry.ErrorBoundary>
    );
  }
}

export default App;
           

使用多個錯誤邊界

(5.20.0 及以上版本可用)

當使用多個錯誤邊界時,我們建議使用

beforeCapture

設定

标簽/上下文(tags/context)

,以便您可以知道錯誤發生在哪個錯誤邊界。 在下面的示例中,我們根據錯誤渲染的路徑将标記(

tag

)附加到錯誤(

error

)。

import React from 'react';
import * as Sentry from '@sentry/react';

function App({ props }) {
  return (
    <React.Fragment>
      <Sentry.ErrorBoundary
        beforeCapture={(scope) => {
          scope.setTag("location", "first");
          scope.setTag("anotherTag", "anotherValue");
        }}
      >
        <Route to="path/to/first" component={First} />
      </Sentry.ErrorBoundary>
      <Sentry.ErrorBoundary
        beforeCapture={(scope) => {
          scope.setTag("location", "second");
        }}
      >
        <Route to="path/to/second" component={Second} />
      </Sentry.ErrorBoundary>
    </React.Fragment>
  );
}

export default App;
           

React Profiler

@sentry/react

導出一個

withProfiler

高階元件,該元件将

React

相關的

span

附加到作用域上的目前活動事務(

transaction

)。

在下面的示例中,

withProfiler

高階元件用于檢測

App

元件。

import React from "react";
import * as Sentry from "@sentry/react";

class App extends React.Component {
  render() {
    return (
      <FancyComponent>
        <NestedComponent someProp={2} />
        <AnotherComponent />
      </FancyComponent>
    );
  }
}

export default Sentry.withProfiler(App);
           

React Profiler

目前使用三種不同類型的操作碼(

op-codes

)生成

span

react.mount

react.render

react.update

react.mount

  • 表示被分析元件

    mount

    所需時間的跨度。

react.render

  • 表示被分析元件在頁面上的時間跨度。隻有在事務發生時

    mount

    unmount

    被分析的元件時,才會生成這個跨度。

react.update

  • 表示被分析元件更新時的跨度。隻有當被分析元件已

    mount

    時才生成此

    span

React Strict Mode

下,某些元件方法将被調用兩次。這可能會導緻在事務中出現重複的

react.mount

跨度。

React Strict Mode

僅在開發模式下運作,是以這不會影響您的生産跟蹤。

Profiler 選項

withProfiler

高階元件有多種選項可用于進一步定制。它們可以作為第二個參數傳入

withProfiler

函數。

export default Sentry.withProfiler(App, { name: "CustomAppName" });
           

name

(string)

  • 被分析的元件的名稱。預設情況下,名稱取自元件的

    displayName

    屬性或元件的

    name

    屬性。

includeRender

(boolean)

  • 是否應該由

    Profiler

    建立

    react.render

    跨度。預設設定為

    true

includeUpdates

(boolean)

  • react.update

    spans 是否應該由

    Profiler

    建立。預設設定為

    true

    。 對于将經曆多次重新渲染的元件(例如文本輸入

    text input

    元件),我們建議将此屬性設定為

    false

    ,因為生成的

    span

    可能非常嘈雜。

配置

基本選項

SDK

可以使用多種選項進行配置。這些選項在

SDK

中基本上是标準化的,但在更好地适應平台特性方面存在一些差異。選項是在

SDK

首次初始化時設定的。

選項作為對象傳遞給

init()

函數:

Sentry.init({
  dsn: "https://[email protected]/0",
  maxBreadcrumbs: 50,
  debug: true,
});
           

常見選項

SDK

的常用選項清單。這些在所有

SDK

中的工作方式或多或少都相同,但為了更好地支援平台,将存在一些細微差别。 可以從環境變量(

SENTRY_DSN

SENTRY_ENVIRONMENT

SENTRY_RELEASE

)中讀取的選項會自動讀取。

dsn

DSN

告訴

SDK

将事件發送到哪裡。如果沒有提供這個值,

SDK

将嘗試從

SENTRY_DSN

環境變量中讀取它。如果這個變量也不存在,

SDK

就不會發送任何事件。

在沒有程序環境(如浏覽器)的運作時中,

fallback

不會應用。

更多:https://docs.sentry.io/product/sentry-basics/dsn-explainer/#dsn-utilization

debug

打開或關閉調試模式。如果啟用了調試,如果發送事件時出現問題,

SDK

将嘗試列印出有用的調試資訊。預設值總是

false

。一般不建議在生産環境中打開它,盡管打開

debug

模式不會引起任何安全問題。

release

設定 release。某些

SDK

會嘗試自動配置

release

,但是最好手動設定

release

,以確定該

release

與您的

deploy integrations

source map uploads

同步。

Release

名稱是字元串,但是

Sentry

會檢測到某些格式,并且它們的呈現方式可能有所不同。

更多:https://docs.sentry.io/product/releases/

預設情況下,

SDK

會嘗試從環境變量

SENTRY_RELEASE

中讀取該值(在浏覽器

SDK

中,将從

window.SENTRY_RELEASE

中讀取該值,如果可用)。

environment

設定環境。此字元串為自由形式,預設情況下不設定。一個

release

可以與多個環境相關聯,以便在 UI 中将它們分開(可以考慮

staging

prod

或類似的方式)。

預設情況下,

SDK

将嘗試從

SENTRY_ENVIRONMENT

環境變量中讀取該值(浏覽器

SDK

除外)。

tunnel

設定将用于傳輸捕獲事件的

URL

,而不是使用

DSN

。這可用于解決廣告攔截器(

ad-blockers

)或對發送到

Sentry

的事件進行更精細的控制。此選項需要實作自定義伺服器端點。

更多:https://docs.sentry.io/platforms/javascript/troubleshooting/#dealing-with-ad-blockers

sampleRate

配置錯誤事件的采樣率,範圍為

0.0

1.0

。預設值為

1.0

,表示發送了

100%

的錯誤事件。如果設定為

0.1

,則僅發送

10%

的錯誤事件。事件是随機選擇的。

maxBreadcrumbs

這個變量控制應該捕獲的面包屑總數。預設值為

100

attachStacktrace

當啟用時,堆棧跟蹤将自動附加到所有記錄的消息。堆棧跟蹤總是附加到異常;然而,當設定此選項時,堆棧跟蹤也會與消息一起發送。例如,該選項意味着堆棧跟蹤顯示在所有日志消息的旁邊。

該選項預設為

off

Sentry

中的分組對于有和沒有堆棧跟蹤的事件是不同的。是以,當您為某些事件啟用或禁用此

flag

時,您将獲得新組。

denyUrls

與不應該發送到

Sentry

的錯誤

URL

相比對的字元串或正規表達式模式清單。預設情況下,将發送所有錯誤。這是一個 “contains(包含)” 比對整個檔案 URL。是以,如果你添加

foo.com

,它也會比對

https://bar.com/myfile/foo.com

。預設情況下,将發送所有錯誤。

allowUrls

比對錯誤

URL

的字元串清單或正規表達式模式的遺留别名,這些錯誤

URL

應該專門發送給

Sentry

。預設情況下,将發送所有錯誤。這是一個 “contains(包含)” 比對整個檔案 URL。是以,如果您将

foo.com

添加到它,它也将比對

https://bar.com/myfile/foo.com

。預設情況下,所有錯誤将被發送。

autoSessionTracking

設定為

true

時,

SDK

将向

Sentry

發送

session

事件。這在所有浏覽器

SDK

中都受支援,每個頁面加載和頁面導航都向

Sentry

發出一個

session

。在移動

SDK

中,當應用進入背景超過

30

秒時,會話結束。

initialScope

要設定為初始作用域的資料。初始作用域可以定義為對象或回調函數,如下所示。

對象:

Sentry.init({
  dsn: "https://[email protected]/0",
  debug: true,
  initialScope: {
    tags: {"my-tag": "my value"},
    user: {id: 42, email: "[email protected]"},
  }
});
           

回調函數:

Sentry.init({
  dsn: "https://[email protected]/0",
  debug: true,
  initialScope: scope => {
    scope.setTags({ a: 'b' });
    return scope;
  },
});
           
maxValueLength

單個值在被截斷之前可以具有的最大字元數(預設為

250

)。

normalizeDepth

Sentry SDK

将任何上下文資料标準化到給定的深度。 任何包含結構比這更深的資料的

key

都将使用其類型(

[Object]

[Array]

)進行修剪和标記,而不會進一步周遊樹。預設情況下,步行執行

3

級深度。

內建配置

對于許多平台,SDK 內建可以與之一起配置。在一些平台上,這是

init()

調用的一部分,而在另一些平台上,則應用不同的模式。

integrations

在某些 SDK 中,在庫初始化時通過此參數配置內建。

更多:

defaultIntegrations

這可以用來禁用預設添加的內建。當設定為

false

時,不會添加預設的內建。

Hooks

這些選項可用于以各種方式 hook

SDK

,以定制事件的報告。

beforeSend

使用

SDK-specific

事件對象調用此函數,可以傳回修改後的事件對象或不傳回任何内容,以跳過報告事件。例如,這可以用于在發送前手動剝離

PII

beforeBreadcrumb

在将面包屑添加到作用域之前,使用

SDK

特定的面包屑(

SDK-specific breadcrumb

)對象調用此函數。當該函數未傳回任何内容時,将删除

breadcrumb

。要傳遞

breadcrumb

,請傳回第一個參數,其中包含

breadcrumb

對象。回調通常會獲得第二個參數(稱為

“hint”

),該參數包含建立

breadcrumb

的原始對象,以進一步自定義面包屑的外觀。

傳輸選項

Transports

被用來發送事件到

Sentry

。可以在某種程度上對傳輸進行定制,以更好地支援高度特定的部署。

transport

切換出用于發送事件的

transport

。如何運作取決于

SDK

。例如,它可以用于捕獲事件以進行單元測試,或通過需要代理身份驗證的更複雜的設定發送事件。

跟蹤選項

tracesSampleRate

1

之間的數字,控制給定事務發送到

Sentry

的機率百分比。(

表示

0%

1

表示

100%

)同樣适用于應用程式中建立的所有事務。必須定義這個或

tracesSampler

以啟用跟蹤。

tracesSampler

一個函數負責确定一個給定的事務将被發送到

Sentry

的機率百分比。它将自動被傳遞有關事務和建立它的上下文的資訊,并且必須傳回一個介于

(被發送的機率為

0%

)和

1

(被發送的機率為

100%

) 之間的數字。還可以用于過濾事務,對不需要的事務傳回

。必須定義這個或

tracesSampleRate

來啟用跟蹤。

內建

預設內建

Sentry

的所有

SDK

都提供內建,可擴充

SDK

的功能。

預設情況下啟用系統內建以內建到标準庫或解釋器本身。 它們被記錄在案,是以您既可以了解它們的作用,也可以在它們引起問題時禁用它們。

預設啟用

InboundFilters

Import name:

Sentry.Integrations.InboundFilters

通過這種內建,您可以根據給定異常中的類型,消息或 URL 忽略特定錯誤。

預設情況下,它忽略以

Script error

Javascript error: Script error

開頭的錯誤。

要配置這個內建,直接使用

ignoreErrors

denyUrls

,和

allowUrls

SDK 選項。請記住,

denyURL

allowURL

隻對捕獲的異常有效,而不是原始消息事件。

FunctionToString

Import name:

Sentry.Integrations.FunctionToString

這種內建使

SDK

可以提供原始的函數和方法名稱,即使我們的錯誤(

error

)或面包屑處理程式(

breadcrumbs handlers

)包裝了它們也是如此。

TryCatch

Import name:

Sentry.Integrations.TryCatch

這個內建封裝了原生

time

events APIs

(

setTimeout

,

setInterval

,

requestAnimationFrame

,

addEventListener/removeEventListener

) 在

try/catch

塊處理

async

異常。

Breadcrumbs

Import name:

Sentry.Integrations.Breadcrumbs

這種內建封裝了原生 API 以捕獲面包屑。預設情況下,

Sentry SDK

封裝了所有

API

可用選項:

{
  // 記錄對 `console.log`、`console.debug` 等的調用
  console: boolean;

  // 記錄所有點選和按鍵事件
  // - 當提供帶有 `serializeAttribute` key 的對象時,
  //   面包屑內建将在 DOM 元素中查找給定的屬性,同時生成面包屑路徑。
  //   比對的元素後跟它們的自定義屬性,而不是它們的 `id` 或 `class` 名稱。
  dom: boolean | { serializeAttribute: string | string[] };

  // 記錄使用 `Fetch API` 完成的 `HTTP` 請求
  fetch: boolean;

  // 記錄對 `history.pushState` 的調用
  history: boolean;

  // 每當我們向伺服器發送事件時記錄
  sentry: boolean;

  // 記錄使用 XHR API 完成的 HTTP 請求
  xhr: boolean;
}
           

GlobalHandlers

Import name:

Sentry.Integrations.GlobalHandlers

這個內建附加了全局處理程式來捕獲未捕獲的

exceptions

和未處理的

rejections

可用的選項:

{
  onerror: boolean;
  onunhandledrejection: boolean;
}
           

LinkedErrors

Import name:

Sentry.Integrations.LinkedErrors

此內建允許您配置

linked

錯誤。它們将被遞歸地讀取到指定的限制,并由特定的

key

執行查找。預設情況下,

Sentry SDK

将限制設定為

5

,使用的鍵

key

cause

可用的選項:

{
  key: string;
  limit: number;
}
           

這是如何實作的代碼示例:

document
  .querySelector("#get-reviews-btn")
  .addEventListener("click", async event => {
    const movie = event.target.dataset.title;
    try {
      const reviews = await fetchMovieReviews(movie);
      renderMovieReviews(reviews);
    } catch (e) {
      const fetchError = new Error(`Failed to fetch reviews for: ${movie}`);
      fetchError.cause = e;
      Sentry.captureException(fetchError);
      renderMovieReviewsError(fetchError);
    }
  });
           

UserAgent

Import name:

Sentry.Integrations.UserAgent

這種內建将

user-agent

資訊附加到事件中,這使我們能夠正确地分類并使用特定的作業系統(

OS

),浏覽器(

browser

)和版本(

version

)資訊對其進行标記。

Dedupe

Import name:

Sentry.Integrations.Dedupe

這種內建消除了某些事件的重複資料。如果您收到許多重複的錯誤,這會很有幫助。請注意,

Sentry

隻會比較堆棧跟蹤(

stack traces

)和指紋(

fingerprints

)。預設情況下為浏覽器啟用此內建。

import * as Sentry from "@sentry/browser";
import { Dedupe as DedupeIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new DedupeIntegration()],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/dedupe.min.js"
  integrity="sha384-3IMGY+DN27Yns7KDiKL3sOWXBYlILQ/bxLogt02NG7DL7qEJHIMbpnXfqNlO0J8G"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://examplePublic[email protected]/0",
  integrations: [new Dedupe()],
});
           
修改系統內建

要禁用系統內建,請在調用

init()

時設定

defaultIntegrations: false

要覆寫它們的設定,請提供一個帶有您的配置到內建選項的新執行個體。 例如,要關閉浏覽器捕獲控制台調用:

integrations: [new Sentry.Integrations.Breadcrumbs({ console: false })]

删除內建

此示例删除了用于向事件添加面包屑的預設啟用內建:

Sentry.init({
  // ...

  integrations: function(integrations) {
    // integrations will be all default integrations
    return integrations.filter(function(integration) {
      return integration.name !== "Breadcrumbs";
    });
  },
});
           

可插拔內建

這些可插拔的內建是為特定的應用程式和/或架構增加功能的代碼片段。我們對它們進行了記錄,這樣您就可以看到它們的功能,并且可以啟用它們。

如何啟用

安裝

@sentry/integrations

包,并提供一個帶有你配置到

integrations

選項的新執行個體。加載

SDK

之後,包括插件。

示例:

import * as Sentry from "@sentry/browser";
import { ReportingObserver as ReportingObserverIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new ReportingObserverIntegration()],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/reportingobserver.min.js"
  integrity="sha384-20D83MPBNSRANJFguhj0o9Qo7p9MCemwdMMQXotwA8742WuIwga85k+T7qEgIMWK"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new ReportingObserver()],
});
           

ExtraErrorData

Import name:

Sentry.Integrations.ExtraErrorData

這個內建從錯誤對象中提取所有非原生(non-native)屬性,并将它們作為

extra

資料附加到事件中。

可用的選項:

import * as Sentry from "@sentry/browser";
import { ExtraErrorData as ExtraErrorDataIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new ExtraErrorDataIntegration(
    {
      // limit of how deep the object serializer should go. Anything deeper than limit will
      // be replaced with standard Node.js REPL notation of [Object], [Array], [Function] or
      // a primitive value. Defaults to 3.
      depth: number;
    }
  )],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/extraerrordata.min.js"
  integrity="sha384-DMO/ZWwA4ztkOtskx1Uad3cH6lbfSA/PGdW2IZ7A/c2qd/BU6zh5xiJ5D4nxJbye"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new ExtraErrorData(
    {
      // limit of how deep the object serializer should go. Anything deeper than limit will
      // be replaced with standard Node.js REPL notation of [Object], [Array], [Function] or
      // a primitive value. Defaults to 3.
      depth: number;
    }
  )],
});
           

CaptureConsole

Import name:

Sentry.Integrations.CaptureConsole

這種內建捕獲所有的

Console API

調用,并使用

captureMessage

調用将它們重定向到

Sentry

。然後,它會重新觸發以保留預設的原生行為。

import * as Sentry from "@sentry/browser";
import { CaptureConsole as CaptureConsoleIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new CaptureConsoleIntegration(
    {
      // array of methods that should be captured
      // defaults to ['log', 'info', 'warn', 'error', 'debug', 'assert']
      levels: string[];
    }
  )],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/captureconsole.min.js"
  integrity="sha384-FJ5n80A08NroQF9DJzikUUhiCaQT2rTIYeJyHytczDDbIiejfcCzBR5lQK4AnmVt"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new CaptureConsole(
    {
      // array of methods that should be captured
      // defaults to ['log', 'info', 'warn', 'error', 'debug', 'assert']
      levels: string[];
    }
  )],
});
           

Debug

Import name:

Sentry.Integrations.Debug

通過這種內建,您可以檢查已處理事件的内容,該事件将被傳遞到

beforeSend

并有效地發送到

Sentry SDK

。無論何時注冊,它都将始終作為最後的內建運作。

可用的選項:

import * as Sentry from "@sentry/browser";
import { Debug as DebugIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new DebugIntegration(
    {
      // trigger DevTools debugger instead of using console.log
      debugger: boolean;

      // stringify event before passing it to console.log
      stringify: boolean;
    }
  )],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/debug.min.js"
  integrity="sha384-OIzIETBTnmaXcnCVlI4DzHq1+YxDdBS6uyZPp8yS60YZNUqzIQvrudJplBqEZ09K"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new Debug(
    {
      // trigger DevTools debugger instead of using console.log
      debugger: boolean;

      // stringify event before passing it to console.log
      stringify: boolean;
    }
  )],
});
           

Offline

Import name:

Sentry.Integrations.Offline

此內建使用

Web

浏覽器的

線上和離線事件

來檢測何時沒有可用的網絡連接配接。如果離線,它會将事件儲存到

Web

浏覽器的用戶端存儲(通常是

IndexedDB

),然後在網絡連接配接恢複時自動上傳事件。

Online and offline events

  • https://developer.mozilla.org/en-US/docs/Web/API/Navigator/Online_and_offline_events

此插件不會嘗試為其他場景提供本地存儲或重試。 例如,如果浏覽器有本地連接配接但沒有網際網路連接配接,那麼它可能會報告它線上,并且在這種情況下,

Sentry

Offline

插件不會嘗試儲存或重試任何發送失敗。

import * as Sentry from "@sentry/browser";
import { Offline as OfflineIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new OfflineIntegration(
    {
      // limit how many events will be localled saved. Defaults to 30.
      maxStoredEvents: number;
    }
  )],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/offline.min.js"
  integrity="sha384-rRq5WRQ3OncIj4lduaVZMtyfVwZnqeWXM0nXyXckOrhFLS2mlKEYX+VAlbLlIZL4"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new Offline(
    {
      // limit how many events will be localled saved. Defaults to 30.
      maxStoredEvents: number;
    }
  )],
});
           

RewriteFrames

Import name: Sentry.Integrations.RewriteFrames

這種內建允許您對堆棧跟蹤的每個幀應用轉換。 在流線型(

streamlined

)場景中,它可用于更改其來源的檔案幀的名稱,或者可以使用疊代函數為其提供任意變換。

Windows

機器上,您必須使用

Unix

路徑并跳過

root

選項中的卷号才能啟用。例如

C:\\Program Files\\Apache\\www

将不起作用,但是

/Program Files/Apache/www

将起作用。

可用的選項:

import * as Sentry from "@sentry/browser";
import { RewriteFrames as RewriteFramesIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new RewriteFramesIntegration(
    {
      // root path that will be stripped from the current frame's filename by the default iteratee if the filename is an absolute path
      root: string;

      // a custom prefix that will be used by the default iteratee (default: `app://`)
      prefix: string;

      // function that takes the frame, applies a transformation, and returns it
      iteratee: (frame) => frame;
    }
  )],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/rewriteframes.min.js"
  integrity="sha384-WOm9k3kzVt1COFAB/zCXOFx4lDMtJh/2vmEizIwgog7OW0P/dPwl3s8f6MdwrD7q"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new RewriteFrames(
    {
      // root path that will be stripped from the current frame's filename by the default iteratee if the filename is an absolute path
      root: string;

      // a custom prefix that will be used by the default iteratee (default: `app://`)
      prefix: string;

      // function that takes the frame, applies a transformation, and returns it
      iteratee: (frame) => frame;
    }
  )],
});
           

使用示例:

例如,如果檔案的完整路徑是

/www/src/app/file.js

用法 堆棧跟蹤中的路徑 描述
RewriteFrames() app:///file.js 預設行為是替換除檔案名之外的絕對路徑,并使用預設字首 (

app:///

) 作為字首。
RewriteFrames({prefix: 'foo/'}) foo/file.js 使用字首

foo/

代替預設字首

app:///

RewriteFrames({root: '/www'}) app:///src/app/file.js

root

定義為

/www

,是以僅從路徑的開頭修剪該部分。

ReportingObserver

Import name: Sentry.Integrations.ReportingObserver

此內建挂鈎到

ReportingObserver API

并将捕獲的事件發送到

Sentry

。它可以配置為僅處理特定的

issue

類型。

可用的選項:

import * as Sentry from "@sentry/browser";
import { ReportingObserver as ReportingObserverIntegration } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new ReportingObserverIntegration(
    {
      types: <'crash'|'deprecation'|'intervention'>[];
    }
  )],
});
           

CDN

<script
  src="https://browser.sentry-cdn.com/6.12.0/bundle.min.js"
  integrity="sha384-S3qfdh3AsT1UN84WIYNuOX9vVOoFg3nB17Jp5/pTFGDBGBt+dtz7MGAV845efkZr"
  crossorigin="anonymous"
></script>

<script
  src="https://browser.sentry-cdn.com/6.12.0/reportingobserver.min.js"
  integrity="sha384-20D83MPBNSRANJFguhj0o9Qo7p9MCemwdMMQXotwA8742WuIwga85k+T7qEgIMWK"
  crossorigin="anonymous"
></script>

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [new ReportingObserver(
    {
      types: <'crash'|'deprecation'|'intervention'>[];
    }
  )],
});
           

React Router 內建

(适用于

5.21.0

及以上版本)

5.21.0

版起,

@sentry/react

包中包含

React Router

支援。

注意:

React Router

內建旨在與我們的跟蹤 SDK

@sentry/tracing

一起使用。

有關如何設定和安裝 SDK 的更多詳細資訊,請參閱 React Performance 入門。

https://docs.sentry.io/platforms/javascript/guides/react/performance/

我們支援

React Router 3、4 和 5

的內建。

React Router v4/v5

要使用

router integration

,請使用自定義

history

導入和設定自定義路由檢測。確定将

Router

元件與

createBrowserHistory

(或等效的)結合使用。

import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';

import * as Sentry from '@sentry/react';
import { Integrations } from '@sentry/tracing';

const history = createBrowserHistory();

Sentry.init({
  integrations: [
    new Integrations.BrowserTracing({
      // Can also use reactRouterV3Instrumentation or reactRouterV4Instrumentation
      routingInstrumentation: Sentry.reactRouterV5Instrumentation(history),
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

// ...

// In your App render:
render() {
  return (
    // Use custom history with a Router component
    <Router history={history}>
      <Components />
    </Router>
  );
}
           

現在您應該使用

react router

檢測從

BrowserTracing

內建生成

pageload/navigation

事務。

參數化事務名稱

要擷取參數化的交易名稱(例如

/teams/:teamid/user/:userid

而不是

/teams/123/user/345

),您必須授予

SDK

通路路由渲染比對路徑的權限。這是因為

SDK

沒有可以在

React Router v4/v5

中使用的靜态路由配置。 有兩種方法可以實作這一點:

  1. 傳遞路由配置對象

您可以根據

react-router-config

傳遞一組路由配置對象。到檢測函數調用。您還需要提供從

react-router-dom

react-router

包導出的

matchPath

函數。

  • https://github.com/remix-run/react-router/tree/main/packages/react-router-config
import { Route, Router, Switch, matchPath } from 'react-router-dom';
import { createBrowserHistory } from 'history';

import * as Sentry from '@sentry/react';
import { Integrations } from '@sentry/tracing';

const history = createBrowserHistory();

// Array of Route Config Objects
// Make sure the order of the routes is correct. The longest url under the same parent should be placed first and in decreasing order.
const routes = [{ path: '/users/:userid' }, { path: '/users' }, { path: '/' }];

Sentry.init({
  integrations: [
    new Integrations.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV5Instrumentation(history, routes, matchPath),
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

// In your App render:
render() {
  return (
    <Router history={history}>
      <Switch>
         <Route path="/users/:userid" component={() => <div>UserId</div>} />
         <Route path="/users" component={() => <div>Users</div>} />
         <Route path="/" component={() => <div>Home</div>} />
      </Switch>
    </Router>
  );
}
           
  1. 使用 Sentry Route 元件

使用

withSentryRouting

高階元件建立一個

SentryRoute

元件,該元件将在渲染時更新比對路徑。

import {Route, Router, Switch } from 'react-router-dom';
import { createBrowserHistory } from 'history';

import * as Sentry from '@sentry/react';
import { Integrations } from '@sentry/tracing';

// Create Custom Sentry Route component
const SentryRoute = Sentry.withSentryRouting(Route);

const history = createBrowserHistory();

Sentry.init({
  integrations: [
    new Integrations.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV5Instrumentation(history),
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

render() {
  return (
    <Router history={history}>
      <Switch>
        <SentryRoute path="/users/:userid" component={() => <div>UserId</div>} />
        <SentryRoute path="/users" component={() => <div>Users</div>} />
        <SentryRoute path="/" component={() => <div>Home</div>} />
      </Switch>
    </Router>
  );
}
           
React Router v3

要使用

router integration

,請導入并設定自定義路由工具并将

history

、您的

routes

match

函數傳遞給它。

React Router v3

React Router >= 3.2.0

< 4.0.0

的支援保持不變。

Redux 內建

(5.20.0 及以上版本可用)

5.20.0

版起,

Redux

支援包含在

@sentry/react

包中。要将

Sentry

應用于

Redux

,請在初始化

Redux store

的同一位置使用

Sentry.createReduxEnhancer

import { createStore, compose } from "redux";
import * as Sentry from "@sentry/react";

// ...

const sentryReduxEnhancer = Sentry.createReduxEnhancer({
  // Optionally pass options listed below
});

const store = createStore(rootReducer, sentryReduxEnhancer);

// ...
           

如果您有其他增強器或中間件,例如

thunk

const store = createStore(
  rootReducer,
  compose(applyMiddleware(thunk), sentryReduxEnhancer)
);
           

注意:

Sentry 使用 redux enhancer。通過 enhancer,如上所示。

不要将它傳遞給 applyMiddleware 并且在将它傳遞給 createStore 方法時不要調用該方法。

Normalization 深度

預設情況下,

Sentry SDK

将任何上下文規範化為

3

的深度,在發送

Redux

狀态的情況下,您可能希望增加該深度。 您可以通過将

normalizeDepth

傳遞給

Sentry.init

調用來實作:

Sentry.init({
  dsn: "https://[email protected]/0",
  normalizeDepth: 10, // Or however deep you want your state context to be.
});
           
Redux Enhancer 選項

将選項對象作為第一個參數傳遞給

Sentry.createReduxEnhancer

以對其進行配置。

注意:

我們建議不要向 Sentry 發送敏感資訊,但如果您這樣做,我們将盡力過濾掉諸如使用者密碼之類的内容。

actionTransformer

(Function)

用于從

action

中删除敏感資訊。傳遞給函數的第一個參數是

Redux action

。傳回

null

以不向

Sentry

發送操作。預設情況下,我們發送所有

action

const sentryReduxEnhancer = Sentry.createReduxEnhancer({
  actionTransformer: action => {
    if (action.type === "GOVERNMENT_SECRETS") {
      // Return null to not log the action to Sentry
      return null;
    }
    if (action.type === "SET_PASSWORD") {
      // Return a transformed action to remove sensitive information
      return {
        ...action,
        password: null,
      };
    }

    return action;
  },
});
           

stateTransformer

(Function)

用于從

state

中删除敏感資訊。傳遞給函數的第一個參數是

Redux state

。傳回

null

以不将

state

附加到發送給

Sentry

的事件。請注意,如果您選擇不向

Sentry

發送

state

,您的錯誤可能沒有附加最新版本的

state

。 預設情況下,我們附加所有

state

更改。

const sentryReduxEnhancer = Sentry.createReduxEnhancer({
  stateTransformer: state => {
    if (state.topSecret.doNotSend) {
      // Return null to not send this version of the state.
      return null;
    }

    // Transform the state to remove sensitive information
    const transformedState = {
      ...state,
      topSecret: {
        ...state.topSecret,
        // Replace sensitive information with something else
        nuclearLaunchCodes: "I love pizza",
        // or just remove it entirely
        hiddenTreasureLocation: null,
      },
      // You should also remove large data that is irrelevant to debugging to not clutter your Sentry issues
      giganticState: null,
    };

    return transformedState;
  },
});
           

configureScopeWithState

(Function)

在每次

state

更新時調用,使用

Redux state

配置

Sentry Scope

。第一個參數是作用域,與調用

Sentry.configureScope

時得到的作用域執行個體相同,第二個參數是最新的

Redux state

const sentryReduxEnhancer = Sentry.createReduxEnhancer({
  configureScopeWithState: (scope, state) => {
    // Set tag if the user is using imperial units.
    if (state.settings.useImperialUnits) {
      scope.setTag("user.usesImperialUnits", true);
    }
  },
});
           

自定義內建

使用以下格式向

JavaScript

添加自定義內建:

// All integration that come with an SDK can be found on Sentry.Integrations object
// Custom integration must conform Integration interface: https://github.com/getsentry/sentry-javascript/blob/master/packages/types/src/integration.ts

Sentry.init({
  // ...

  integrations: [new MyAwesomeIntegration()],
});
           

rrweb:Session 重播

Sentry

提供了與

rrweb

的概念驗證內建 - 一個用于記錄和重放使用者會話的工具包。 這在診斷豐富的單頁應用程式中的複雜使用者行為時非常有用。

更多資訊:

  • https://www.rrweb.io/
  • https://docs.sentry.io/platforms/javascript/guides/react/configuration/filtering/#using-hints
  • https://docs.sentry.io/platforms/javascript/guides/react/enriching-events/attachments/
Sentry For React 完整接入詳解(2021 Sentry v21.8.x)前方高能預警!三萬字,慎入!
配置

要開始,您需要添加

@sentry/rrweb

rrweb

包:

npm install --save @sentry/rrweb rrweb
           

接下來注冊與

Sentry SDK

的內建。這将根據您使用的架構而有所不同:

// If you're using one of our integration packages, like `@sentry/react` or
// `@sentry/angular`, substitute its name for `@sentry/browser` here
import * as Sentry from "@sentry/browser";
import SentryRRWeb from "@sentry/rrweb";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [
    new SentryRRWeb({
      // ...options
    }),
  ],
  // ...
});
           

捕獲事件的重播後,您會在事件的“重播(

Replay

)”部分下的“問題詳細資訊(

Issue Details

)”中找到它。

  • 更多:https://github.com/getsentry/sentry-rrweb
采樣

為了滿足您組織的需求,您可能更喜歡對回放進行采樣。最簡單的方法是在初始化

Sentry SDK

時做出采樣決定。 例如,以下是

Sentry

本身如何使用抽樣來僅為員工捕獲這些資訊:

const hasReplays = getCurrentUser().isStaff;

let integrations = [];
if (hasReplays) {
  console.log("[sentry] Instrumenting session with rrweb");
  integrations.push(new SentryRRWeb());
}

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations,
});

Sentry.setTag("rrweb.active", hasReplays ? "yes" : "no");
           

您會注意到我們還設定了

rrweb.active

标簽,這有助于我們識别附加了重播(

replay

)的事件,否則我們将無法找到它們。 配置完成後,您就可以在搜尋查詢中簡單地使用

rrweb.active:yes

Release & 運作狀況

Release

是部署到環境中的代碼版本。當您向 Sentry 提供有關您的版本的資訊時,您可以:

  • 确定新版本中引入的問題和回歸
  • 預測哪個送出導緻了問題以及誰可能負責
  • 通過在送出消息中包含問題編号來解決問題
  • 部署代碼時接收電子郵件通知

此外,

release

用于将

source maps

應用于被壓縮的 JavaScript 以檢視原始的、未轉換的源代碼。

綁定版本

配置用戶端

SDK

時包含

release ID

(通常稱為“版本

version

”)。

release

名稱不能:

  • 包含換行符、制表符、正斜杠 (

    /

    ) 或反斜杠 (

    \

    )
  • 是(全部)句号 (

    .

    )、雙句号 (

    ..

    ) 或空格 ( )
  • 超過

    200

    個字元

該值可以是任意的,但我們推薦以下任一命名政策:

  • 語義版本控制:

    [email protected]

    [email protected]+build

    (例如,[email protected]+1234)
    • package

      project/app

      的唯一辨別符(

      iOS

      上的

      CFBundleIdentifier

      Android

      上的

      packageName

      )
    • version

      是類似于

      semver

      的結構

      <major>.<minor?>.<patch?>.<revision?>-<prerelease?>

      (

      iOS

      上的

      CFBundleShortVersionString

      Android

      上的

      versionName

      )
    • build

      是辨別

      app

      疊代的數字(

      iOS

      上的

      CFBundleVersion

      Android

      上的

      versionCode

      )
  • Commit SHA: 如果您使用

    DVCS

    ,我們建議使用

    辨別哈希 identifying hash

    (例如,

    commit SHA

    da39a3ee5e6b4b0d3255bfef95601890afd80709

    )。您可以讓

    Sentry CLI

    使用

    sentry-clireleases proposal-version

    為支援的版本控制系統自動确定此哈希值。

每個組織的釋出都是全局性的;為它們添加特定于項目的字首,以便于區分。

Sentry.init({
  release: "[email protected]",
});
           

Node/npm

環境中使用

JavaScript

執行此操作的一種常見方法是使用

process.env.npm_package_version

,如下所示:

  • 更多:https://docs.npmjs.com/misc/scripts#packagejson-vars
Sentry.init({
  release: "my-project-name@" + process.env.npm_package_version,
});
           

您如何使版本(

version

)可用于您的代碼取決于您。例如,您可以使用在建構過程中設定的環境變量。

這用

release

值标記每個事件。我們建議您在部署之前告訴

Sentry

一個新

release

,因為這将解鎖我們關于

releases

的文檔中讨論的更多功能。但是,如果您不這樣做,

Sentry

将在第一次看到具有該

release ID

的事件時自動在系統中建立一個

release

實體。

  • release:https://docs.sentry.io/product/releases/

配置您的

SDK

後,您可以安裝

repository integration

或手動為

Sentry

提供您自己的

commit metadata

。 閱讀我們關于

設定 releases

的文檔,以擷取有關

內建 integrations

關聯送出 associating commits

以及在部署

releases

時通知

Sentry

的更多資訊。

  • 設定 releases: https://docs.sentry.io/product/releases/setup/

Release 運作狀況

通過觀察使用者采用情況、應用程式使用情況、崩潰百分比和會話資料來監控

release

的運作狀況。

release

運作狀況将深入了解與使用者體驗相關的崩潰和錯誤的影響,并通過

release

詳細資訊、圖表和過濾器揭示每個新問題的趨勢。

  • health of releases : https://docs.sentry.io/product/releases/health/
  • crashes:https://docs.sentry.io/product/releases/health/#crash
  • session data:https://docs.sentry.io/product/releases/health/#session

SDK

将在

SDK

初始化時自動管理會話的開始和結束。

我們為每個頁面加載建立一個會話。對于單頁應用程式,我們将為每次導航更改(History API)建立一個新會話。

我們将會話标記為:

  • 如果

    unhandled error

    unhandled promise rejection

    冒泡到全局處理程式,則崩潰。
  • 如果

    SDK

    捕獲包含異常的事件(這包括手動捕獲的錯誤),則會出現錯誤。

要接收有關使用者采用的資料,例如使用者崩潰率百分比和采用特定版本的使用者數,請在初始化

SDK

時将使用者設定在

initialScope

上。

預設情況下,

JavaScript SDK

正在發送會話。

要禁用發送會話,請将

autoSessionTracking

标志設定為

false

Sentry.init({
  autoSessionTracking: false // default: true
});
           

環境

Sentry

在收到帶有

environment

标簽的事件時會自動建立環境。環境區分大小寫。 環境名稱不能包含換行符、空格或正斜杠,不能是字元串“

None

”或超過

64

個字元。 您無法删除環境,但可以隐藏它們。

  • hidden-environments: https://docs.sentry.io/product/sentry-basics/environments/#hidden-environments
Sentry.init({
  environment: "production",
});
           

環境可幫助您在

sentry.io

的問題詳細資訊頁面中更好地過濾問題、版本和使用者回報,您可以在我們涵蓋使用環境的文檔中了解更多資訊。

  • environments:https://docs.sentry.io/product/sentry-basics/environments/

過濾

将 Sentry 添加到您的應用程式可為您提供大量關于錯誤和性能的非常有價值的資訊,否則您将無法獲得這些資訊。 大量的資訊是好的——隻要它是正确的資訊,并且數量合理。

Sentry SDK

有幾個配置選項可以幫助您過濾事件。

我們還提供

入站過濾器 Inbound Filters

來過濾

sentry.io

中的事件。 不過,我們建議在用戶端級别進行過濾,因為它消除了發送您實際上不想要的事件的開銷。 了解有關事件中可用字段的更多資訊。

  • Inbound Filters: https://docs.sentry.io/product/data-management-settings/filtering/
  • fields available in an event:https://develop.sentry.dev/sdk/event-payloads/

過濾錯誤事件

通過使用

beforeSend

回調方法和配置、啟用或禁用內建來配置您的

SDK

以過濾錯誤事件。

使用 beforeSend

所有

Sentry SDK

都支援

beforeSend

回調方法。

beforeSend

在事件發送到伺服器之前立即調用,是以它是您可以編輯其資料的最後位置。它将事件對象作為參數接收,是以您可以使用該參數根據自定義邏輯和事件上可用的資料修改事件的資料或完全删除它(通過傳回

null

)。

Sentry.init({
  // ...

  beforeSend(event, hint) {
    const error = hint.originalException;
    if (
      error &&
      error.message &&
      error.message.match(/database unavailable/i)
    ) {
      event.fingerprint = ["database-unavailable"];
    }
    return event;
  },
});
           

還要注意,正如我們的

breadcrumbs

文檔中所讨論的,

breadcrumbs

可以被過濾。

  • breadcrumbs: https://docs.sentry.io/product/error-monitoring/breadcrumbs/

Event Hints

before-send

回調傳遞

event

和第二個參數

hint

,該參數包含一個或多個

hints

通常,

hint

儲存原始異常,以便可以提取附加資料或影響分組。 在本例中,如果捕獲到某種類型的異常,指紋将被強制為一個公共值:

Sentry.init({
  // ...

  beforeSend(event, hint) {
    const error = hint.originalException;
    if (
      error &&
      error.message &&
      error.message.match(/database unavailable/i)
    ) {
      event.fingerprint = ["database-unavailable"];
    }
    return event;
  },
});
           

有關哪些

hints

可用的資訊,請參閱:

  • hints in JavaScript: https://docs.sentry.io/platforms/javascript/guides/react/configuration/filtering/#using-hints

SDK

建立用于傳輸(

transmission

)的事件或面包屑時,該傳輸通常是從某種源對象建立的。例如,錯誤事件通常是從日志記錄或異常執行個體中建立的。為了更好地定制,SDK 将這些對象發送到某些回調(

beforeSend

beforeBreadcrumb

或 SDK 中的事件處理器系統)。

使用 Hints

Hints

可在兩個地方獲得:

  1. beforeSend / beforeBreadcrumb

  2. eventProcessors

事件和面包屑

hints

是包含用于組合事件或面包屑的各種資訊的對象。 通常

hints

儲存原始異常,以便可以提取附加資料或影響分組。

對于事件,例如

event_id

originalException

syntheticException

(在内部用于生成更清晰的堆棧跟蹤)以及您附加的任何其他任意資料。

對于面包屑,

hints

的使用取決于實作。對于

XHR

請求,

hint

包含

xhr

對象本身;對于使用者互動,提示包含

DOM

元素和事件名稱等。

在本例中,如果捕獲到某種類型的異常,指紋将被強制為一個公共值:

Sentry.init({
  // ...

  beforeSend(event, hint) {
    const error = hint.originalException;
    if (
      error &&
      error.message &&
      error.message.match(/database unavailable/i)
    ) {
      event.fingerprint = ["database-unavailable"];
    }
    return event;
  },
});
           

Hints for Events

originalException

導緻

Sentry SDK

建立事件的原始異常。這對于更改

Sentry SDK

分組事件的方式或提取附加資訊很有用。

syntheticException

當引發字元串(

string

)或非錯誤(

non-error

)對象時,Sentry 會建立一個合成異常(

synthetic exception

),以便您可以獲得基本的堆棧跟蹤。 此異常存儲在此處以供進一步提取資料。

Hints for Breadcrumbs

event

對于從浏覽器事件建立的面包屑,

Sentry SDK

通常将事件作為

hint

提供給面包屑。例如,這可用于将目标 DOM 元素中的資料提取到面包屑中。

level / input

對于從控制台日志(

console.log

)攔截建立的面包屑。 這儲存了原始

console log level

log function

的原始輸入資料。

response / input

對于從

HTTP

請求建立的面包屑。它儲存響應對象(來自

fetch API

)和

fetch

函數的輸入參數。

request / response / event

對于從

HTTP

請求建立的面包屑。這包含請求和響應對象(來自

node HTTP API

)以及

node event

(

response

error

)。

xhr

對于通過遺留

XMLHttpRequest API

完成的

HTTP

請求建立的面包屑。這儲存了原始的

xhr

對象。

整理 Sentry

您可以建構一個允許的域清單,這些域可能會引發可接受的異常。 例如,如果您的腳本是從

cdn.example.com

加載的并且您的站點是

example.com

,您可以将

allowUrls

設定為:

Sentry.init({
  allowUrls: [
    /https?:\/\/((cdn|www)\.)?example\.com/
  ]
});
           

如果您想永遠阻止特定的

URL

,您也可以使用

denyUrls

Note

5.17.0

版本之前,

allowUrls

denyUrls

分别稱為

whitelistUrls

blacklistUrls

出于向後相容性的原因,這些選項仍受支援,但它們将在

6.0

版中删除。 有關更多資訊,請參閱

Inclusive Language Policy:https://develop.sentry.dev/inclusion/

此外,我們的社群還為日常事務編制了一份常見的忽略規則清單,例如

Facebook

Chrome extensions

等。 這很有用,建議您檢查一下這些内容,看看它們是否适用于您。這不是我們 SDK 的預設值; 這隻是一個廣泛示例的一個亮點。

  • Here is the original gist:https://gist.github.com/impressiver/5092952
Sentry.init({
  ignoreErrors: [
    // Random plugins/extensions
    "top.GLOBALS",
    // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html
    "originalCreateNotification",
    "canvas.contentDocument",
    "MyApp_RemoveAllHighlights",
    "http://tt.epicplay.com",
    "Can't find variable: ZiteReader",
    "jigsaw is not defined",
    "ComboSearch is not defined",
    "http://loading.retry.widdit.com/",
    "atomicFindClose",
    // Facebook borked
    "fb_xd_fragment",
    // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to
    // reduce this. (thanks @acdha)
    // See http://stackoverflow.com/questions/4113268
    "bmi_SafeAddOnload",
    "EBCallBackMessageReceived",
    // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
    "conduitPage",
  ],
  denyUrls: [
    // Facebook flakiness
    /graph\.facebook\.com/i,
    // Facebook blocked
    /connect\.facebook\.net\/en_US\/all\.js/i,
    // Woopra flakiness
    /eatdifferent\.com\.woopra-ns\.com/i,
    /static\.woopra\.com\/js\/woopra\.js/i,
    // Chrome extensions
    /extensions\//i,
    /^chrome:\/\//i,
    // Other plugins
    /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
    /webappstoolbarba\.texthelp\.com\//i,
    /metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
  ],
});
           

使用采樣過濾 Transaction 事件

為了防止某些

transactions

被報告給

Sentry

,請使用

tracesSampler

配置選項,它允許您提供一個函數來評估目前

transaction

并在它不是您想要的時候删除它。 (它還允許您以不同的采樣率對不同的

transaction

進行抽樣。)

注意:

tracesSampler

tracesSampleRate

配置選項是互斥的。 如果您定義了一個

tracesSampler

來過濾掉某些

transaction

,您還必須通過傳回您希望對它們進行采樣的速率來處理未過濾

transaction

的情況。

最簡單的形式,僅用于過濾

transaction

,它看起來像這樣:

Sentry.init({
  // ...

  tracesSampler: samplingContext => {
    if ("...") {
      // Drop this transaction, by setting its sample rate to 0%
      return 0;
    } else {
      // Default sample rate for all others (replaces tracesSampleRate)
      return 0.1;
    }
  };
});
           

關閉與清空

大多數

SDK

的預設行為是在背景通過網絡異步發送事件。 這意味着如果應用程式意外關閉,某些事件可能會丢失。

SDK

提供了處理這種情況的機制。

close

方法可選地接受以毫秒為機關的

timeout

,并傳回一個

promise

,該

promise

在重新整理所有挂起事件或

timeout

生效時

resolve

Sentry.close(2000).then(function() {
  // perform something after close
});
           

調用

close

後,不能再使用目前用戶端。 僅在關閉應用程式之前立即調用

close

很重要。

或者,

flush

方法清空事件隊列,同時保持用戶端啟用以供繼續使用。

采樣

Sentry

添加到您的應用程式可為您提供大量關于錯誤和性能的非常有價值的資訊,否則您将無法獲得這些資訊。 大量的資訊是好的——隻要它是正确的資訊,并且數量合理。

采樣 Error 事件

要将具有代表性的錯誤樣本發送到

Sentry

,請将

SDK

配置中的

sampleRate

選項設定為

(發送的錯誤的

0%

)和

1

(發送的錯誤的

100%

)之間的數字。 這是一個靜态比率,它同樣适用于所有錯誤。例如,要對

25%

的錯誤進行抽樣:

Sentry.init({ sampleRate: 0.25 });
           

更改錯誤采樣率需要重新部署。

此外,設定

SDK

采樣率會限制對事件源的可見性。

為您的項目設定速率限制(僅在

volume

高時丢棄事件)可能更适合您的需求。

采樣 Transaction 事件

我們建議對您的

transaction

進行抽樣,原因有兩個:

  1. 捕獲單個跟蹤涉及的開銷最小,但捕獲每個頁面加載或每個 API 請求的跟蹤可能會給您的系統增加不必要的負載。
  2. 啟用采樣可以讓您更好地管理發送到 Sentry 的事件數量,是以您可以根據組織的需求定制您的數量。

選擇采樣率的目标是在性能和數量問題與資料準确性之間找到平衡。 您不想收集太多資料,但希望收集足夠的資料以得出有意義的結論。 如果您不确定要選擇什麼速率,請從一個較低的值開始,随着您對流量模式和流量的了解越來越多,逐漸增加它。

配置 Transaction 采樣率

Sentry SDK

有兩個配置選項來控制發送到

Sentry

transaction

量,讓您可以擷取具有代表性的樣本:

  1. 統一采樣率(

    tracesSampleRate

    ):
  • 提供均勻的事務橫截面,無論它們在您的應用程式中的哪個位置或在什麼情況下發生。
  • 使用預設繼承(

    inheritance

    )和優先(

    precedence

    )行為
  1. 采樣函數(

    tracesSampler

    )其中:
  • 以不同的速率采樣不同的

    transaction

  • 完全過濾掉一些

    transaction

  • 修改預設優先級和繼承行為

inheritance: https://docs.sentry.io/platforms/javascript/guides/react/configuration/sampling/#inheritance

precedence:https://docs.sentry.io/platforms/javascript/guides/react/configuration/sampling/#precedence

Filters:https://docs.sentry.io/platforms/javascript/guides/react/configuration/filtering/

設定統一采樣率

為此,請将

Sentry.init()

中的

tracesSampleRate

選項設定為

1

之間的數字。設定此選項後,建立的每個

transaction

都有該百分比的機會被發送到

Sentry

。(是以,例如,如果您将

tracesSampleRate

設定為

0.2

,大約

20%

transaction

将被記錄和發送。)看起來像這樣:

Sentry.init({
  // ...

  tracesSampleRate: 0.2,
});
           
設定采樣函數

要使用采樣函數,請将

Sentry.init()

中的

tracesSampler

選項設定為一個函數,該函數将接受

samplingContext

對象并傳回介于

1

之間的采樣率。例如:

Sentry.init({
  // ...

  tracesSampler: samplingContext => {
    // Examine provided context data (including parent decision, if any) along
    // with anything in the global namespace to compute the sample rate or
    // sampling decision for this transaction

    if ("...") {
      // These are important - take a big sample
      return 0.5;
    } else if ("...") {
      // These are less important or happen much more frequently - only take 1%
      return 0.01;
    } else if ("...") {
      // These aren't something worth tracking - drop all transactions like this
      return 0;
    } else {
      // Default sample rate
      return 0.1;
    }
  };
});
           

為友善起見,該函數還可以傳回一個布爾值。傳回

true

等同于傳回

1

,并且将保證

transaction

将發送到

Sentry

。傳回

false

相當于傳回

,并保證

transaction

不會被發送到

Sentry

采樣 Context 資料

預設采樣 Context 資料

transaction

事務時傳遞給

tracesSampler

SamplingContext

對象中包含的資訊因平台和內建(

integration

)而異。

對于基于浏覽器的

SDK

,它至少包括以下内容:

// contents of `samplingContext`
{
  transactionContext: {
    name: string; // human-readable identifier, like "GET /users"
    op: string; // short description of transaction type, like "pageload"
  }
  parentSampled: boolean; // if this transaction has a parent, its sampling decision
  location: Location | WorkerLocation; // the window.location or self.location object
  ... // custom context as passed to `startTransaction`
}
           
自定義采樣 Context 資料

使用自定義檢測建立

transaction

時,您可以通過将資料作為可選的第二個參數傳遞給

startTransaction

來将資料添加到

samplesContext

。 如果您希望采樣器可以通路某些資料,但又不想将其作為标簽(

tag

)或資料(

data

)附加到

transaction

中,例如敏感資訊或太大而無法與

transaction

一起發送的資訊,這将非常有用。例如:

Sentry.startTransaction(
  {
    // `transactionContext` - will be recorded on transaction
    name: 'Search from navbar',
    op: 'search',
    tags: {
      testGroup: 'A3',
      treatmentName: 'eager load',
    },
  },
  // `customSamplingContext` - won't be recorded
  {
    // PII
    userId: '12312012',
    // too big to send
    resultsFromLastSearch: { ... }
  },
);
           

繼承

無論

transaction

的抽樣決策如何,該決策都将傳遞到其子跨度,并從那裡傳遞到它們随後在其他服務中引起的任何

transaction

。 (有關如何完成傳播的更多資訊,請參閱連接配接服務。)

  • Connecting Services: https://docs.sentry.io/platforms/javascript/performance/

如果目前正在建立的

transaction

是那些後續事務之一(換句話說,如果它有父

transaction

),則上遊(父)采樣決策将始終包含在采樣上下文資料中,以便您的

tracesSampler

可以選擇是否和何時繼承該決策。 (在大多數情況下,繼承是正确的選擇,以避免部分跟蹤痕迹。)

在某些

SDK

中,為了友善起見,

tracesSampler

函數可以傳回一個布爾值,這樣如果這是所需的行為,則可以直接傳回父級的決策。

tracesSampler: samplingContext => {
  // always inherit
  if (samplingContext.parentSampled !== undefined) {
    return samplingContext.parentSampled
  }

  ...
  // rest of sampling logic here
}
           

如果您使用的是

tracesSampleRate

而不是

tracesSampler

,則決策将始終被繼承。

強制抽樣決策

如果您在

transaction

建立時知道是否要将

transaction

發送到

Sentry

,您還可以選擇将采樣決策直接傳遞給

transaction

構造函數(注意,不是在

customSamplingContext

對象中)。如果您這樣做,

transaction

将不受

tracesSampleRate

的限制,也不會運作

tracesSampler

,是以您可以指望通過的決策不會被覆寫。

Sentry.startTransaction({
  name: "Search from navbar",
  sampled: true,
});
           

優先級

transaction

以多種方式結束抽樣決策。

  • 根據

    tracesSampleRate

    中設定的靜态采樣率随機采樣
  • 根據

    tracesSampler

    采樣函數傳回的采樣率随機采樣
  • tracesSampler

    傳回的絕對決策(

    100%

    機會或

    0%

    機會)
  • 如果

    transaction

    有父級,繼承其父級的抽樣決策
  • 絕對決策傳遞給

    startTransaction

當有可能不止一個發揮作用時,以下優先規則适用:

  1. 如果将抽樣決策傳遞給

    startTransaction

    (請參閱上面的強制抽樣決策),則将使用該決策,而不管其他任何事情
  2. 如果定義了

    tracesSampler

    ,則将使用其決策。 它可以選擇保留或忽略任何父采樣決策,或使用采樣上下文資料來做出自己的決策或為

    transaction

    選擇采樣率。
  3. 如果未定義

    tracesSampler

    ,但存在父采樣決策,則将使用父采樣決策。
  4. 如果未定義

    tracesSampler

    并且沒有父采樣決策,則将使用

    tracesSampleRate

Sentry Testkit

在為您的應用程式建構測試時,您希望斷言正确的流跟蹤(

flow-tracking

)或錯誤正在發送到

Sentry

,但沒有真正将其發送到

Sentry

伺服器。 這樣您就不會在測試運作或其他 CI 操作期間用錯誤報告淹沒

Sentry

注意:Sentry 合作夥伴

Wix

維護 Sentry Testkit。

  • Wix:https://wix.github.io/sentry-testkit/

Sentry Testkit

是一個

Sentry

插件,它允許攔截 Sentry 的

report

并進一步檢查正在發送的資料。它使

Sentry

能夠在您的應用程式中原生工作,并且通過覆寫預設

Sentry

的傳輸機制(

transport mechanism

),報告不會真正發送,而是本地記錄到記憶體中。 這樣,您可以稍後擷取記錄的報告以供您自己使用、驗證或您在本地開發/測試環境中可能擁有的任何其他用途。

Sentry Testkit: https://wix.github.io/sentry-testkit/

安裝

npm install sentry-testkit --save-dev
           
在測試中使用
const sentryTestkit = require("sentry-testkit");

const { testkit, sentryTransport } = sentryTestkit();

// initialize your Sentry instance with sentryTransport
Sentry.init({
  dsn: "https://[email protected]/0",
  transport: sentryTransport,
  //... other configurations
});

// then run any scenario that should call Sentry.catchException(...)

expect(testkit.reports()).toHaveLength(1);
const report = testkit.reports()[0];
expect(report).toHaveProperty(/*...*/);
           

您也可以在

sentry-testkit

存儲庫的測試部分看到更多使用示例。

testing section: https://github.com/wix/sentry-testkit/tree/master/test

Testkit API

Sentry Testkit 由一個非常簡單直接的 API 組成。 請參閱 Sentry Testkit Docs 中的完整 API 描述和文檔。

Sentry Testkit Docs: https://wix.github.io/sentry-testkit/

用法

Sentry

SDK

與您的運作時環境挂鈎,并根據平台自動報告錯誤、未捕獲的異常和未處理的拒絕以及其他類型的錯誤。

關鍵術語:
  • event

    是向

    Sentry

    發送資料的一個執行個體。 通常,此資料是錯誤(

    error

    )或異常(

    exception

    )。
  • issue

    是一組相似的事件。
  • 事件的報告稱為

    捕獲(capturing)

    。當一個事件被捕獲時,它被發送到

    Sentry

最常見的捕獲形式是捕獲錯誤。可以捕獲為錯誤的内容因平台而異。 一般來說,如果你有一些看起來像異常的東西,它可以被捕獲。對于某些

SDK

,您還可以省略

captureException

的參數,

Sentry

将嘗試捕獲目前異常。它對于手動向

Sentry

報告錯誤或消息也很有用。

在捕獲事件時,您還可以記錄導緻該事件的面包屑(

breadcrumbs

)。 面包屑與事件不同:它們不會在 Sentry 中建立事件,而是會被緩沖,直到發送下一個事件。 在我們的面包屑文檔中了解有關面包屑的更多資訊。

breadcrumbs: https://docs.sentry.io/platforms/javascript/guides/react/enriching-events/breadcrumbs/

捕獲 Errors

通過包含和配置

Sentry

,我們的

React SDK

會自動附加全局處理程式(

global handlers

)來捕獲未捕獲的異常和未處理的

promise

拒絕,如官方

ECMAScript 6

标準中所述。您可以通過在

GlobalHandlers

內建中将

onunhandledrejection

選項更改為

false

并手動挂接到每個事件處理程式,然後直接調用

Sentry.captureException

Sentry.captureMessage

來禁用此預設行為。

您可以将

Error

對象傳遞給

captureException()

以将其捕獲為事件。也可以傳遞非 Error(

non-Error

) 對象和字元串(

string

),但請注意

Sentry

中的結果事件(

resulting events

)可能會丢失堆棧跟蹤。

import * as Sentry from "@sentry/react";

try {
  aFunctionThatMightFail();
} catch (err) {
  Sentry.captureException(err);
}
           

捕獲 Messages

另一種常見的操作是捕獲裸消息。消息是應該發送給

Sentry

的文本資訊。通常不會發出消息,但它們對某些團隊很有用。

Sentry.captureMessage("Something went wrong");
           

設定 Level

級别 - 類似于日志級别 - 通常基于內建預設添加。 您還可以在事件中覆寫它。

要設定超出範圍的級别,您可以為每個事件調用

captureMessage()

Sentry.captureMessage("this is a debug message", "debug");
           

要在作用域内設定級别,您可以調用

setLevel()

Sentry.configureScope(function(scope) {
  scope.setLevel(Sentry.Severity.Warning);
});
           

或每個事件:

Sentry.withScope(function(scope) {
  scope.setLevel("info");
  Sentry.captureException("info");
});
           

SDK 指紋

所有事件都有一個指紋。具有相同指紋的事件被組合成一個

issue

預設情況下,

Sentry

将運作一種内置分組算法,以根據事件中可用的資訊(如堆棧跟蹤

stacktrace

、異常

exception

和消息

message

)生成指紋。 要擴充預設分組行為或完全更改它,您可以使用以下選項的組合:

  1. 在您的

    SDK

    中,使用

    SDK

    指紋識别,如下所述
  2. 在您的項目中,使用指紋規則或堆棧跟蹤規則
    • Fingerprint Rules: https://docs.sentry.io/product/data-management-settings/event-grouping/fingerprint-rules/

    • Stack Trace Rules:https://docs.sentry.io/product/data-management-settings/event-grouping/stack-trace-rules/

在受支援的sdk中,您可以覆寫

Sentry

的預設分組,該分組将指紋屬性作為字元串數組傳遞。指紋數組的長度不受限制。這類似于指紋規則功能,它總是可用的,可以實作類似的結果。

  • fingerprint-rules:https://docs.sentry.io/product/data-management-settings/event-grouping/fingerprint-rules/

基本示例

在最基本的情況下,直接傳遞值:

function makeRequest(method, path, options) {
  return fetch(method, path, options).catch(function(err) {
    Sentry.withScope(function(scope) {
      // group errors together based on their request and response
      scope.setFingerprint([method, path, String(err.statusCode)]);
      Sentry.captureException(err);
    });
  });
}
           

您可以使用變量替換将動态值填充到通常在伺服器上計算的指紋中。 例如,可以添加值

{{ default }}

以将整個正常生成的分組哈希添加到指紋中。 這些值與伺服器端指紋識别相同。有關更多資訊,請參閱:

Variables: https://docs.sentry.io/product/data-management-settings/event-grouping/fingerprint-rules/#variables

以更大的粒度對錯誤進行分組

您的應用程式查詢遠端過程調用模型 (RPC) 接口或外部應用程式程式設計接口 (API) 服務,是以堆棧跟蹤通常是相同的(即使傳出請求非常不同)。

以下示例将進一步拆分 Sentry 将建立的預設組(由

{{ default }}

表示),并考慮到錯誤對象的一些屬性:

class MyRPCError extends Error {
  constructor(message, functionName, errorCode) {
    super(message);

    // The name of the RPC function that was called (e.g. "getAllBlogArticles")
    this.functionName = functionName;

    // For example a HTTP status code returned by the server.
    this.errorCode = errorCode;
  }
}

Sentry.init({
  ...,
  beforeSend: function(event, hint) {
    const exception = hint.originalException;

    if (exception instanceof MyRPCError) {
      event.fingerprint = [
        '{{ default }}',
        String(exception.functionName),
        String(exception.errorCode)
      ];
    }

    return event;
  }
});
           

更進一步地分組錯誤

通用錯誤(例如資料庫連接配接錯誤)具有許多不同的堆棧跟蹤,并且永遠不會組合在一起。

以下示例将通過從數組中省略

{{ default }}

來完全覆寫

Sentry

的分組:

class DatabaseConnectionError extends Error {}

Sentry.init({
  ...,
  beforeSend: function(event, hint) {
    const exception = hint.originalException;

    if (exception instanceof DatabaseConnectionError) {
      event.fingerprint = ['database-connection-error'];
    }

    return event;
  }
});
           

Source Maps

生成 Source Maps

大多數現代

JavaScript

編譯器都支援

source maps

。以下是一些常用工具的說明。

我們建議使用

Sentry

Webpack

插件來配置

source maps

并在建構過程中自動上傳它們。

sentry-webpack-plugin: https://github.com/getsentry/sentry-webpack-plugin

source-map-support

要依賴 Sentry 的 source map 解析,您的代碼不能使用

source-map-support

包。 該包以一種阻止我們的處理器正确解析它的方式覆寫捕獲的堆棧跟蹤。

source-map-support:https://www.npmjs.com/package/source-map-support

Webpack

Sentry 提供了一個友善的

Webpack

插件,可以配置

source maps

并自動将它們上傳到

Sentry

要使用該插件,您首先需要安裝它:

npm install --save-dev @sentry/webpack-plugin
// or
yarn add --dev @sentry/webpack-plugin
           

然後,配置它

webpack.config.js

const SentryWebpackPlugin = require("@sentry/webpack-plugin");

module.exports = {
  // other webpack configuration
  devtool: 'source-map',
  plugins: [
    new SentryWebpackPlugin({
      // sentry-cli configuration - can also be done directly through sentry-cli
      // see https://docs.sentry.io/product/cli/configuration/ for details
      authToken: process.env.SENTRY_AUTH_TOKEN,
      org: "example-org",
      project: "example-project",
      release: process.env.SENTRY_RELEASE,

      // other SentryWebpackPlugin configuration
      include: ".",
      ignore: ["node_modules", "webpack.config.js"],
    }),
  ],
};
           

此外,

Webpack

插件會自動設定

window.SENTRY_RELEASE

,是以您的

Sentry.init

調用不需要包含

release

值。

将 Webpack 插件設定為最後運作的插件;

否則,插件收到的 source maps 可能不是最終的。

進階用法

如果您更喜歡手動上傳

source maps

,請配置 Webpack 去輸出

source maps

module.exports = {
  devtool: 'source-map',
  output: {
    // Make maps auto-detectable by sentry-cli
    filename: "[name].js",
    sourceMapFilename: "[name].js.map",
    // Other `output` configuration
  },
  // Other webpack configuration
};
           

如果您使用

SourceMapDevToolPlugin

對 source map 生成進行更細粒度的控制,請關閉

noSources

,以便 Sentry 可以在事件堆棧跟蹤中顯示正确的源代碼上下文。

SourceMapDevToolPlugin:https://webpack.js.org/plugins/source-map-dev-tool-plugin

Rollup

您可以配置

Rollup

以生成

source maps

,然後您可以使用

sentry-cli

上傳

source maps

  • Rollup:https://rollupjs.org/
  • upload using sentry-cli:https://docs.sentry.io/product/cli/releases/#sentry-cli-sourcemaps
export default {
  entry: "./src/app.js",
  output: {
    file: "bundle.js",
    format: "cjs",
    sourceMap: true,
  },
};
           

SystemJS

SystemJS

可以配置為輸出

source maps

,然後您可以使用 sentry-cli 上傳

source maps

builder.bundle("src/app.js", "dist/app.min.js", {
  minify: true,
  sourceMaps: true,
  sourceMapContents: true,
});
           
此示例配置将您的原始、未轉換的源代碼内聯到生成的

source map

檔案中。Sentry 需要

source map

和您的原始源檔案來執行反向轉換。 如果您選擇不内聯源檔案,則除了

source map

外,您還必須使這些源檔案可供 Sentry 使用(見下文)。
  • SystemJS:https://github.com/systemjs/builder
  • upload using sentry-cli:https://docs.sentry.io/product/cli/releases/#sentry-cli-sourcemaps

TypeScript

TypeScript 編譯器可以輸出

source maps

,然後您可以使用

sentry-cli

上傳源映射。

sourceRoot

屬性配置為

/

以從生成的源代碼引用中去除建構路徑字首。這允許

Sentry

相對于您的源根檔案夾比對源檔案:

{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSources": true,
    "sourceRoot": "/"
  }
}
           

UglifyJS

我們強烈建議您使用更進階的打包器(或轉譯器),因為

UglifyJS

配置會變得非常複雜,并且很難達到預期的結果。

UglifyJS 可以配置為輸出

source maps

,然後您可以使用

sentry-cli

上傳:

uglifyjs app.js \
  -o app.min.js.map \
  --source-map url=app.min.js.map,includeSources
           

UglifyJS:https://github.com/mishoo/UglifyJS

上傳 Source Maps

Webpack

Sentry 使用

releases

來将正确的

source maps

與您的事件相比對。release API 旨在允許您在 Sentry 中存儲源檔案(和

source maps

)。

您可以在我們的 Webpack 插件的幫助下完成此操作,該插件在内部使用我們的

Sentry CLI

  1. 從您的

    [Account] > API keys

    建立一個新的身份驗證令牌
  2. 确認您在

    “Scopes”

    下選擇了

    project:write

  3. 使用

    npm

    安裝

    @sentry/webpack-plugin

  4. 使用必要的配置建立

    .sentryclirc

    檔案,如本頁所述
  5. 更新你的

    webpack.config.js

const SentryPlugin = require("@sentry/webpack-plugin");

module.exports = {
  // ... other config above ...
  plugins: [
    new SentryPlugin({
      release: process.env.RELEASE,
      include: "./dist",
    }),
  ],
};
           

使用我們的 Sentry Webpack 插件文檔了解有關插件進一步配置的更多資訊。sentry-webpack-plugin:https://github.com/getsentry/sentry-webpack-plugin

此外,您需要配置

client

以發送

release

Sentry.init({
  dsn: "https://examplePublic[email protected]/0",
  release: process.env.RELEASE,
});
           
您不必使用

RELEASE

環境變量。隻要您上傳的版本與

SDK

init

調用的版本相比對,您就可以以任何形式提供它們。

Releases API:https://docs.sentry.io/api/releases/

Sentry CLI

使用 sentry-cli 上傳 Source Maps

使用

sentry-cli

上傳

source maps

時,您需要設定建構系統以建立版本(

release

)并上傳與該版本對應的各種源檔案。要讓

Sentry

對您的堆棧跟蹤進行解碼,請同時提供:

  • 要部署的檔案(換句話說,您的

    編譯/壓縮/打包(transpilation/minification/bundling)

    過程的結果;例如,

    app.min.js

    )
  • 對應的

    source maps

如果

source map

檔案不包含您的原始源代碼 (

sourcesContent

),您還必須提供原始源檔案。 如果源檔案丢失,

Sentry CLI

将嘗試自動将源嵌入到您的

source maps

中。

Sentry

使用

releases

将正确的

source maps

與您的事件相比對。

要建立新版本,請運作以下指令(例如,在釋出期間):

releases:https://docs.sentry.io/product/releases/

sentry-cli releases new <release_name>
           

release

名稱在您的組織中必須是唯一的,并且與您的

SDK

初始化代碼中的

release

選項相比對。

然後,使用

upload-sourcemaps

指令掃描檔案夾中的

source maps

,處理它們,并将它們上傳到

Sentry

sentry-cli releases files <release_name> upload-sourcemaps /path/to/files
           
您可以通過導航到

[Project] > Project Settings > Source Maps

找到上傳到

Sentry

的工件。

此指令會将所有以

.js

.map

結尾的檔案上傳到指定的版本(

release

)。如果你想改變這些擴充 — 例如,上傳 typescript 源檔案 — 使用

--ext

選項:

sentry-cli releases files <release_name> upload-sourcemaps --ext ts --ext map /path/to/files
           

到目前為止,該版本處于草稿狀态(

“unreleased”

)。

上傳所有

source maps

後,您的應用程式已成功釋出,使用以下指令完成

release

sentry-cli releases finalize <release_name>
           

為友善起見,您可以将

--finalize

标志傳遞給新指令,這将立即完成

release

有關更多資訊,請參閱我們的

sentry-cli

文檔。

  • sentry-cli:https://docs.sentry.io/product/cli/releases/#managing-release-artifacts

Web 應用程式可在多個來源通路的情況并不少見。 請參閱我們關于多源的文檔以了解如何處理此問題。

  • multiple origins:https://docs.sentry.io/platforms/javascript/guides/react/sourcemaps/uploading/multiple-origins/

公開托管

source maps

提供給 Sentry 的最可靠方法是上傳它們,因為它減少了網絡流量并確定将使用正确版本的代碼和源映射。

預設情況下,Sentry 将在您編譯的 JavaScript 檔案中查找

source map

指令。這些指令位于最後一行,格式如下:

//# sourceMappingURL=<url>
           

當 Sentry 遇到這樣的指令時,它會解析相對于它所在的源檔案的 source map URL,并嘗試一個 HTTP 請求來擷取它。

例如,如果您有一個位于

http://example.org/js/app.min.js

的壓縮的 JavaScript 檔案,并且在該檔案的最後一行,可以找到以下指令:

//# sourceMappingURL=app.js.map
           

Sentry 将嘗試從

http://example.org/js/app.js.map

擷取

app.js.map

或者,在

source map

生成期間,您可以指定

source map

所在的完全限定

URL

//# sourceMappingURL=http://example.org/js/app.js.map
           

雖然從您的伺服器向 Sentry 提供

source maps

是最自然的內建,但并不總是可取的:

  • Sentry 可能并不總是能夠通路您的伺服器。
  • 如果您未在

    asset URL

    中指定版本,則可能存在版本不比對
  • 額外的延遲可能意味着源映射并非适用于所有錯誤。

由于這些原因,最好事先将

source maps

上傳到 Sentry(見下文)。

在防火牆後面工作

雖然推薦的解決方案是将您的源工件(打包轉譯後的代碼)上傳到

Sentry

,但有時需要允許來自

Sentry

的内部

IP

的通信。

有關 Sentry public IP 的更多資訊,請參閱:

  • IP Ranges:https://docs.sentry.io/product/security/ip-ranges/
安全通路 Source Maps

如果您想對

source maps

保密并選擇不将

source maps

直接上傳到

Sentry

,您可以在項目設定中啟用

“Security Token”

選項。

這将導緻從

Sentry

的伺服器發出的來自你的 “Allowed Domains” 的

url

的出站請求附加 HTTP header

X-Sentry-Token

頭:

GET /assets/bundle.min.js
X-Sentry-Token: {token}
           

token

是您在項目設定中定義的安全值。然後,您可以配置您的 Web 伺服器以允許在此

header/token

對存在時通路您的

source maps

。 您也可以覆寫預設

header

名稱 (

X-Sentry-Token

) 并使用

HTTP Basic Authentication

,例如通過傳遞

Authorization: Basic {encoded_password}

多個 Origin

Web 應用程式可在多個來源通路的情況并不少見。例如:

  • 網站可通過

    https

    http

    運作
  • 地理定位網址:例如

    https://us.example.com

    https://eu.example.com

  • 多個靜态

    CDN

    :如

    https://static1.example.com

    https://static2.example.com

  • 客戶特定的域/子域

在這種情況下,相同的

JavaScript

source map

檔案可能位于兩個或多個不同的來源。 在這種情況下,我們建議在路徑上使用我們特殊的波浪号 (

~

) 字首。

例如,如果您有以下内容:

  • https://static1.example.com/js/app.js
  • https://static2.example.com/js/app.js

您可以使用

~/js/app.js

URL

上傳。這将告訴

Sentry

忽略域并将

artifact

用于任何來源。

此外,您還可以以多個名稱上傳同一個檔案。 在引擎蓋(

hood

)下 Sentry 将對這些進行重複資料删除。

~

字首告訴

Sentry

對于給定的

URL

,路徑為

/js/app.js

的協定和主機名的任何組合都應該使用這個工件。

驗證檔案

確定

source maps

本身有效并正确上傳可能非常具有挑戰性。 為了解決這個問題,我們維護了一個線上驗證工具,可用于針對您的托管源測試您的

source map

sourcemaps.io

  • https://sourcemaps.io/

此外,您可以在使用

sentry-cli

上傳

source maps

時使用

--validate

标志,這将嘗試在本地解析源映射并查找引用。 請注意,在已知情況下,驗證标志将在設定正确時訓示失敗(如果您引用了外部

source maps

,則驗證工具将訓示失敗)。

除了驗證步驟之外,您還可以檢查這些:

  • 確定您的檔案的 URL 字首正确。 這很容易出錯。
  • 上傳壓縮檔案的比對

    source maps

  • 確定您在伺服器上的壓縮檔案實際上引用了您的檔案。

最佳實踐

一個簡單的設定

在這個簡單的項目中,

minified/transpiled

的檔案及其

source maps

位于同一目錄中:

├── build/
│   ├── worker.js
│   ├── worker.js.map
│   ├── app.js
│   ├── app.js.map
│   ├── index.html
├── package.json
├── public/
│   └── index.html
├── sentry.properties
├── src/
│   ├── app.js
│   └── worker.js
├── webpack.config.js
           

對于這個項目,我們可以使用一個簡單的

Sentry

配置:

const SentryWebpackPlugin = require("@sentry/webpack-plugin");
// ...
plugins: [
  new SentryWebpackPlugin({
    authToken: process.env.SENTRY_AUTH_TOKEN,
    org: "example-org",
    project: "example-project",
      include: "build",
    configFile: "sentry.properties",
    release: process.env.SENTRY_RELEASE,
  }),
],
// ...
           

我們建議使用

Webpack

插件将

source maps

內建到

Sentry

。 如果您的項目中沒有使用

Webpack

,則可以使用

Sentry CLI

一緻的版本

要讓

Sentry

将錯誤堆棧跟蹤與您的

source maps

相關聯,請将您的版本号定義為

Webpack

插件選項或

Sentry CLI

參數(無論您使用哪個)。如果您使用

Sentry CLI

,您還應該在

Sentry.init()

調用中定義相同的版本号。 確定版本号一緻性的最簡單方法是将其設定為項目中的環境變量:

# ...
SENTRY_RELEASE="1.2.3"
# ...
           

然後,如果您使用的是

sentry-webpack-plugin

// ...
new SentryWebpackPlugin({
  // ... other options
  release: process.env.SENTRY_RELEASE,
});
// ...
           

或者,如果您使用的是

Sentry CLI

sh sentry-cli releases new "$SENTRY_RELEASE" sentry-cli releases files "$SENTRY_RELEASE" upload-sourcemaps /path/to/sourcemaps

// ...
Sentry.init({
  // ... other options
  release: process.env.SENTRY_RELEASE,
});
// ...
           

正确的 Source Paths

您的

release artifacts

(

bundle

檔案和源

source maps

)的檔案名應與堆棧跟蹤中報告的路徑比對。 您可以使用上傳配置來調整檔案的名稱。

Webpack

插件和

Sentry CLI

都有相同的選項;下面介紹了與

source maps

相關的内容。還可以使用我們的

RewriteFrames

內建來調整堆棧跟蹤内的路徑。

根據您的設定,您可能需要在開發和生産環境中為

source maps

進行不同的配置,因為堆棧跟蹤中的路徑可能不同。
Webpack 和 Sentry CLI 的選項

這些選項和示例将有助于內建您的

source maps

include

此選項接受一個或多個路徑來遞歸掃描源和

*.map

檔案。例如:

  1. 包括您的轉譯器/捆綁器輸出檔案的位置:
  • include: './app/.next'

  • include: './build'

  1. 包括來自多個檔案夾:
  • 包括:['./src', './lib']

  1. 遞歸搜尋整個項目:
  • include: '.'

rewrite

允許重寫比對的

source maps

,以便在可能的情況下将索引映射扁平化并内聯缺失的源。預設為

true

應該啟用此選項以使

stripPrefix

stripCommonPrefix

工作。

urlPrefix

此選項在所有檔案名的開頭添加一個公共字首。預設為

~/

,這是一個比對任何

scheme

hostname

的通配符(

http://my.web.site/path/to/script.js

http://my.web.site/

部分)。

當應用程式的入口點(通常是浏覽器端的

index.html

Node

index.js

)位于源/源映射檔案之上一個或多個級别時,此選項很有用,如下例所示:

├── build/
│   ├── index.html
│   ├── static/
│   │   ├── app.js
│   │   ├── app.js.map
           

在這種情況下,請按照以下示例進行配置:

// ...
new SentryWebpackPlugin({
  // ...
  include: "build/static/",
  urlPrefix: "~/static/"
  // ...
}),
// ...
           

stripPrefix

此選項從

sourcemap

中(例如,在

sources entry

中)引用的檔案名中删除給定的字首。 當您需要修剪捆綁器/開發(

bundler/development

)伺服器可能添加到檔案名的額外字首時,這很有用,例如

webpack://_N_E/

請注意,使用

stripPrefix

選項不會更改上傳檔案的名稱。 當您将目标檔案的父檔案夾作為不需要的字首時,請在包含

Webpack

插件選項或傳遞給

sentry-cli

path/to/sourcemaps

中包含要删除的部分。例如,如果您的檔案存儲在

./build/static/js/

并且您在

Webpack

插件配置中有

include: "build"

,您的檔案将使用類似

~/static/js/bundle.js

的名稱上傳。如果您更新您的配置

include: "build/static/js"

,您的檔案将上傳為

~/bundle.js

(等等)。

調整幀(Frames)

或者,您可以使用

Sentry

RewriteFrames

內建來微調堆棧跟蹤内的路徑。

import { RewriteFrames } from "@sentry/integrations";

Sentry.init({
  dsn: "https://[email protected]/0",
  integrations: [
    new RewriteFrames({
      // ... options
    }),
  ],
});
           

對 Source Maps 進行故障排除

Source maps

有時很難開始。如果您遇到問題:

驗證在您的 SDK 中配置了一個 release

要定位和應用上傳的

source maps

,需要通過 CLI 或 API(以及随其上傳的正确工件)建立

release

,并且需要在您的 SDK 配置中指定新建立的

release

的名稱。

要驗證這一點,請從

Sentry UI

打開

issue

并檢查

release

是否已配置。如果螢幕右側的

“Release”

旁邊顯示

“not configured”

“N/A”

(或者如果您在标簽清單中沒有看到

release tag

),則需要傳回并标記你的錯誤。如果設定正确,您将看到

"Release: my_example_release"

驗證工件(artifacts)已上傳

正确配置您的

release

并标記問題後,您可以通過導航到

[Project] » Project Settings » Source Maps

找到上傳到

Sentry

的工件。

此外,請確定所有必要的檔案都可用。要讓 Sentry

de-minify

堆棧跟蹤,您必須同時提供

minify

的檔案(例如

app.min.js

)和相應的

source map

。如果

source map

檔案不包含您的原始源代碼 (

sourcesContent

),您必須另外提供原始源代碼檔案。或者,

sentry-cli

會自動将源代碼(如果缺少)嵌入到您的

source maps

中。

驗證

sourceMappingURL

是否存在

一些

CDN

會自動從靜态檔案(包括

JavaScript

檔案)中去除注釋。 這可能會導緻删除

JavaScript

檔案的

sourceMappingURL

指令,因為它被視為注釋。例如,

CloudFlare

有一個名為

Auto-Minify

的功能,如果啟用它,它将去除

sourceMappingURL

  • Auto-Minify:https://blog.cloudflare.com/an-all-new-and-improved-autominify/

仔細檢查您部署的最終

JavaScript

檔案是否存在

sourceMappingURL

或者,您可以在

minify

的檔案上設定

SourceMap HTTP header

,而不是

sourceMappingURL

。如果此

header

存在,

Sentry

将使用它來發現

source map

的位置。

驗證 artifact 釋出值是否與您的 SDK 中配置的值比對

每當您使用分發辨別符(

SDK

中的

dist

配置選項)時,在

source map

上傳期間必須使用相同的值。相反,如果您的

source map

使用

dist

值上傳,則必須在您的

SDK

中設定相同的值。要将

dist

值添加到您上傳的

source maps

,請使用

--dist

标志和

sentry-cli

dist

選項和

@sentry/webpack-plugin

。要在

SDK

中設定

dist

值,請使用

Sentry.init()

中的

dist

選項。

要驗證 SDK 中的分發設定是否正确,請在

Sentry UI

中打開一個

issue

并檢查

dist

标簽是否存在。對于工件,轉到項目設定中的

Source Maps

頁面,選擇您剛剛檢查的事件中顯示的

release

,并驗證

dist

值(在

upload time

旁邊的小橢圓中)與事件上的值比對。

驗證 artifact 名稱與

sourceMappingURL

值比對

bundled

minified

的 JavaScript 檔案最後一行的

sourceMappingURL

注釋告訴 Sentry(或浏覽器)在哪裡找到相應的

source map

。這可以是完全限定的

URL

、相對路徑或檔案名本身。 将

artifact

上傳到

Sentry

時,您必須使用檔案解析為的值命名源映射檔案。

也就是說,如果您的檔案類似于:

// -- end script.min.js
//# sourceMappingURL=script.min.js.map
           

并托管在

http://example.com/js/script.min.js

,然後

Sentry

将在

http://example.com/js/script.min.js.map

查找該

source map

檔案。 是以,您上傳的

artifact

必須命名為

http://example.com/js/script.min.js.map

(或

~/js/script.min.js.map

)。

或者,如果您的檔案類似于:

//-- end script.min.js
//# sourceMappingURL=https://example.com/dist/js/script.min.js.map
           

那麼您上傳的

artifact

也應該命名為:

https://example.com/dist/js/script.min.js.map

(或

~/dist/js/script.min.js.map

)。

最後,如果您的檔案類似于:

//-- end script.min.js
//# sourceMappingURL=../maps/script.min.js.map
           

那麼您上傳的

artifact

應命名為

https://example.com/dist/maps/script.min.js.map

(或

~/dist/maps/script.min.js.map

)。

驗證 artifact 名稱與堆棧跟蹤幀比對

如果您已上傳

source maps

,但它們并未應用于

Sentry

問題中的代碼,請檢視事件的

JSON

并查找

abs_path

以準确檢視我們嘗試解析檔案的位置 - 對于 例如,

http://localhost:8000/scripts/script.js

(對于堆棧跟蹤中的每一幀,

abs_path

将出現一次 - 将其與未

deminified

的檔案比對。)。 可以在事件發生日期旁邊的

issue

頁面頂部找到指向

JSON

視圖的連結。上傳的

artifact

名稱必須與這些值比對。

如果您的路徑中有動态值(例如,

https://www.site.com/{some_value}/scripts/script.js

),您可能需要使用

rewriteFrames

內建來更改您的

abs_path

值。

使用 sentry-cli

如果您的

sourceMappingURL

注釋類似于:

// -- end script.min.js (located at http://localhost:8000/scripts/script.min.js)
//# sourceMappingURL=script.min.js.map
           

正确上傳這些檔案的示例

sentry-cli

指令如下所示(假設您在

/scripts

目錄中,從上一級目錄運作 Web 伺服器,這就是我們使用

--url-prefix

選項的原因) :

sentry-cli releases files VERSION upload-sourcemaps . --url-prefix '~/scripts'
           

此指令上傳目前目錄中的所有

JavaScript

檔案。

Sentry

中的

Artifacts

頁面現在應如下所示:

~/scripts/script.js
~/scripts/script.min.js
~/scripts/script.min.js.map
           

或者,您可以指定要上傳的檔案。 例如:

sentry-cli releases files VERSION upload-sourcemaps script.min.js script.min.js.map --url-prefix '~/scripts'
           

您還可以使用完全限定的 URL 上傳它。例如:

sentry-cli releases files VERSION upload-sourcemaps . --url-prefix 'http://localhost:8000/scripts'
           
使用 API

您也可以使用

API

上傳

artifact

curl -X POST \
  https://sentry.io/api/0/organizations/ORG_SLUG/releases/VERSION/files/ \
  -H 'Authorization: Bearer AUTH_TOKEN' \
  -H 'content-type: multipart/form-data' \
  -F fi[email protected] \
  -F 'name=~/scripts/script.min.js.map'
           
使用 ~

~

Sentry

中用于替換

scheme

domain

http://example.com/dist/js/script.js

将比對

~/dist/js/script.js

http://example.com/dist/js/script.js

但不會比對

~/script.js

在發生錯誤之前驗證 artifact 已上傳

Sentry

期望給定版本中的源代碼和

source maps

在該

release

中發生錯誤之前上傳到

Sentry

如果您在

Sentry

捕獲錯誤後上傳

artifact

Sentry

将不會傳回并追溯将任何源注釋(

source annotations

)應用于這些錯誤。 隻有在

artifact

上傳後觸發的新錯誤才會受到影響。

驗證您的 source maps 是否正确建構

我們維護一個線上驗證工具,可用于針對您的托管源測試您的

source maps

sourcemaps.io

  • https://sourcemaps.io/

或者,如果您使用

Sentry CLI

source maps

上傳到

Sentry

,您可以使用

--validate

指令行選項來驗證您的

source maps

是否正确。

驗證您的 source maps 在本地工作

如果您發現

Sentry

沒有正确映射檔案名、行或列映射,您應該驗證您的

source maps

是否在本地運作。為此,您可以将

Node.js

Mozilla

source-map library

結合使用。

  • https://github.com/mozilla/source-map

首先,将

source-map

作為

npm

子產品全局安裝:

npm install -g source-map
           

然後,編寫一個腳本來讀取您的

source map

檔案并測試映射。 下面是一個例子:

var fs = require("fs"),
  path = require("path"),
  sourceMap = require("source-map");

// file output by Webpack, Uglify, and so forth
var GENERATED_FILE = path.join(".", "app.min.js.map");

// line and column located in your generated file (for example, the source of your error
// from your minified file)
var GENERATED_LINE_AND_COLUMN = { line: 1, column: 1000 };

var rawSourceMap = fs.readFileSync(GENERATED_FILE).toString();
new sourceMap.SourceMapConsumer(rawSourceMap).then(function(smc) {
  var pos = smc.originalPositionFor(GENERATED_LINE_AND_COLUMN);

  // should see something like:
  // { source: 'original.js', line: 57, column: 9, name: 'myfunc' }
  console.log(pos);
});
           

如果您在本地獲得與通過

Sentry

獲得的結果相同(不正确)的結果,請仔細檢查您的

source map

生成配置。

驗證您的源檔案不是太大

對于單個

artifact

Sentry

接受的最大檔案大小為

40 MB

使用者通常會達到此限制,因為他們在臨時建構階段傳輸源檔案。例如,在

Webpack/Browserify

合并所有源檔案之後,但在

minification

之前。 如果可能,請發送原始源檔案。

驗證 artifact 沒有被 gzip

Sentry API

目前僅适用于以純文字(

UTF-8

編碼)形式上傳的

source maps

和源檔案。如果檔案以壓縮格式(例如

gzip

)上傳,它們将不會被正确解釋。

這有時發生在生成

pre-compressed minified

檔案的建構腳本和插件中。 例如,

Webpack

compression

插件。您需要禁用此類插件并在生成的

source maps/source files

上傳到 Sentry 後執行壓縮。

  • https://github.com/webpack/compression-webpack-plugin

驗證 worker 與 Web 共享相同的卷(如果通過 Docker 運作自托管 Sentry)

Sentry 在其

worker

中進行

source map

計算。 這意味着

worker

需要通路通過前端上傳的檔案。仔細檢查

cron worker

web worker

是否可以從同一個磁盤讀取/寫入檔案。

故障排除

如果您需要幫助解決

Sentry JavaScript SDK integration

問題,您可以閱讀此處記錄的邊緣案例。

調試附加資料

您可以檢視事件的

JSON payload

以了解

Sentry

如何在事件中存儲其他資料。資料的形狀可能與描述不完全比對。

Sentry For React 完整接入詳解(2021 Sentry v21.8.x)前方高能預警!三萬字,慎入!

有關更多詳細資訊,請參閱有關事件有效負載的完整文檔。

  • https://develop.sentry.dev/sdk/event-payloads/

最大 JSON Payload 大小

maxValueLength

的預設值為

250

,但如果您的消息較長,您可以根據需要調整此值。 請注意,并非每個值都受此選項影響。

CORS 屬性和 Header

要了解從不同來源的腳本引發的 JavaScript 異常,請執行以下兩項操作:

  1. 添加

    crossorigin="anonymous"

    腳本屬性
<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>
           

腳本屬性告訴浏覽器

“anonymously”

擷取目标檔案。 請求此檔案時,浏覽器不會将潛在的使用者識别資訊(如

cookie

HTTP

憑據)傳輸到伺服器。

  1. 添加

    Cross-Origin HTTP header

Access-Control-Allow-Origin: *
           

跨域資源共享 (

CORS

) 是一組

API

(主要是

HTTP header

),用于規定檔案應該如何跨域下載下傳和提供服務。

通過設定

Access-Control-Allow-Origin: *

,伺服器向浏覽器表明任何來源都可以擷取此檔案。 或者,您可以将其限制為您控制的已知來源:

Access-Control-Allow-Origin: https://www.example.com
           

大多數社群

CDN

正确設定了

Access-Control-Allow-Origin

header。

$ curl --head https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.js | \
 grep -i "access-control-allow-origin"

 Access-Control-Allow-Origin: *
           

意外的 OPTIONS 請求

如果您的應用程式由于執行額外的

OPTIONS

請求而開始行為異常,則很可能是不需要的

sentry-trace

請求

header

的問題,當您在浏覽器

SDK

中為我們的

Tracing Integration

使用過于通用的配置時可能會發生這種情況。

要解決此問題,請在

SDK

初始化期間更改

trackingOrigins

選項。 有關更多詳細資訊,請參閱我們的性能監控文檔中的自動檢測。

  • https://docs.sentry.io/platforms/javascript/performance/instrumentation/automatic-instrumentation/#tracingorigins

instrument.js

Console Log 語句的行号

如果調試時在您的控制台中顯示了

instrument.js

,請将

Sentry

添加到您的架構黑盒設定中,例如:

/@sentry/

,以便

Chrome

在調試時忽略

SDK

堆棧幀。

  • blackboxing:https://docs.sentry.io/platforms/javascript/guides/react/troubleshooting/

處理廣告攔截器(Ad-Blockers)

當您使用我們的

CDN

時,廣告攔截或腳本攔截擴充可能會阻止我們的

SDK

被正确擷取和初始化。是以,對

SDK API

的任何調用都将失敗,并可能導緻您的應用程式出現意外行為。

此外,即使正确下載下傳并初始化

SDK

,也可能會阻止需要接收捕獲資料的

Sentry

端點。這将阻止任何錯誤報告、會話運作狀況或性能資料的傳遞,進而使其在

sentry.io

中實際上不可用。

您可以通過上述多種方式解決第一個

issue

。但是,端點阻塞隻能使用隧道解決。

使用 tunnel 選項

隧道是一個

HTTP

端點,充當

Sentry

和您的應用程式之間的代理。 由于您控制此伺服器,是以不會有任何發送到它的請求被阻止的風險。 當端點位于同一個源下時(盡管它不必為了隧道工作),浏覽器不會将任何對端點的請求視為第三方請求。是以,這些請求将應用不同的安全措施,預設情況下不會觸發廣告攔截器。可以在下面找到流程的快速摘要。

Sentry For React 完整接入詳解(2021 Sentry v21.8.x)前方高能預警!三萬字,慎入!

JavaScript SDK 6.7.0

版開始,您可以使用

tunnel

選項告訴 SDK 将事件傳送到配置的 URL,而不是使用

DSN

。 這允許

SDK

從查詢參數中删除

sentry_key

,這是廣告攔截器首先阻止發送事件的主要原因之一。此選項還會阻止

SDK

發送預檢請求,這是需要在查詢參數中發送

sentry_key

的要求之一。

要啟用

tunnel

選項,請在

Sentry.init

調用中提供相對或絕對

URL

。當您使用相對

URL

時,它是相對于目前來源的,這是我們推薦的形式。使用相對 URL 不會觸發預檢

CORS

請求,是以不會阻止任何事件,因為廣告攔截器不會将這些事件視為第三方請求。

Sentry.init({
  dsn: "https://ex[email protected]/0",
  tunnel: "/tunnel",
});
           

配置完成後,所有事件都将發送到

/tunnel

端點。 但是,此解決方案需要在伺服器上進行額外配置,因為現在需要解析事件并将其重定向到

Sentry

。 這是您的伺服器元件的示例:

<?php
// Change $host appropriately if you run your own Sentry instance.
$host = "sentry.io";
// Set $known_project_ids to an array with your Sentry project IDs which you
// want to accept through this proxy.
$known_project_ids = array(  );

$envelope = stream_get_contents(STDIN);
$pieces = explode("\n", $envelope, 2);
$header = json_decode($pieces[0], true);
if (isset($header["dsn"])) {
    $dsn = parse_url($header["dsn"]);
    $project_id = intval(trim($dsn["path"], "/"));
    if (in_array($project_id, $known_project_ids)) {
      $options = array(
        'http' => array(
            'header'  => "Content-type: application/x-sentry-envelope\r\n",
            'method'  => 'POST',
            'content' => $envelope
        )
      );
      echo file_get_contents(
          "https://$host/api/$project_id/envelope/",
          false,
          stream_context_create($options));
    }
}
           
// Requires .NET Core 3.1 and C# 9 or higher
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;

// Change host appropriately if you run your own Sentry instance.
const string host = "sentry.io";
// Set knownProjectIds to a list with your Sentry project IDs which you
// want to accept through this proxy.
var knownProjectIds = new HashSet<string>() {  };

var client = new HttpClient();
WebHost.CreateDefaultBuilder(args).Configure(a =>
    a.Run(async context =>
    {
        context.Request.EnableBuffering();
        using var reader = new StreamReader(context.Request.Body);
        var header = await reader.ReadLineAsync();
        var headerJson = JsonSerializer.Deserialize<Dictionary<string, object>>(header);
        if (headerJson.TryGetValue("dsn", out var dsnString)
            && Uri.TryCreate(dsnString.ToString(), UriKind.Absolute, out var dsn))
        {
            var projectId = dsn.AbsolutePath.Trim('/');
            if (knownProjectIds.Contains(projectId) && string.Equals(dsn.Host, host, StringComparison.OrdinalIgnoreCase)) {
              context.Request.Body.Position = 0;
              await client.PostAsync($"https://{dsn.Host}/api/{projectId}/envelope/",
                  new StreamContent(context.Request.Body));
            }
        }
    })).Build().Run();
           

檢視我們的示例存儲庫以了解更多資訊。

  • https://github.com/getsentry/examples/tree/master/tunneling

如果您的用例與 SDK 包本身被阻止有關,以下任何一種解決方案都可以幫助您解決此問題。

直接使用 Package

處理腳本阻塞擴充的最佳方法是直接通過

npm

使用

SDK

包并将其與您的應用程式捆綁在一起。 這樣,您就可以確定代碼始終如您所願。

第二種方法是從我們的

CDN

下載下傳

SDK

并自己托管。這樣,

SDK

仍将與您的其餘代碼分開,但您可以确定它不會被阻止,因為它的來源将與您網站的來源相同。

您可以使用

curl

或任何其他類似工具輕松擷取它:

curl https://browser.sentry-cdn.com/5.20.1/bundle.min.js -o sentry.browser.5.20.1.min.js -s
           

使用 JavaScript Proxy API

最後一個選項是使用

Proxy

保護,這将確定您的代碼不會中斷,即使您調用我們的 SDK,它被阻止。 除了 Internet Explorer 之外的所有浏覽器都支援

Proxy

。此外,如果

Proxy

不在您使用者的任何浏覽器中,它将被悄悄跳過,是以您不必擔心它會破壞任何内容。

将此代碼段直接放在包含我們的

CDN

包的

<script>

标簽上方。可讀格式的代碼片段如下所示:

if ("Proxy" in window) {
  var handler = {
    get: function(_, key) {
      return new Proxy(function(cb) {
        if (key === "flush" || key === "close") return Promise.resolve();
        if (typeof cb === "function") return cb(window.Sentry);
        return window.Sentry;
      }, handler);
    },
  };
  window.Sentry = new Proxy({}, handler);
}
           

如果您想直接複制和粘貼代碼段,這裡将其

minified

<script>
  if ("Proxy" in window) {
    var n = {
      get: function(o, e) {
        return new Proxy(function(n) {
          return "flush" === e || "close" === e
            ? Promise.resolve()
            : "function" == typeof n
            ? n(window.Sentry)
            : window.Sentry;
        }, n);
      },
    };
    window.Sentry = new Proxy({}, n);
  }
</script>
           

直接使用 Client

為了能夠管理多個

Sentry

執行個體而它們之間沒有任何沖突,您需要建立自己的

Client

。 如果您的應用程式內建在其中,這也有助于防止跟蹤任何父應用程式錯誤。在這個例子中,我們使用

@sentry/browser

但它也适用于

@sentry/node

import { BrowserClient } from "@sentry/browser";

const client = new BrowserClient({
  dsn: "https://[email protected]/0",
});

client.captureException(new Error("example"));
           

雖然上面的示例應該可以正常工作,但

Client

上缺少一些方法,如

configureScope

withScope

,因為

Hub

負責狀态管理。這就是為什麼建立新

Hub

并将

Client

綁定到它可能更容易的原因。結果是一樣的,但你也會得到狀态管理。

import { BrowserClient, Hub } from "@sentry/browser";

const client = new BrowserClient({
  dsn: "https://[email protected]/0",
});

const hub = new Hub(client);

hub.configureScope(function(scope) {
  scope.setTag("a", "b");
});

hub.addBreadcrumb({ message: "crumb 1" });
hub.captureMessage("test");

try {
  a = b;
} catch (e) {
  hub.captureException(e);
}

hub.withScope(function(scope) {
  hub.addBreadcrumb({ message: "crumb 2" });
  hub.captureMessage("test2");
});
           

處理內建

內建是在

Client

上設定的,如果您需要處理多個

Client

Hub

,您還必須確定正确進行內建處理。這是一個如何使用多個

Client

和多個運作全局內建的

Hub

的工作示例。

import * as Sentry from "@sentry/browser";

// Very happy integration that'll prepend and append very happy stick figure to the message
class HappyIntegration {
  constructor() {
    this.name = "HappyIntegration";
  }

  setupOnce() {
    Sentry.addGlobalEventProcessor(event => {
      const self = Sentry.getCurrentHub().getIntegration(HappyIntegration);
      // Run the integration ONLY when it was installed on the current Hub
      if (self) {
        event.message = `\\o/ ${event.message} \\o/`;
      }
      return event;
    });
  }
}

HappyIntegration.id = "HappyIntegration";

const client1 = new Sentry.BrowserClient({
  dsn: "https://[email protected]/0",
  integrations: [...Sentry.defaultIntegrations, new HappyIntegration()],
  beforeSend(event) {
    console.log("client 1", event);
    return null; // Returning null does not send the event
  },
});
const hub1 = new Sentry.Hub(client1);

const client2 = new Sentry.BrowserClient({
  dsn: "https://[email protected]/0", // Can be a different DSN
  integrations: [...Sentry.defaultIntegrations, new HappyIntegration()],
  beforeSend(event) {
    console.log("client 2", event);
    return null; // Returning null does not send the event
  },
});
const hub2 = new Sentry.Hub(client2);

hub1.run(currentHub => {
  // The hub.run method makes sure that Sentry.getCurrentHub() returns this hub during the callback
  currentHub.captureMessage("a");
  currentHub.configureScope(function(scope) {
    scope.setTag("a", "b");
  });
});

hub2.run(currentHub => {
  // The hub.run method makes sure that Sentry.getCurrentHub() returns this hub during the callback
  currentHub.captureMessage("x");
  currentHub.configureScope(function(scope) {
    scope.setTag("c", "d");
  });
});
           

第三方 Promise 庫

當您包含和配置

Sentry

時,我們的

JavaScript SDK

會自動附加

global handlers

capture

未捕獲的

exceptions

和未處理的

promise rejections

。 您可以通過在

GlobalHandlers

內建中将

onunhandledrejection

選項更改為

false

并手動挂接到每個事件處理程式,然後直接調用

Sentry.captureException

Sentry.captureMessage

來禁用此預設行為。

如果您使用第三方庫來實作

Promise

,您可能還需要管理您的配置。 此外,請記住,浏覽器通常會實施安全措施,在提供來自不同來源的腳本檔案時阻止錯誤報告。

具有“非錯誤異常

Non-Error Exception

”的事件

如果您看到錯誤消息

“Non-Error exception (or promise rejection) captured with keys: x, y, z.”

,這會發生在您

a

) 使用

plain object

調用

Sentry.captureException()

時,b) 抛出一個

plain object

,或者

c

) 拒絕一個帶有

plain object

promise

您可以在

“Additional Data”

部分的

__serialized__

條目中檢視有問題的非錯誤對象的内容。

為了更好地了解這些錯誤事件,我們建議根據

__serialized__

資料的内容找到

plain object

被傳遞或抛出到

Sentry

的位置,然後将

plain object

轉換為

Error

對象。

支援的浏覽器

Sentry

JavaScript SDK

支援以下浏覽器:

Android Firefox Chrome IE iPhone Edge Safari
4.4 latest latest IE 10 iOS12 latest latest
5.0 IE 11 iOS13
6.0
7.1
8.1
9.0
10.0

支援 <= IE 11

5.7.0

版本之前,我們的

JavaScript SDK

需要一些

polyfills

用于舊版浏覽器,如

IE 11

及更低版本。如果您正在使用它,請在加載我們的

SDK

之前更新到最新版本或添加下面的腳本标簽。

<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise%2CObject.assign%2CString.prototype.includes%2CNumber.isNaN"></script>
           

我們需要以下

polyfill

  • Promise

  • Object.assign

  • Number.isNaN

  • String.prototype.includes

此外,請記住在

HTML

頁面頂部定義有效的

HTML doctype

,以確定

IE

不會進入

相容模式(compatibility mode)

公衆号:黑客下午茶
           

繼續閱讀