Automatic Instrumentation
要自动捕获 transactions,必须首先在应用程序中启用跟踪。
@sentry/tracing
包提供了一个 BrowserTracing
集成,以添加 automatic instrumentation 来监视浏览器应用程序的性能。
What Automatic Instrumentation Provides
BrowserTracing
集成为每个页面 load 和 navigation 事件创建一个新 transaction,并为在打开这些 transactions 时发生的每个 XMLHttpRequest
或 fetch
请求创建一个 child span。进一步了解 traces, transactions, and spans。
Enable Automatic Instrumentation
要启用此自动跟踪,请在 SDK 配置选项中包含 BrowserTracing
集成。(请注意,使用 ESM 模块时,主要的 @sentry/*
import 必须先于 @sentry/tracing
import。)
配置完成后,在 sentry.io 中查看 transactions 时,您将同时看到 pageload
和 navigation
。
ESM
// 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 { Integrations as TracingIntegrations } from "@sentry/tracing"; // Must import second Sentry.init({ dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", integrations: [ new Integrations.BrowserTracing({ tracingOrigins: ["localhost", "my-site-url.com", /^\//], // ... other options }), ], // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, });
CDN
Sentry.init({ dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", integrations: [ new Sentry.Integrations.BrowserTracing({ tracingOrigins: ["localhost", "my-site-url.com", /^\//], // ... other options }), ], // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, });
Configuration Options
您可以将许多不同的选项传递给 BrowserTracing
集成(作为 {optionName: value}
形式的对象),但是它具有合理的默认值。有关所有可能的选项,请参见 TypeDocs。
tracingOrigins
tracingOrigins
的默认值是 ['localhost', /^\//]
。JavaScript SDK 将 sentry-trace
header 附加到其目标包含列表中的字符串或匹配列表中的正则表达式的所有传出的 XHR/fetch
请求。如果您的前端向另一个域发出请求,则需要在其中添加它,以将 sentry-trace
header 传播到后端服务,这是将 transactions 链接在一起作为单个跟踪的一部分所必需的。tracingOrigins
选项与整个请求 URL 匹配,而不仅仅是域。使用更严格的正则表达式来匹配 URL 的某些部分,可以确保请求不用不必要地附加 sentry-trace
header。
例如:
- 前端应用程序是从
example.com
提供的 - 后端服务由
api.example.com
提供 - 前端应用程序对后端进行 API 调用
- 因此,该选项需要这样配置:
new Integrations.BrowserTracing({tracingOrigins: ['api.example.com']})
- 现在,向
api.example.com
发出的 XHR/fetch 请求将获得附加的sentry-trace
header
Sentry.init({ dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", integrations: [ new Integrations.BrowserTracing({ tracingOrigins: ["localhost", "my-site-url.com"], }), ], // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, });
您将需要配置您的 Web 服务器 CORS 以允许 sentry-trace
header。该配置可能类似于 "Access-Control-Allow-Headers: sentry-trace"
,但是该配置取决于您的设置。如果您不允许使用 sentry-trace
header,则该请求可能会被阻止。
beforeNavigate
对于 pageload
和 navigation
transactions,BrowserTracing
集成使用浏览器的 window.location
API 生成 transaction 名称。要自定义 pageload
和 navigation
transactions 的名称,您可以向 BrowserTracing
集成提供 beforeNavigate
选项。该选项允许您修改 transaction 名称以使其更通用,例如,名为 GET /users/12312012
和 GET /users/11212012
的 transactions 都可以重命名为 GET /users/:userid
,以便他们可以在一起。
import * as Sentry from "@sentry/browser"; import { Integrations } from "@sentry/tracing"; Sentry.init({ dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", integrations: [ new Integrations.BrowserTracing({ beforeNavigate: context => { return { ...context, // You could use your UI's routing library to find the matching // route template here. We don't have one right now, so do some basic // parameter replacements. name: location.pathname .replace(/\d+/g, "<digits>") .replace(/[a-f0-9]{32}/g, "<hash>"), }; }, }), ], // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, });
shouldCreateSpanForRequest
此函数可用于过滤掉不需要的 spans,例如 XHR 的运行状况检查或类似的检查。默认情况下,shouldCreateSpanForRequest
已经过滤掉了除了 tracingOrigins
中定义的内容以外的所有内容。
import * as Sentry from "@sentry/browser"; import { Integrations } from "@sentry/tracing"; Sentry.init({ dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", integrations: [ new Integrations.BrowserTracing({ shouldCreateSpanForRequest: url => { // Do not create spans for outgoing requests to a `/health/` endpoint return !url.match(/\/health\/?$/); }, }), ], // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, });
Manual Instrumentation
要手动捕获 transactions,必须首先在应用程序中启用跟踪。
要手动 instrument 代码的某些区域,可以创建 transactions 来捕获它们。
这对于所有 JavaScript SDK(后端和前端)均有效,并且独立于 Express
,Http
和 BrowserTracing
集成而工作。
const transaction = Sentry.startTransaction({ name: "test-transaction" }); const span = transaction.startChild({ op: "functionX" }); // This function returns a Span // functionCallX span.finish(); // Remember that only finished spans will be sent with the transaction transaction.finish(); // Finishing the transaction will send it to Sentry
例如,如果要为页面上的用户交互创建 transaction,请执行以下操作:
// Let's say this function is invoked when a user clicks on the checkout button of your shop shopCheckout() { // This will create a new Transaction for you const transaction = Sentry.startTransaction('shopCheckout'); // set the transaction on the scope so it picks up any errors hub.configureScope(scope => scope.setSpan(transaction)); // Assume this function makes an xhr/fetch call const result = validateShoppingCartOnServer(); const span = transaction.startChild({ data: { result }, op: 'task', description: `processing shopping cart result`, }); processAndValidateShoppingCart(result); span.finish(); transaction.finish(); }
这个例子将发送一个 transaction shopCheckout
到 Sentry。交易将包含一个 task
span,该 span 衡量 processAndValidateShoppingCart
花费了多长时间。最后,对 transaction.finish()
的调用将完成transaction 并将其发送给 Sentry。
在为异步操作创建 spans 时,您还可以利用 Promises。但是请记住,必须在调用 transaction.finish()
之前将其 span 包含在事务中。
例如:
function processItem(item, transaction) { const span = transaction.startChild({ op: "http", description: `GET /items/:item-id`, }); return new Promise((resolve, reject) => { http.get(`/items/${item.id}`, response => { response.on("data", () => {}); response.on("end", () => { span.setTag("http.status_code", response.statusCode); span.setData("http.foobarsessionid", getFoobarSessionid(response)); span.finish(); resolve(response); }); }); }); }
Connect Backend and Frontend Transactions
要将后端和前端 transactions 连接到单个一致的跟踪中,Sentry 使用 trace_id
值,该值在前端和后端之间传播。根据情况,此 ID 可以在请求 header 或 HTML <meta>
标记中传输。以这种方式链接 transactions 使您可以在 Sentry UI 中在它们之间进行导航,因此您可以更好地了解系统的不同部分如何相互影响。您可以在我们的分布式跟踪文档中了解有关此模型的更多信息。
Pageload
在前端和后端都启用跟踪并利用自动前端 instrumentation 功能时,可以将前端上自动生成的 pageload
transaction 与后端上的为页面服务提供请求的 transaction 相连接。因为在浏览器中运行的 JavaScript 代码无法读取当前页面的响应 headers,所以 trace_id
必须在响应本身中传输,尤其是在从后端发送的 HTML <head>
中的 <meta>
标签中。
<html> <head> <meta name="sentry-trace" content="{{ span.toTraceparent() }}" /> <!-- ... --> </head> </html>
name
属性必须是字符串 "sentry-trace"
,content
属性必须由后端的 Sentry SDK 使用 span.toTraceparent()
(或等效项,取决于后端平台)生成。这保证了将为每个请求生成一个新的唯一值。
span
引用是为 HTML 提供服务的 transaction,或其任何 child spans。它定义了 pageload
transaction 的父级。
一旦数据被包含在 <meta>
标签中,我们的 BrowserTracing
集成将自动获取数据并将其链接到在 pageload 时生成的 transaction。(请注意,它不会链接到自动生成的 navigation
transactions,即不需要重新加载整个页面的 transaction。每个 transaction 都是后端不同请求 transaction 的结果,因此应具有唯一的 trace_id
。)
Navigation and Other XHR Requests
加载页面后,它发出的任何请求(以及后端产生的任何请求)都通过请求 header 链接。
就像上面讨论的 <meta>
标签一样,标题的名称是 sentry-trace
,其值是通过调用 span.toTraceparent()
(或等效的)来获得的,其中 span
是相关 transaction 或其任何子项。
Sentry 的所有与跟踪相关的集成(BrowserTracing
,Http
和 Express
)都会针对它们生成的所有 transactions 和 spans 自动生成或拾取并传播此 header。在手动创建 transaction 或 span 的任何情况下,您都可以自己附加和读取 header,这样做很有意义。
Control Data Truncation
当前,每个标签的最大字符数限制为200个字符。超过200个字符限制的标签将被截断,丢失潜在的重要信息。要保留此数据,您可以将数据拆分为多个标签。
例如,一个200多个字符标记的请求:
上面200个字符以上的请求将被截断为:
相反,使用 span.set_tag
和 span.set_data
会使用结构化元数据保留此查询的详细信息。这可以通过 baseUrl
,endpoint
和 parameters
完成:
const baseUrl = "https://empowerplant.io"; const endpoint = "/api/0/projects/ep/setup_form"; const parameters = { user_id: 314159265358979323846264338327, tracking_id: "EasyAsABC123OrSimpleAsDoReMi", product_name: PlantToHumanTranslator, product_id: 161803398874989484820458683436563811772030917980576, }; const span = transaction.startChild({ op: "request", description: "setup form", }); span.setTag("baseUrl", baseUrl); span.setTag("endpoint", endpoint); span.setData("parameters", parameters); // you may also find some parameters to be valuable as tags span.setData("user_id", parameters.user_id); http.get(`${base_url}/${endpoint}/`, (data = parameters));
Group Transactions
Sentry 捕获 transactions 时,将为它们分配一个 transaction 名称。该名称通常由 Sentry SDK 根据您使用的框架集成自动生成。如果您无法利用自动 transaction 生成(或想要自定义 transaction 名称的生成方式),则可以使用,在使用配置初始化 SDK 时注册的全局事件处理器。
在 node.js 应用程序中执行此操作的示例:
import { addGlobalEventProcessor } from "@sentry/node"; addGlobalEventProcessor(event => { // if event is a transaction event if (event.type === "transaction") { event.transaction = sanitizeTransactionName(event.transaction); } return event; });
对于使用 BrowserTracing
集成的浏览器 JavaScript 应用程序,beforeNavigate
选项可用于根据 URL 更好地将 navigation/pageload
transactions 分组在一起。
import * as Sentry from "@sentry/browser"; import { Integrations } from "@sentry/tracing"; Sentry.init({ // ... integrations: [ new Integrations.BrowserTracing({ beforeNavigate: context => { return { ...context, // You could use your UI's routing library to find the matching // route template here. We don't have one right now, so do some basic // parameter replacements. name: location.pathname .replace(/\d+/g, "<digits>") .replace(/[a-f0-9]{32}/g, "<hash>"), }; }, }), ], });
Retrieve an Active Transaction
如果要将 Spans 附加到已在进行中的 transaction 中,例如在对 transaction 进行分组时,可以使用 Sentry.getCurrentHub().getScope().getTransaction()
。当 scope 中有正在运行的 transaction 时,此函数将返回一个 Transaction
对象,否则它将返回 undefined
。如果您使用的是 BrowserTracing 集成,则默认情况下,我们会将 transaction 附加到 Scope,因此您可以执行以下操作:
function myJsFunction() { const transaction = Sentry.getCurrentHub() .getScope() .getTransaction(); if (transaction) { let span = transaction.startChild({ op: "encode", description: "parseAvatarImages", }); // Do something span.finish(); } }