內容源於:https://docs.sentry.io/platforms/javascript/guides/react/
系列
腦圖
公眾號:黑客下午茶
快速開始
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://examplePublicKey@o0.ingest.sentry.io/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
的選項。在下方檢視所有可能的自定義選項。
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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/0",
debug: true,
initialScope: {
tags: {"my-tag": "my value"},
user: {id: 42, email: "john.doe@example.com"},
}
});
回撥函式:
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/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
0
到 1
之間的數字,控制給定事務傳送到 Sentry
的概率百分比。(0
表示 0%
,1
表示 100%
)同樣適用於應用程式中建立的所有事務。必須定義這個或 tracesSampler
以啟用跟蹤。
tracesSampler
一個函式負責確定一個給定的事務將被髮送到 Sentry
的概率百分比。它將自動被傳遞有關事務和建立它的上下文的資訊,並且必須返回一個介於 0
(被髮送的概率為 0%
)和 1
(被髮送的概率為 100%
) 之間的數字。還可以用於過濾事務,對不需要的事務返回 0
。必須定義這個或 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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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
此外掛不會嘗試為其他場景提供本地儲存或重試。 例如,如果瀏覽器有本地連線但沒有網際網路連線,那麼它可能會報告它線上,並且在這種情況下,Sentry
的 Offline
外掛不會嘗試儲存或重試任何傳送失敗。
import * as Sentry from "@sentry/browser";
import { Offline as OfflineIntegration } from "@sentry/integrations";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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
中使用的靜態路由配置。 有兩種方法可以實現這一點:
- 傳遞路由配置物件
您可以根據 react-router-config
傳遞一組路由配置物件。到檢測函式呼叫。您還需要提供從 react-router-dom
或 react-router
包匯出的 matchPath
函式。
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>
);
}
- 使用 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://examplePublicKey@o0.ingest.sentry.io/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/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://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
new SentryRRWeb({
// ...options
}),
],
// ...
});
捕獲事件的重播後,您會在事件的“重播(Replay
)”部分下的“問題詳細資訊(Issue Details
)”中找到它。
取樣
為了滿足您組織的需求,您可能更喜歡對回放進行取樣。最簡單的方法是在初始化 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://examplePublicKey@o0.ingest.sentry.io/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
個字元
該值可以是任意的,但我們推薦以下任一命名策略:
- 語義版本控制:
package@version
或package@version+build
(例如,my.project.name@2.3.12+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: "my-project-name@2.3.12",
});
在 Node/npm
環境中使用 JavaScript
執行此操作的一種常見方法是使用 process.env.npm_package_version
,如下所示:
Sentry.init({
release: "my-project-name@" + process.env.npm_package_version,
});
您如何使版本(version
)可用於您的程式碼取決於您。例如,您可以使用在構建過程中設定的環境變數。
這用 release
值標記每個事件。我們建議您在部署之前告訴 Sentry
一個新 release
,因為這將解鎖我們關於 releases
的文件中討論的更多功能。但是,如果您不這樣做,Sentry
將在第一次看到具有該 release ID
的事件時自動在系統中建立一個 release
實體。
配置您的 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
的問題詳細資訊頁面中更好地過濾問題、版本和使用者反饋,您可以在我們涵蓋使用環境的文件中瞭解更多資訊。
過濾
將 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
可以被過濾。
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
可在兩個地方獲得:
beforeSend / beforeBreadcrumb
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
(傳送的錯誤的 0%
)和 1
(傳送的錯誤的 100%
)之間的數字。 這是一個靜態比率,它同樣適用於所有錯誤。例如,要對 25%
的錯誤進行抽樣:
Sentry.init({ sampleRate: 0.25 });
更改錯誤取樣率需要重新部署。
此外,設定SDK
取樣率會限制對事件源的可見性。
為您的專案設定速率限制(僅在volume
高時丟棄事件)可能更適合您的需求。
取樣 Transaction 事件
我們建議對您的 transaction
進行抽樣,原因有兩個:
- 捕獲單個跟蹤涉及的開銷最小,但捕獲每個頁面載入或每個 API 請求的跟蹤可能會給您的系統增加不必要的負載。
- 啟用取樣可以讓您更好地管理髮送到 Sentry 的事件數量,因此您可以根據組織的需求定製您的數量。
選擇取樣率的目標是在效能和數量問題與資料準確性之間找到平衡。 您不想收集太多資料,但希望收集足夠的資料以得出有意義的結論。 如果您不確定要選擇什麼速率,請從一個較低的值開始,隨著您對流量模式和流量的瞭解越來越多,逐漸增加它。
配置 Transaction 取樣率
Sentry SDK
有兩個配置選項來控制傳送到 Sentry
的 transaction
量,讓您可以獲取具有代表性的樣本:
- 統一取樣率(
tracesSampleRate
):
- 提供均勻的事務橫截面,無論它們在您的應用程式中的哪個位置或在什麼情況下發生。
- 使用預設繼承(
inheritance
)和優先(precedence
)行為
- 取樣函式(
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
選項設定為 0
到 1
之間的數字。設定此選項後,建立的每個 transaction
都有該百分比的機會被髮送到 Sentry
。(因此,例如,如果您將 tracesSampleRate
設定為 0.2
,大約 20%
的 transaction
將被記錄和傳送。)看起來像這樣:
Sentry.init({
// ...
tracesSampleRate: 0.2,
});
設定取樣函式
要使用取樣函式,請將 Sentry.init()
中的 tracesSampler
選項設定為一個函式,該函式將接受 samplingContext
物件並返回介於 0
和 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
相當於返回 0
,並保證 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
當有可能不止一個發揮作用時,以下優先規則適用:
- 如果將抽樣決策傳遞給
startTransaction
(請參閱上面的強制抽樣決策),則將使用該決策,而不管其他任何事情 - 如果定義了
tracesSampler
,則將使用其決策。 它可以選擇保留或忽略任何父取樣決策,或使用取樣上下文資料來做出自己的決策或為transaction
選擇取樣率。 - 如果未定義
tracesSampler
,但存在父取樣決策,則將使用父取樣決策。 - 如果未定義
tracesSampler
並且沒有父取樣決策,則將使用tracesSampleRate
。
Sentry Testkit
在為您的應用程式構建測試時,您希望斷言正確的流跟蹤(flow-tracking
)或錯誤正在傳送到 Sentry
,但沒有真正將其傳送到 Sentry
伺服器。 這樣您就不會在測試執行或其他 CI 操作期間用錯誤報告淹沒 Sentry
。
注意:Sentry 合作伙伴 Wix
維護 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://examplePublicKey@o0.ingest.sentry.io/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
)生成指紋。 要擴充套件預設分組行為或完全更改它,您可以使用以下選項的組合:
- 在您的
SDK
中,使用SDK
指紋識別,如下所述 - 在您的專案中,使用指紋規則或堆疊跟蹤規則
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
。
- 從您的
[Account] > API keys
建立一個新的身份驗證令牌 - 確認您在
“Scopes”
下選擇了project:write
- 使用
npm
安裝@sentry/webpack-plugin
- 使用必要的配置建立
.sentryclirc
檔案,如本頁所述 - 更新你的
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://examplePublicKey@o0.ingest.sentry.io/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
文件。
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 的更多資訊,請參閱:
安全訪問 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
檔案可能位於兩個或多個不同的來源。 在這種情況下,我們建議在路徑上使用我們特殊的波浪號 (~
) 字首。
例如,如果您有以下內容:
您可以使用 ~/js/app.js
的 URL
上傳。這將告訴 Sentry
忽略域並將 artifact
用於任何來源。
此外,您還可以以多個名稱上傳同一個檔案。 在引擎蓋(hood
)下 Sentry 將對這些進行重複資料刪除。
~
字首告訴Sentry
對於給定的URL
,路徑為/js/app.js
的協議和主機名的任何組合都應該使用這個工件。
驗證檔案
確保 source maps
本身有效並正確上傳可能非常具有挑戰性。 為了解決這個問題,我們維護了一個線上驗證工具,可用於針對您的託管源測試您的 source map
: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
檔案。例如:
- 包括您的轉譯器/捆綁器輸出檔案的位置:
include: './app/.next'
include: './build'
- 包括來自多個資料夾:
包括:['./src', './lib']
- 遞迴搜尋整個專案:
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://examplePublicKey@o0.ingest.sentry.io/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
。
仔細檢查您部署的最終 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 file=@script.min.js.map \
-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
。
或者,如果您使用 Sentry CLI
將 source maps
上傳到 Sentry
,您可以使用 --validate
命令列選項來驗證您的 source maps
是否正確。
驗證您的 source maps 在本地工作
如果您發現 Sentry
沒有正確對映檔名、行或列對映,您應該驗證您的 source maps
是否在本地執行。為此,您可以將 Node.js
與 Mozilla
的source-map library
結合使用。
首先,將 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 後執行壓縮。
驗證 worker 與 Web 共享相同的卷(如果通過 Docker 執行自託管 Sentry)
Sentry 在其 worker
中進行 source map
計算。 這意味著 worker
需要訪問通過前端上傳的檔案。仔細檢查 cron worker
和 web worker
是否可以從同一個磁碟讀取/寫入檔案。
故障排除
如果您需要幫助解決 Sentry JavaScript SDK integration
問題,您可以閱讀此處記錄的邊緣案例。
除錯附加資料
您可以檢視事件的 JSON payload
以瞭解 Sentry
如何在事件中儲存其他資料。資料的形狀可能與描述不完全匹配。
有關更多詳細資訊,請參閱有關事件有效負載的完整文件。
最大 JSON Payload 大小
maxValueLength
的預設值為 250
,但如果您的訊息較長,您可以根據需要調整此值。 請注意,並非每個值都受此選項影響。
CORS 屬性和 Header
要了解從不同來源的指令碼引發的 JavaScript 異常,請執行以下兩項操作:
- 新增
crossorigin="anonymous"
指令碼屬性
<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>
指令碼屬性告訴瀏覽器 “anonymously”
獲取目標檔案。 請求此檔案時,瀏覽器不會將潛在的使用者識別資訊(如 cookie
或 HTTP
憑據)傳輸到伺服器。
- 新增
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
選項。 有關更多詳細資訊,請參閱我們的效能監控文件中的自動檢測。
instrument.js
Console Log 語句的行號
如果除錯時在您的控制檯中顯示了 instrument.js
,請將 Sentry
新增到您的框架黑盒設定中,例如:/@sentry/
,以便 Chrome
在除錯時忽略 SDK
堆疊幀。
處理廣告攔截器(Ad-Blockers)
當您使用我們的 CDN
時,廣告攔截或指令碼攔截擴充套件可能會阻止我們的 SDK
被正確獲取和初始化。因此,對 SDK API
的任何呼叫都將失敗,並可能導致您的應用程式出現意外行為。
此外,即使正確下載並初始化 SDK
,也可能會阻止需要接收捕獲資料的 Sentry
端點。這將阻止任何錯誤報告、會話執行狀況或效能資料的傳遞,從而使其在 sentry.io
中實際上不可用。
您可以通過上述多種方式解決第一個 issue
。但是,端點阻塞只能使用隧道解決。
使用 tunnel 選項
隧道是一個 HTTP
端點,充當 Sentry
和您的應用程式之間的代理。 由於您控制此伺服器,因此不會有任何傳送到它的請求被阻止的風險。 當端點位於同一個源下時(儘管它不必為了隧道工作),瀏覽器不會將任何對端點的請求視為第三方請求。因此,這些請求將應用不同的安全措施,預設情況下不會觸發廣告攔截器。可以在下面找到流程的快速摘要。
從 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://examplePublicKey@o0.ingest.sentry.io/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();
檢視我們的示例儲存庫以瞭解更多資訊。
如果您的用例與 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://examplePublicKey@o0.ingest.sentry.io/0",
});
client.captureException(new Error("example"));
雖然上面的示例應該可以正常工作,但 Client
上缺少一些方法,如 configureScope
和 withScope
,因為 Hub
負責狀態管理。這就是為什麼建立新 Hub
並將 Client
繫結到它可能更容易的原因。結果是一樣的,但你也會得到狀態管理。
import { BrowserClient, Hub } from "@sentry/browser";
const client = new BrowserClient({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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://examplePublicKey@o0.ingest.sentry.io/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)
。
公眾號:黑客下午茶