diff --git a/src/docs/product/performance/getting-started.mdx b/src/docs/product/performance/getting-started.mdx index b92dbe2d47a75f..642689c72c53dc 100644 --- a/src/docs/product/performance/getting-started.mdx +++ b/src/docs/product/performance/getting-started.mdx @@ -13,16 +13,16 @@ After this quick setup, you'll have access to [Performance](/product/performance Sentry's Performance features are now generally available. Customers on any of our legacy plans will need to add transaction events to their subscription to access Performance. For more details about access to these features, feel free to reach out at [performance-feedback@sentry.io](mailto:performance-feedback@sentry.io). -Supported SDKs for Tracing - -- JavaScript Browser SDK ≥ 5.16.0 -- JavaScript Node SDK ≥ 5.16.0 -- Python SDK version ≥ 0.11.2 -- JavaScript React SDK ≥ 5.18.1 - -## Install and Configure an SDK +## Using in SDKs - +- [JavaScript](/platforms/javascript/#monitor-performance) +- [Angular](/platforms/javascript/guides/angular/#monitor-performance) +- [React](/platforms/javascript/guides/react/#monitor-performance) +- [Vue](/platforms/javascript/guides/vue/#monitor-performance) +- [Node.js](/platforms/node/#monitor-performance) +- [Express](/platforms/node/guides/express/#monitor-performance) +- [Koa](/platforms/node/guides/koa/#monitor-performance) +- [Python](/platforms/python/#monitor-performance) diff --git a/src/includes/performance-monitoring/configuration/koa.mdx b/src/includes/performance-monitoring/configuration/koa.mdx deleted file mode 100644 index f3880299b4cbdf..00000000000000 --- a/src/includes/performance-monitoring/configuration/koa.mdx +++ /dev/null @@ -1,126 +0,0 @@ -**Koa** - -To get started with performance monitoring with Koa, first install these packages: - -```bash -# Using yarn -$ yarn add @sentry/node @sentry/tracing - -# Using npm -$ npm install --save @sentry/node @sentry/tracing -``` - - - -We switched our package name from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](/product/performance/apm-to-tracing/). - - - -Creates and attach a transaction to each context - -```javascript -const Sentry = require("@sentry/node"); -const { Span } = require("@sentry/tracing"); -const Koa = require("koa"); -const app = new Koa(); -const domain = require("domain"); - -Sentry.init({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, // Be sure to lower this in production -}); - -// not mandatory, but adding domains do help a lot with breadcrumbs -const requestHandler = (ctx, next) => { - return new Promise((resolve, _) => { - const local = domain.create(); - local.add(ctx); - local.on("error", err => { - ctx.status = err.status || 500; - ctx.body = err.message; - ctx.app.emit("error", err, ctx); - }); - local.run(async () => { - Sentry.getCurrentHub().configureScope(scope => - scope.addEventProcessor(event => - Sentry.Handlers.parseRequest(event, ctx.request, { user: false }) - ) - ); - await next(); - resolve(); - }); - }); -}; - -// this tracing middleware creates a transaction per request -const tracingMiddleWare = async (ctx, next) => { - // captures span of upstream app - const sentryTraceId = ctx.request.get("sentry-trace"); - let traceId; - let parentSpanId; - let sampled; - if (sentryTraceId) { - const span = Span.fromTraceparent(sentryTraceId); - if (span) { - traceId = span.traceId; - parentSpanId = span.parentSpanId; - sampled = span.sampled; - } - } - const transaction = Sentry.startTransaction({ - name: `${ctx.method} ${ctx.url}`, - op: "http.server", - parentSpanId, - traceId, - sampled, - }); - ctx.__sentry_transaction = transaction; - await next(); - - // if using koa router, a nicer way to capture transaction using the matched route - if (ctx._matchedRoute) { - const mountPath = ctx.mountPath || ""; - transaction.setName(`${ctx.method} ${mountPath}${ctx._matchedRoute}`); - } - transaction.setHttpStatus(ctx.status); - transaction.finish(); -}; - -app.use(requestHandler); -app.use(tracingMiddleWare); - -// usual error handler -app.on("error", (err, ctx) => { - Sentry.withScope(scope => { - scope.addEventProcessor(event => { - return Sentry.Handlers.parseRequest(event, ctx.request); - }); - Sentry.captureException(err); - }); -}); -// the rest of your app -``` - -**Subsequent manual child spans** - -The following example creates a span for a part of the code that contains an -expensive operation and sends the result to Sentry. You will need to use the -transaction stored in the context. - -```javascript -const myMiddleware = async (ctx, next) => { - let span; - const transaction = ctx.__sentry_transaction; - if (transaction) { - span = transaction.startChild({ - description: route, - op: "myMiddleware", - }); - } - await myExpensiveOperation(); - if (span) { - span.finish(); - } - return next(); -}; -``` diff --git a/src/includes/performance-monitoring/configuration/node.mdx b/src/includes/performance-monitoring/configuration/node.mdx deleted file mode 100644 index fbff0f99e3652b..00000000000000 --- a/src/includes/performance-monitoring/configuration/node.mdx +++ /dev/null @@ -1,196 +0,0 @@ ---- -hide_from_sidebar: true ---- - -**Node** - -To get started with performance monitoring with Node.js, first install these packages: - -```bash -# Using yarn -$ yarn add @sentry/node @sentry/tracing - -# Using npm -$ npm install --save @sentry/node @sentry/tracing -``` - - - -We switched our package name from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](/product/performance/apm-to-tracing/). - - - -**Sending Traces** - -To send traces, set the `tracesSampleRate` to a nonzero value. The following configuration will capture 100% of all your transactions: - -```javascript -const Sentry = require("@sentry/node"); -// or use es6 import statements -// import * as Sentry from '@sentry/node'; - -// This is required since it patches functions on the hub -const Tracing = require("@sentry/tracing"); -// or use es6 import statements -// import * as Tracing from '@sentry/tracing'; - -Sentry.init({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, // Be sure to lower this in production -}); - -// Your test code to verify it works - -const transaction = Sentry.startTransaction({ - op: "test", - name: "My First Test Transaction", -}); - -setTimeout(() => { - try { - foo(); - } catch (e) { - Sentry.captureException(e); - } finally { - transaction.finish(); - } -}, 99); - -// --------------------------------- -``` - -Performance data is transmitted using a new event type called "transactions", which you can learn about in [Distributed Tracing](/performance-monitoring/distributed-tracing/#traces-transactions-and-spans). **To capture transactions, you must install the performance package and configure your SDK to set the `tracesSampleRate` option to a nonzero value.** The example configuration above will transmit 100% of captured transactions. Be sure to lower this value in production otherwise you could burn through your quota quickly. - -**Automatic Instrumentation** - -It’s possible to add tracing to all popular frameworks; however, we only provide pre-written handlers for Express. - -```javascript -const Sentry = require("@sentry/node"); -const Tracing = require("@sentry/tracing"); -const express = require("express"); -const app = express(); - -Sentry.init({ - dsn: "___PUBLIC_DSN___", - integrations: [ - // enable HTTP calls tracing - new Sentry.Integrations.Http({ tracing: true }), - // enable Express.js middleware tracing - new Tracing.Integrations.Express({ app }), - ], - tracesSampleRate: 1.0, // Be sure to lower this in production -}); - -// RequestHandler creates a separate execution context using domains, so that every -// transaction/span/breadcrumb is attached to its own Hub instance -app.use(Sentry.Handlers.requestHandler()); -// TracingHandler creates a trace for every incoming request -app.use(Sentry.Handlers.tracingHandler()); - -// the rest of your app - -app.use(Sentry.Handlers.errorHandler()); -app.listen(3000); -``` - -Spans are instrumented for the following operations within a transaction: - -- HTTP requests made with `request` -- `get` calls using native `http` and `https` modules -- Middleware (Express.js only) - -**Trace context for Errors** - -By default, Sentry error events will not get trace context unless you configure the scope with the transaction. For example: - -```js -const Sentry = require("@sentry/node"); -const Tracing = require("@sentry/tracing"); - -const http = require("http"); - -Sentry.init({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, - integrations: [ - // enable HTTP calls tracing - new Sentry.Integrations.Http({ tracing: true }), - ], -}); - -const transaction = Sentry.startTransaction({ - op: "transaction", - name: "My Transaction", -}); - -// Note that we set the transaction as the span on the scope. -// This step makes sure that if an error happens during the lifetime of the transaction -// the transaction context will be attached to the error event -Sentry.configureScope(scope => { - scope.setSpan(transaction); -}); - -let request; - -try { - // this should generate an http span - request = http.get("http://sentry.io", res => { - console.log(`STATUS: ${res.statusCode}`); - console.log(`HEADERS: ${JSON.stringify(res.headers)}`); - }); - - // this error event should have trace context - foo(); -} catch (err) { - Sentry.captureException(err); -} - -request.on("close", () => { - transaction.finish(); -}); -``` - -**Manual Instrumentation** - -To manually instrument a specific region of your code, you can create a transaction to capture it. - -The following example creates a transaction for a part of the code that contains an expensive operation (for example, `processItem`), and sends the result to Sentry: - -```javascript -app.use(function processItems(req, res, next) { - const item = getFromQueue(); - const transaction = Sentry.startTransaction({ - op: "task", - name: item.getTransaction(), - }); - - // processItem may create more spans internally (see next examples) - processItem(item, transaction).then(() => { - transaction.finish(); - next(); - }); -}); -``` - -#### Retrieving a Transaction - -In cases where you want to attach Spans to an already ongoing Transaction you can use `Sentry.getCurrentHub().getScope().getTransaction()`. This function will return a `Transaction` in case there is a running Transaction otherwise it returns `undefined`. If you are using our Express integration by default we attach the Transaction to the Scope. So you could do something like this: - -```javascript -app.get("/success", function successHandler(req, res) { - const transaction = Sentry.getCurrentHub() - .getScope() - .getTransaction(); - - if (transaction) { - let span = transaction.startChild({ - op: "encode", - description: "parseAvatarImages", - }); - // Do something - span.finish(); - } - res.status(200).end(); -}); -``` diff --git a/src/includes/performance-monitoring/configuration/react.mdx b/src/includes/performance-monitoring/configuration/react.mdx deleted file mode 100644 index b844edb1c2d3fb..00000000000000 --- a/src/includes/performance-monitoring/configuration/react.mdx +++ /dev/null @@ -1,101 +0,0 @@ -**React** - -To get started with performance monitoring using Sentry's React SDK, first install the `@sentry/react` and `@sentry/tracing` packages: - -```bash -# Using yarn -$ yarn add @sentry/react @sentry/tracing - -# Using npm -$ npm install --save @sentry/react @sentry/tracing -``` - - - -We switched our package name from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](/product/performance/apm-to-tracing/). - - - -Next, initialize the integration in your call to `Sentry.init`. Make sure this happens before you mount your React component on the page. - -```jsx -import * as Sentry from "@sentry/react"; -import { Integrations } from "@sentry/tracing"; -Sentry.init({ - dsn: "___PUBLIC_DSN___", - release: "my-project-name@" + process.env.npm_package_version, - integrations: [new Integrations.BrowserTracing()], - tracesSampleRate: 1.0, // Be sure to lower this in production -}); - -// ... - -ReactDOM.render(, rootNode); - -// Can also use with React Concurrent Mode -// ReactDOM.createRoot(rootNode).render(); -``` - -**`withProfiler` Higher-Order Component** - -`@sentry/react` exports a `withProfiler` higher-order component that leverages the `@sentry/tracing` package to add React-related spans to transactions. - -In the example below, the `withProfiler` higher-order component is used to instrument an App component. - -```jsx -import React from "react"; -import * as Sentry from "@sentry/react"; - -class App extends React.Component { - render() { - return ( - - - - - ); - } -} - -export default Sentry.withProfiler(App); -``` - -The React Profiler currently generates spans with three different kinds of op-codes: `react.mount`, `react.render`, and `react.update`. - -`react.mount` - -: The span that represents how long it took for the profiled component to mount. - -`react.render` - -: The span that represents how long the profiled component was on a page. This span is only generated if the profiled component mounts and unmounts while a transaction is occurring. - -`react.update` - -: The span that represents when the profiled component updated. This span is only generated if the profiled component has mounted. - - - - - In [React Strict Mode](https://reactjs.org/docs/strict-mode.html), certain component methods will be [invoked twice](https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects). This may lead to duplicate `react.mount` spans appearing in a transaction. React Strict Mode only runs in development mode, so this will have no impact on your production traces. - - - - -The `withProfiler` higher-order component has a variety of options for further customization. They can be passed in as the second argument to the `withProfiler` function. - -```jsx -export default Sentry.withProfiler(App, { name: "CustomAppName" }); -``` - -`name` (string) - -: The name of the component being profiled. By default, the name is taken from the component `displayName` property or the component `name` property. - -`includeRender` (boolean) - -: If a `react.render` span should be created by the Profiler. Set as true by default. - -`includeUpdates` (boolean) - -: If `react.update` spans should be created by the Profiler. Set as true by default. We recommend setting this prop as false for components that will experience many rerenders, such as text input components, as the resulting spans can be very noisy. diff --git a/src/includes/performance-monitoring/configuration/javascript.mdx b/src/platforms/javascript/common/performance.mdx similarity index 79% rename from src/includes/performance-monitoring/configuration/javascript.mdx rename to src/platforms/javascript/common/performance.mdx index 0a73e40c7cd7f9..36a7cd537a7f29 100644 --- a/src/includes/performance-monitoring/configuration/javascript.mdx +++ b/src/platforms/javascript/common/performance.mdx @@ -1,39 +1,37 @@ -To get started with performance monitoring using Sentry's JavaScript SDK, first install the `@sentry/browser` and `@sentry/tracing` packages: +--- +title: Performance +description: "Learn more about how to configure our Performance integrations to get the best experience out of it." +--- -```bash -# Using yarn -$ yarn add @sentry/browser @sentry/tracing + -# Using npm -$ npm install --save @sentry/browser @sentry/tracing -``` +The `BrowserTracing` package is designed to work with `@sentry/tracing` and one of our browser JavaScript packages (`@sentry/browser`, `@sentry/react`, `@sentry/angular` etc.) and requires those packages to be installed and set up. For information on how to set up performance monitoring with JavaScript, see [the Performance documentation](../../#monitor-performance) -The integration name was updated from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](/product/performance/apm-to-tracing/). +The integration name was updated from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](./apm-to-tracing/). -Next, initialize the integration in your call to `Sentry.init`: + + +### Automatic Instrumentation + +The `BrowserTracing` integration provides automatic instrumentation to monitor the performance of browser applications. -```jsx +The `BrowserTracing` integration resides in the `@sentry/tracing` package. You can add it to your `Sentry.init` call: + +```javascript {tabTitle: ESM} import * as Sentry from "@sentry/browser"; import { Integrations } from "@sentry/tracing"; Sentry.init({ dsn: "___PUBLIC_DSN___", - release: "my-project-name@" + process.env.npm_package_version, integrations: [new Integrations.BrowserTracing()], tracesSampleRate: 1.0, // Be sure to lower this in production }); ``` -Alternatively, instead of npm packages, you can use our pre-built CDN bundle that combines both `@sentry/browser` and `@sentry/tracing`: - - - -Next, initialize the integration in your call to `Sentry.init`: - -```js +```javascript {tabTitle: CDN} Sentry.init({ dsn: "___PUBLIC_DSN___", integrations: [new Sentry.Integrations.BrowserTracing()], @@ -41,51 +39,26 @@ Sentry.init({ }); ``` -Performance data is transmitted using a new event type called "transactions," which you can learn about in [Distributed Tracing](/performance-monitoring/distributed-tracing/#traces-transactions-and-spans). **To capture transactions, you must install the performance package and configure your SDK to set the `tracesSampleRate` configuration to a nonzero value.** The example configuration above will transmit 100% of captured transactions. Be sure to lower this value in production otherwise you could burn through your quota quickly. +After configuration, you should see both pageload and navigation transactions show up in your Sentry UI. -Learn more about sampling in [Using Your SDK to Filter Events](/error-reporting/configuration/filtering/). - -### Automatic Instrumentation +You can pass many different options to the `BrowserTracing` integration (as an object of the form `{optionName: value}`), but it comes with reasonable defaults out of the box. For all possible options, see [TypeDocs](https://getsentry.github.io/sentry-javascript/interfaces/tracing.browsertracingoptions.html). -For `@sentry/browser`, we provide an integration called `BrowserTracing` that does automatic instrumentation in the browser. The `BrowserTracing` integration creates `pageload` and `navigation` transactions containing spans for XHR/fetch requests and Performance API entries such as marks, measures, and resource timings. +### tracingOrigins -The `BrowserTracing` integration is specific to `@sentry/browser` and does not work with `@sentry/node`. - -The `BrowserTracing` integration resides in the `@sentry/tracing` package. You can add it to your `Sentry.init` call: +Usage: ```javascript -// Without CDN - -import * as Sentry from "@sentry/browser"; -import { Integrations } from "@sentry/tracing"; - Sentry.init({ dsn: "___PUBLIC_DSN___", - integrations: [new Integrations.BrowserTracing()], - tracesSampleRate: 1.0, // Be sure to lower this in production -}); - -// With CDN - -Sentry.init({ - dsn: "___PUBLIC_DSN___", - integrations: [new Sentry.Integrations.BrowserTracing()], + integrations: [ + new Integrations.BrowserTracing({ + tracingOrigins: ["localhost", "my-site-url.com"], + }), + ], tracesSampleRate: 1.0, // Be sure to lower this in production }); ``` -_NOTE:_ The `BrowserTracing` integration is available under `Sentry.Integrations.BrowserTracing` when using the CDN bundle. - -To send traces, you will need to set the `tracesSampleRate` to a nonzero value. The configuration above will capture 100% of your transactions. - -By default, the `pageload` and `navigation` transactions set a transaction name using `window.location.pathname`. - -You can pass many different options to the `BrowserTracing` integration (as an object of the form `{optionName: value}`), but it comes with reasonable defaults out of the box. - -For all possible options, see [TypeDocs](https://getsentry.github.io/sentry-javascript/interfaces/tracing.browsertracingoptions.html). - -#### tracingOrigins Option - The default value of `tracingOrigins` is `['localhost', /^\//]`. The JavaScript SDK will attach the `sentry-trace` header to all outgoing XHR/fetch requests whose destination contains a string in the list or matches a regex in the list. If your frontend is making requests to a different domain, you will need to add it there to propagate the `sentry-trace` header to the backend services, which is required to link transactions together as part of a single trace. **One important thing to note is that the `tracingOrigins` option matches against the whole request URL, not just the domain. Using stricter regex to match certain parts of the URL can help make sure that requests do not unnecessarily have the `sentry-trace` header attached.** _Example:_ @@ -96,9 +69,9 @@ _Example:_ - Therefore, the option needs to be configured like this: `new Integrations.BrowserTracing({tracingOrigins: ['api.example.com']})` - Now outgoing XHR/fetch requests to `api.example.com` will get the `sentry-trace` header attached -_NOTE:_ You need to make sure your web server CORS is configured to allow the `sentry-trace` header. The configuration might look like `"Access-Control-Allow-Headers: sentry-trace"`, but this depends a lot on your setup. If you do not allow the `sentry-trace` header, the request might be blocked. +_NOTE:_ You need to make sure your web server CORS is configured to allow the `sentry-trace` header. The configuration might look like `"Access-Control-Allow-Headers: sentry-trace"`, but the configuration depends on your set up. If you do not allow the `sentry-trace` header, the request might be blocked. -#### beforeNavigate Option +### beforeNavigate For `pageload` and `navigation` transactions, the `BrowserTracing` integration uses the browser's `window.location` API to generate a transaction name. To customize the name of the `pageload` and `navigation` transactions, you can supply a `beforeNavigate` option to the `BrowserTracing` integration. This option allows you to pass in a function that takes in the location at the time of navigation and returns a new transaction name. @@ -129,6 +102,31 @@ Sentry.init({ }); ``` +### shouldCreateSpanForRequest + +This function can be used to filter our unwanted Spans like XHR's running health checks or something similar. By default `shouldCreateSpanForRequest` is already filtering out what was defined in `tracingOrigins`. + +```javascript +import * as Sentry from "@sentry/browser"; +import { Integrations } from "@sentry/tracing"; +Sentry.init({ + dsn: "___PUBLIC_DSN___", + integrations: [ + new Integrations.BrowserTracing({ + shouldCreateSpanForRequest: url => { + // Example of filter out spans that contain `health` + if (url.match(/health/)) { + return false; + } + return true; + }, + }), + ], + tracesSampleRate: 1.0, // Be sure to lower this in production +}); +``` + + ### Manual Instrumentation To manually instrument certain regions of your code, you can create a transaction to capture them. @@ -296,3 +294,8 @@ span.setData("parameters", parameters); span.setData("user_id", parameters.user_id); http.get(`${base_url}/${endpoint}/`, (data = parameters)); ``` + +## Next Steps: + +- [Return to performance monitoring page](../) +- [Return to **Getting Started**](../../) \ No newline at end of file diff --git a/src/docs/product/performance/apm-to-tracing.mdx b/src/platforms/javascript/common/performance/apm-to-tracing.mdx similarity index 100% rename from src/docs/product/performance/apm-to-tracing.mdx rename to src/platforms/javascript/common/performance/apm-to-tracing.mdx diff --git a/src/platforms/javascript/guides/vue/index.mdx b/src/platforms/javascript/guides/vue/index.mdx index 5115f47eafb479..24f50f2a5e3380 100644 --- a/src/platforms/javascript/guides/vue/index.mdx +++ b/src/platforms/javascript/guides/vue/index.mdx @@ -73,4 +73,45 @@ like this: ``` - +## Monitor Performance + +```bash {tabTitle:npm} +$ npm install --save @sentry/browser @sentry/integrations @sentry/tracing +``` + +```bash {tabTitle:Yarn} +$ yarn add @sentry/browser @sentry/integrations @sentry/tracing +``` + +The most basic configuration for tracing your Vue app, which would track only the top-level component, looks like this: + +```js +import * as Sentry from "@sentry/browser"; +import { Vue as VueIntegration } from "@sentry/integrations"; +import { Integrations } from "@sentry/tracing"; +import Vue from "vue"; + +Sentry.init({ + // ... + integrations: [ + new Integrations.BrowserTracing(), + new VueIntegration({ + Vue, + tracing: true, + }), + ], + tracesSampleRate: 1.0, // Be sure to lower this in production +}); +``` + +If you want to track child components, and see more details about the rendering process, configure the integration to track them all: + +```js +new VueIntegration({ + Vue, + tracing: true, + tracingOptions: { + trackComponents: true, + }, +}); +``` \ No newline at end of file diff --git a/src/includes/performance-monitoring/configuration/vue.mdx b/src/platforms/javascript/guides/vue/integrations/components.mdx similarity index 89% rename from src/includes/performance-monitoring/configuration/vue.mdx rename to src/platforms/javascript/guides/vue/integrations/components.mdx index eacbe4cccf667e..348c490486c6b6 100644 --- a/src/includes/performance-monitoring/configuration/vue.mdx +++ b/src/platforms/javascript/guides/vue/integrations/components.mdx @@ -1,20 +1,6 @@ -**Vue.js** - -To get started with performance monitoring with Vue.js, first install these packages: - -```bash -# Using yarn -$ yarn add @sentry/browser @sentry/integrations @sentry/tracing - -# Using npm -$ npm install --save @sentry/browser @sentry/integrations @sentry/tracing -``` - - - -We switched our package name from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](/product/performance/apm-to-tracing/). - - +--- +title: Performance Integration +--- The Vue Tracing Integration allows you to track rendering performance during an initial application load. diff --git a/src/platforms/javascript/index.mdx b/src/platforms/javascript/index.mdx index 8c6a015832a5c4..9f64120994203e 100644 --- a/src/platforms/javascript/index.mdx +++ b/src/platforms/javascript/index.mdx @@ -114,7 +114,7 @@ $ npm install --save @sentry/browser @sentry/tracing -We switched our package name from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](/product/performance/apm-to-tracing/). +We switched our package name from `@sentry/apm` to `@sentry/tracing`. If you were previously using `@sentry/apm`, please see [Switching to @sentry/tracing](./performance/apm-to-tracing/). If you are using our CDN, please see our documentation for [installing with CDN](/platforms/javascript/configuration/install-cdn). diff --git a/src/platforms/node/common/performance.mdx b/src/platforms/node/common/performance.mdx new file mode 100644 index 00000000000000..0abed036cd1ec3 --- /dev/null +++ b/src/platforms/node/common/performance.mdx @@ -0,0 +1,99 @@ +--- +title: Performance +description: "Learn more about how to configure our Performance integrations to get the best experience out of it." +--- + +### Trace Context for Errors + +By default, Sentry error events will not get trace context unless you configure the scope with the transaction. For example: + +```js +const Sentry = require("@sentry/node"); +const Tracing = require("@sentry/tracing"); + +const http = require("http"); + +Sentry.init({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, + integrations: [ + // enable HTTP calls tracing + new Sentry.Integrations.Http({ tracing: true }), + ], +}); + +const transaction = Sentry.startTransaction({ + op: "transaction", + name: "My Transaction", +}); + +// Note that we set the transaction as the span on the scope. +// This step makes sure that if an error happens during the lifetime of the transaction +// the transaction context will be attached to the error event +Sentry.configureScope(scope => { + scope.setSpan(transaction); +}); + +let request; + +try { + // this should generate an http span + request = http.get("http://sentry.io", res => { + console.log(`STATUS: ${res.statusCode}`); + console.log(`HEADERS: ${JSON.stringify(res.headers)}`); + }); + + // this error event should have trace context + foo(); +} catch (err) { + Sentry.captureException(err); +} + +request.on("close", () => { + transaction.finish(); +}); +``` + +## Manual Instrumentation + +To manually instrument a specific region of your code, you can create a transaction to capture it. + +The following example creates a transaction for a part of the code that contains an expensive operation (for example, `processItem`), and sends the result to Sentry: + +```javascript +app.use(function processItems(req, res, next) { + const item = getFromQueue(); + const transaction = Sentry.startTransaction({ + op: "task", + name: item.getTransaction(), + }); + + // processItem may create more spans internally (see next examples) + processItem(item, transaction).then(() => { + transaction.finish(); + next(); + }); +}); +``` + +### Retrieving a Transaction + +In cases where you want to attach Spans to an already ongoing Transaction you can use `Sentry.getCurrentHub().getScope().getTransaction()`. This function will return a `Transaction` in case there is a running Transaction otherwise it returns `undefined`. If you are using our Express integration by default we attach the Transaction to the Scope. So you could do something like this: + +```javascript +app.get("/success", function successHandler(req, res) { + const transaction = Sentry.getCurrentHub() + .getScope() + .getTransaction(); + + if (transaction) { + let span = transaction.startChild({ + op: "encode", + description: "parseAvatarImages", + }); + // Do something + span.finish(); + } + res.status(200).end(); +}); +``` \ No newline at end of file diff --git a/src/platforms/node/guides/express/index.mdx b/src/platforms/node/guides/express/index.mdx index 1595ba61f8b475..0c9d1a56da70d6 100644 --- a/src/platforms/node/guides/express/index.mdx +++ b/src/platforms/node/guides/express/index.mdx @@ -140,6 +140,53 @@ app.use(Sentry.Handlers.errorHandler()); app.use(Sentry.Handlers.errorHandler() as express.ErrorRequestHandler); ``` +## Monitor Performance + +```bash {tabTitle:npm} +$ npm install --save @sentry/node @sentry/tracing +``` + +```bash {tabTitle:Yarn} +$ yarn add @sentry/node @sentry/tracing +``` + +It’s possible to add tracing to all popular frameworks; however, we only provide pre-written handlers for Express. + +```javascript +const Sentry = require("@sentry/node"); +const Tracing = require("@sentry/tracing"); +const express = require("express"); +const app = express(); + +Sentry.init({ + dsn: "___PUBLIC_DSN___", + integrations: [ + // enable HTTP calls tracing + new Sentry.Integrations.Http({ tracing: true }), + // enable Express.js middleware tracing + new Tracing.Integrations.Express({ app }), + ], + tracesSampleRate: 1.0, // Be sure to lower this in production +}); + +// RequestHandler creates a separate execution context using domains, so that every +// transaction/span/breadcrumb is attached to its own Hub instance +app.use(Sentry.Handlers.requestHandler()); +// TracingHandler creates a trace for every incoming request +app.use(Sentry.Handlers.tracingHandler()); + +// the rest of your app + +app.use(Sentry.Handlers.errorHandler()); +app.listen(3000); +``` + +Spans are instrumented for the following operations within a transaction: + +- HTTP requests made with `request` +- `get` calls using native `http` and `https` modules +- Middleware (Express.js only) + ### Troubleshooting When capturing errors locally, ensure that your project's data filter for filtering localhost events is toggled off: diff --git a/src/platforms/node/guides/koa/index.mdx b/src/platforms/node/guides/koa/index.mdx index 3ca909d7f5a034..8909260460b4a3 100644 --- a/src/platforms/node/guides/koa/index.mdx +++ b/src/platforms/node/guides/koa/index.mdx @@ -40,3 +40,122 @@ app.on("error", (err, ctx) => { app.listen(3000); ``` + +## Monitor Performance + +```bash {tabTitle:npm} +$ npm install --save @sentry/node @sentry/tracing +``` + +```bash {tabTitle:Yarn} +$ yarn add @sentry/node @sentry/tracing +``` + +Creates and attach a transaction to each context + +```javascript +const Sentry = require("@sentry/node"); +const { Span } = require("@sentry/tracing"); +const Koa = require("koa"); +const app = new Koa(); +const domain = require("domain"); + +Sentry.init({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, // Be sure to lower this in production +}); + +// not mandatory, but adding domains do help a lot with breadcrumbs +const requestHandler = (ctx, next) => { + return new Promise((resolve, _) => { + const local = domain.create(); + local.add(ctx); + local.on("error", err => { + ctx.status = err.status || 500; + ctx.body = err.message; + ctx.app.emit("error", err, ctx); + }); + local.run(async () => { + Sentry.getCurrentHub().configureScope(scope => + scope.addEventProcessor(event => + Sentry.Handlers.parseRequest(event, ctx.request, { user: false }) + ) + ); + await next(); + resolve(); + }); + }); +}; + +// this tracing middleware creates a transaction per request +const tracingMiddleWare = async (ctx, next) => { + // captures span of upstream app + const sentryTraceId = ctx.request.get("sentry-trace"); + let traceId; + let parentSpanId; + let sampled; + if (sentryTraceId) { + const span = Span.fromTraceparent(sentryTraceId); + if (span) { + traceId = span.traceId; + parentSpanId = span.parentSpanId; + sampled = span.sampled; + } + } + const transaction = Sentry.startTransaction({ + name: `${ctx.method} ${ctx.url}`, + op: "http.server", + parentSpanId, + traceId, + sampled, + }); + ctx.__sentry_transaction = transaction; + await next(); + + // if using koa router, a nicer way to capture transaction using the matched route + if (ctx._matchedRoute) { + const mountPath = ctx.mountPath || ""; + transaction.setName(`${ctx.method} ${mountPath}${ctx._matchedRoute}`); + } + transaction.setHttpStatus(ctx.status); + transaction.finish(); +}; + +app.use(requestHandler); +app.use(tracingMiddleWare); + +// usual error handler +app.on("error", (err, ctx) => { + Sentry.withScope(scope => { + scope.addEventProcessor(event => { + return Sentry.Handlers.parseRequest(event, ctx.request); + }); + Sentry.captureException(err); + }); +}); +// the rest of your app +``` + +### Subsequent Manual Child Spans + +The following example creates a span for a part of the code that contains an +expensive operation and sends the result to Sentry. You will need to use the +transaction stored in the context. + +```javascript +const myMiddleware = async (ctx, next) => { + let span; + const transaction = ctx.__sentry_transaction; + if (transaction) { + span = transaction.startChild({ + description: route, + op: "myMiddleware", + }); + } + await myExpensiveOperation(); + if (span) { + span.finish(); + } + return next(); +}; +``` diff --git a/src/platforms/node/index.mdx b/src/platforms/node/index.mdx index 64c1a0e0e3c719..16211acacf817e 100644 --- a/src/platforms/node/index.mdx +++ b/src/platforms/node/index.mdx @@ -53,3 +53,60 @@ try { Sentry.captureException(e); } ``` + +## Monitor Performance + +To get started with performance monitoring with Node.js, first install these packages: + +```bash {tabTitle:npm} +$ npm install --save @sentry/node @sentry/tracing +``` + +```bash {tabTitle:Yarn} +$ yarn add @sentry/node @sentry/tracing +``` + +To send traces, set the `tracesSampleRate` to a nonzero value. The following configuration will capture 100% of all your transactions: + +```javascript {tabTitle:CommonJS} +const Sentry = require("@sentry/node"); +const Tracing = require("@sentry/tracing"); + +Sentry.init({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, // Be sure to lower this in production +}); +``` + +```javascript {tabTitle:ESM} +import * as Sentry from '@sentry/node'; +import * as Tracing from '@sentry/tracing'; + +Sentry.init({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, // Be sure to lower this in production +}); +``` + +Performance data is transmitted using a new event type called "transactions", which you can learn about in [Distributed Tracing](/performance-monitoring/distributed-tracing/#traces-transactions-and-spans). **To capture transactions, you must install the performance package and configure your SDK to set the `tracesSampleRate` option to a nonzero value.** The example configuration above will transmit 100% of captured transactions. You will want to lower this value in production, otherwise you could burn through your quota quickly. + +## Verify Setup + +Verify your setup by intentionally sending a transaction manually to Sentry. Make sure your sampling rate is at `1.0` so that your transaction captured and sent to Sentry. + +```javascript +const transaction = Sentry.startTransaction({ + op: "test", + name: "My First Test Transaction", +}); + +setTimeout(() => { + try { + foo(); + } catch (e) { + Sentry.captureException(e); + } finally { + transaction.finish(); + } +}, 99); +``` \ No newline at end of file diff --git a/src/includes/performance-monitoring/configuration/python.mdx b/src/platforms/python/common/performance.mdx similarity index 82% rename from src/includes/performance-monitoring/configuration/python.mdx rename to src/platforms/python/common/performance.mdx index a0d413d0986bff..22221ff975aef0 100644 --- a/src/includes/performance-monitoring/configuration/python.mdx +++ b/src/platforms/python/common/performance.mdx @@ -1,27 +1,14 @@ --- -hide_from_sidebar: true +title: Performance +excerpt: "" +description: "Learn more about how to configure our Performance integrations to get the best experience out of it." --- -To get started with performance monitoring using Sentry's Python SDK, first install `sentry_sdk`: +Performance Monitoring helps you see everything from macro-level metrics to micro-level spans, and you’ll be able to cross-reference transactions with related issues, customize queries based on your personal needs, and substantially more and is avaliable for the Sentry Python SDK version ≥ 0.11.2. -```python -import sentry_sdk -``` - -Next, initialize the integration in your call to `sentry_sdk.init`: - -```python -sentry_sdk.init( - "___PUBLIC_DSN___", - traces_sample_rate=1.0 # be sure to lower this in production to prevent quota issues -) -``` - -Performance data is transmitted using a new event type called "transactions", which you can learn about in [Distributed Tracing](/performance-monitoring/distributed-tracing/#traces-transactions-and-spans). **To capture transactions, you must install and configure your SDK to set the `traces_sample_rate` option to a nonzero value.** The example configuration above will transmit 100% of captured traces. Be sure to lower this value in production otherwise you could burn through your quota quickly. - -Learn more about sampling in [Using Your SDK to Filter Events](/error-reporting/configuration/filtering/). +For information on how to set up performance monitoring with Python, see [the Performance documentation](../../#monitor-performance) -**Automatic Instrumentation** +## Automatic Instrumentation Many integrations for popular frameworks automatically capture transactions. If you already have any of the following frameworks set up for Sentry error reporting, you will start to see traces immediately: @@ -48,7 +35,7 @@ sentry_sdk.init( ) ``` -**Manual Instrumentation** +## Manual Instrumentation To manually instrument certain regions of your code, you can create a transaction to capture them. @@ -65,7 +52,7 @@ while True: process_item(item) ``` -**Adding More Spans to the Transaction** +### Adding More Spans to the Transaction The next example contains the implementation of the hypothetical `process_item` function called from the code snippet in the previous section. Our SDK can determine if there is currently an open transaction and add all newly created spans as child operations to that transaction. Keep in mind that each individual span also needs to be manually finished; otherwise, spans will not show up in the transaction. When using spans and transactions as context managers, they are automatically finished at the end of the `with` block. @@ -101,7 +88,7 @@ def process_item(item): span.set_data("http.foobarsessionid", get_foobar_sessionid()) ``` -#### Retrieving a Transaction +### Retrieving a Transaction In cases where you want to attach Spans to an already ongoing Transaction you can use `Hub.current.scope.transaction`. This property will return a `Transaction` in case there is a running Transaction otherwise it returns `None`. @@ -119,7 +106,7 @@ else: do_task() ``` -#### Retrieving the current Span +### Retrieving the Current Span Started spans are stored in the scope, and can be fetched off the scope: @@ -138,7 +125,7 @@ else: do_task() ``` -**Adding Query Information and Parameters to Spans** +### Adding Query Information and Parameters to Spans Currently, every tag has a maximum character limit of 200 characters. Tags over the 200 character limit will become truncated, losing potentially important information. To retain this data, you can split data over several tags instead. diff --git a/src/platforms/python/index.mdx b/src/platforms/python/index.mdx index b910d2f62f403c..b6215f04b6872d 100644 --- a/src/platforms/python/index.mdx +++ b/src/platforms/python/index.mdx @@ -69,3 +69,27 @@ except Exception as e: # Alternatively the argument can be omitted capture_exception(e) ``` + +## Monitor Performance + +To get started with performance monitoring using Sentry's Python SDK, first install `sentry_sdk`: + +```bash +pip install --upgrade sentry-sdk +``` + + +Next, initialize the integration in your call to `sentry_sdk.init`: + +```python +import sentry_sdk + +sentry_sdk.init( + "___PUBLIC_DSN___", + traces_sample_rate=1.0 # be sure to lower this in production to prevent quota issues +) +``` + +Performance data is transmitted using a new event type called "transactions", which you can learn about in [Distributed Tracing](/performance-monitoring/distributed-tracing/#traces-transactions-and-spans). **To capture transactions, you must install and configure your SDK to set the `traces_sample_rate` option to a nonzero value.** The example configuration above will transmit 100% of captured traces. Be sure to lower this value in production otherwise you could burn through your quota quickly. + +Learn more about sampling in [Using Your SDK to Filter Events](/error-reporting/configuration/filtering/). \ No newline at end of file