上传 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
:4.4, 5.0, 6.0, 7.1, 8.1, 9.0, 10.0Firefox
:latestChrome
:latestIE
:IE 10, IE 11iPhone
:iOS 12, IOS 13Edge
:latestSafari
:latest
支持 <= 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)
。