脑图
公众号:黑客下午茶
快速开始
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
不会应用。
更多:Data Source Name (DSN) | Sentry Documentation
debug
打开或关闭调试模式。如果启用了调试,如果发送事件时出现问题,SDK
将尝试打印出有用的调试信息。默认值总是 false
。一般不建议在生产环境中打开它,尽管打开 debug
模式不会引起任何安全问题。
release
设置 release。某些 SDK
会尝试自动配置 release
,但是最好手动设置 release
,以确保该 release
与您的 deploy integrations
或 source map uploads
同步。Release
名称是字符串,但是 Sentry
会检测到某些格式,并且它们的呈现方式可能有所不同。
更多:Releases | Sentry Documentation
默认情况下,SDK
会尝试从环境变量 SENTRY_RELEASE
中读取该值(在浏览器 SDK
中,将从 window.SENTRY_RELEASE
中读取该值,如果可用)。
environment
设置环境。此字符串为自由形式,默认情况下不设置。一个 release
可以与多个环境相关联,以便在 UI 中将它们分开(可以考虑staging
与 prod
或类似的方式)。
默认情况下,SDK
将尝试从 SENTRY_ENVIRONMENT
环境变量中读取该值(浏览器 SDK
除外)。
tunnel
设置将用于传输捕获事件的 URL
,而不是使用 DSN
。这可用于解决广告拦截器(ad-blockers
)或对发送到 Sentry
的事件进行更精细的控制。此选项需要实现自定义服务器端点。
更多:Troubleshooting for Browser JavaScript | Sentry Documentation
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 入门。
我们支持 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
的概念验证集成 - 一个用于记录和重放用户会话的工具包。 这在诊断丰富的单页应用程序中的复杂用户行为时非常有用。
更多信息:
- rrweb.io | Open source web session replay library
- Filtering for React | Sentry Documentation
- Attachments for React | Sentry Documentation
配置
要开始,您需要添加 @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
实体。
- release:Releases | Sentry Documentation
配置您的 SDK
后,您可以安装 repository integration
或手动为 Sentry
提供您自己的 commit metadata
。 阅读我们关于设置 releases
的文档,以获取有关集成 integrations
、关联提交 associating commits
以及在部署 releases
时通知 Sentry
的更多信息。
- 设置 releases: Set Up | Sentry Documentation
Release 运行状况
通过观察用户采用情况、应用程序使用情况、崩溃百分比和会话数据来监控 release
的运行状况。 release
运行状况将深入了解与用户体验相关的崩溃和错误的影响,并通过 release
详细信息、图表和过滤器揭示每个新问题的趋势。
- health of releases : Release Health | Sentry Documentation
- crashes:Release Health | Sentry Documentation
- session data:Release Health | Sentry Documentation
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: Environments | Sentry Documentation
Sentry.init({
environment: "production",
});
环境可帮助您在 sentry.io
的问题详细信息页面中更好地过滤问题、版本和用户反馈,您可以在我们涵盖使用环境的文档中了解更多信息。
- environments:Environments | Sentry Documentation
过滤
将 Sentry 添加到您的应用程序可为您提供大量关于错误和性能的非常有价值的信息,否则您将无法获得这些信息。 大量的信息是好的——只要它是正确的信息,并且数量合理。
Sentry SDK
有几个配置选项可以帮助您过滤事件。
我们还提供入站过滤器 Inbound Filters
来过滤 sentry.io
中的事件。 不过,我们建议在客户端级别进行过滤,因为它消除了发送您实际上不想要的事件的开销。 了解有关事件中可用字段的更多信息。
- Inbound Filters: Inbound Filters | Sentry Documentation
- fields available in an event:Event Payloads | Sentry Developer Documentation
过滤错误事件
通过使用 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: Filtering for React | Sentry Documentation
当 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:Inclusive Language | Sentry Developer Documentation
此外,我们的社区还为日常事务编制了一份常见的忽略规则列表,例如 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: Sampling for React | Sentry Documentation
precedence:
Sampling for React | Sentry Documentation
Filters:
Filtering for React | Sentry Documentation
设置统一采样率
为此,请将 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: Set Up Performance for Browser JavaScript | Sentry Documentation
如果当前正在创建的 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: sentry-testkit/test at master · zivl/sentry-testkit · GitHub
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: Breadcrumbs for React | Sentry Documentation
捕获 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: Fingerprint Rules | Sentry Documentation
以更大的粒度对错误进行分组
您的应用程序查询远程过程调用模型 (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:source-map-support - npm
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:SourceMapDevToolPlugin | webpack
Rollup
您可以配置 Rollup
以生成 source maps
,然后您可以使用 sentry-cli
上传 source maps
:
- Rollup:Rollup | Rollup
- upload using sentry-cli:Release Management | Sentry Documentation
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:GitHub - systemjs/builder: SystemJS build tool
- upload using sentry-cli:Release Management | Sentry Documentation
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:Releases | Sentry Documentation
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:Releases | Sentry Documentation
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:Release Management | Sentry Documentation
Web 应用程序可在多个来源访问的情况并不少见。 请参阅我们关于多源的文档以了解如何处理此问题。
- multiple origins:Troubleshooting Source Maps for React | Sentry Documentation
公开托管
将
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:IP Ranges | Sentry Documentation
安全访问 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
。
- Auto-Minify: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 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
堆栈帧。
- blackboxing:Troubleshooting for React | Sentry Documentation
处理广告拦截器(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)
。