From def093aac94cf8ad7b7597f131daaf4daec5af5b Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 7 Aug 2024 13:22:00 +0200 Subject: [PATCH] feat(node): Add more detailed OTEL docs (#10872) --------- Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Co-authored-by: Lukas Stracke Co-authored-by: Liza Mock --- .../configuration/integrations/http.mdx | 17 ++ .../common/opentelemetry/custom-setup.mdx | 168 ++++++++++++++++ .../javascript/common/opentelemetry/index.mdx | 30 +++ .../using-opentelemetry-apis.mdx | 76 ++++++++ .../javascript/common/tracing/index.mdx | 16 +- .../tracing/instrumentation/opentelemetry.mdx | 184 ------------------ .../javascript-v8/general-other-changes.mdx | 2 +- src/middleware.ts | 4 + 8 files changed, 307 insertions(+), 190 deletions(-) create mode 100644 docs/platforms/javascript/common/opentelemetry/custom-setup.mdx create mode 100644 docs/platforms/javascript/common/opentelemetry/index.mdx create mode 100644 docs/platforms/javascript/common/opentelemetry/using-opentelemetry-apis.mdx delete mode 100644 docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx diff --git a/docs/platforms/javascript/common/configuration/integrations/http.mdx b/docs/platforms/javascript/common/configuration/integrations/http.mdx index 0b00b2db7a707..18c36bdc6858a 100644 --- a/docs/platforms/javascript/common/configuration/integrations/http.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/http.mdx @@ -64,3 +64,20 @@ The callback function receives two arguments: - `urlPath`: The URL path of the incoming request, including the query string if available. For example: `/users?name=John`. - `request`: An object of type `IncomingMessage` containing the incoming request. You can use this to filter on properties like the request method or headers. + +### `instrumentation` + +You can also pass some hooks through to the [underlying OpenTelemetry Instrumentation](https://www.npmjs.com/package/@opentelemetry/instrumentation-http): + +```typescript +httpIntegration({ + instrumentation?: { + requestHook?: (span: Span, req: ClientRequest | HTTPModuleRequestIncomingMessage) => void; + responseHook?: (span: Span, response: HTTPModuleRequestIncomingMessage | ServerResponse) => void; + applyCustomAttributesOnSpan?: ( + span: Span, + request: ClientRequest | HTTPModuleRequestIncomingMessage, + response: HTTPModuleRequestIncomingMessage | ServerResponse, + ) => void; +}); +``` diff --git a/docs/platforms/javascript/common/opentelemetry/custom-setup.mdx b/docs/platforms/javascript/common/opentelemetry/custom-setup.mdx new file mode 100644 index 0000000000000..c959e51987f02 --- /dev/null +++ b/docs/platforms/javascript/common/opentelemetry/custom-setup.mdx @@ -0,0 +1,168 @@ +--- +title: Using Your Existing OpenTelemetry Setup +description: "Learn how to use your existing custom OpenTelemetry setup with Sentry." +supported: + - javascript.nextjs + - javascript.node + - javascript.aws-lambda + - javascript.azure-functions + - javascript.connect + - javascript.express + - javascript.fastify + - javascript.gcp-functions + - javascript.hapi + - javascript.koa + - javascript.nestjs + - javascript.sveltekit + - javascript.astro + - javascript.remix +notSupported: + - javascript +sidebar_order: 0 +--- + +To use an existing OpenTelemetry setup, set `skipOpenTelemetrySetup: true` in your `init({})` config, then set up all the components that Sentry needs yourself. Finish by installing `@sentry/opentelemetry` and adding the following: + +```javascript +const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); +const Sentry = require("@sentry/node"); +const { + SentrySpanProcessor, + SentryPropagator, + SentrySampler, +} = require("@sentry/opentelemetry"); + +const sentryClient = Sentry.init({ + dsn: "___DSN___", + skipOpenTelemetrySetup: true, + + // The SentrySampler will use this to determine which traces to sample + tracesSampleRate: 1.0, +}); + +// Note: This could be BasicTracerProvider or any other provider depending on +// how you are using the OpenTelemetry SDK +const provider = new NodeTracerProvider({ + // Ensure the correct subset of traces is sent to Sentry + // This also ensures trace propagation works as expected + sampler: sentryClient ? new SentrySampler(sentryClient) : undefined, +}); + +// Ensure spans are correctly linked & sent to Sentry +provider.addSpanProcessor(new SentrySpanProcessor()); + +provider.register({ + // Ensure trace propagation works + // This relies on the SentrySampler for correct propagation + propagator: new SentryPropagator(), + // Ensure context & request isolation are correctly managed + contextManager: new Sentry.SentryContextManager(), +}); + +// Validate that the setup is correct +Sentry.validateOpenTelemetrySetup(); +``` + +Make sure that all [Required OpenTelemetry Instrumentation](./#required-instrumentation) is set up correctly. Otherwise, the Sentry SDK may not work as expected. + +## Using Sentry for Error Monitoring Only + +If you have a custom OpenTelemetry setup and only want to use Sentry for error monitoring, you can skip adding the `SentrySpanProcessor`. You'll still need to add the `SentryContextManager`, `SentryPropagator`, and `SentrySampler` to your setup even if you don't want to send any tracing data to Sentry. Read on to learn why this is needed. + + +In order for the Sentry SDK to work as expected, and for it to be in sync with OpenTelemetry, we need a few components to be in place. + +**Components needed for Sentry to work correctly:** + +- **SentryContextManager**: Ensures that the OpenTelemetry context is in sync with Sentry, for example to correctly isolate data between simultaneous requests. +- **SentrySampler**: Ensures that the Sentry `tracesSampleRate` is respected. Even if you don't use Sentry for tracing, you'll still need this in order for trace propagation to work as expected. Read [Using a Custom Sampler](./#using-a-custom-sampler) if you want to use a custom sampler. +- **SentryPropagator**: Ensures that trace propagation works correctly. +- [Required Instrumentation](./#required-instrumentation): Ensures that trace propagation works correctly. + +**Additional components needed to also use Sentry for tracing:** + +- **SentrySpanProcessor**: Ensures that spans are correctly sent to Sentry. + + +Trace propagation is needed for Sentry to automatically connect services together. (For example, if you want to connect the frontend and backend, or different backend services.) This makes it possible to see related errors across services. Learn more about Trace Propagation. + + +## Required Instrumentation + +By default, Sentry will register OpenTelemetry instrumentation to automatically capture spans for traces spanning incoming and outgoing HTTP requests, DB queries, and more. + +If tracing is not enabled (no `tracesSampleRate` is defined in the SDK configuration), only a minimal amount of OpenTelemetry instrumentation will be registered. This includes the following: + +- httpIntegration registers [@opentelemetry/instrumentation-http](https://www.npmjs.com/package/@opentelemetry/instrumentation-http) +- nativeNodeFetchIntegration registers [opentelemetry-instrumentation-fetch-node](https://www.npmjs.com/package/opentelemetry-instrumentation-fetch-node) + + + + If tracing is not enabled, performance instrumentations will not be registered but they will still be included in the bundle. If you + want to reduce the bundle size or used dependencies, you can also Set up Sentry without Performance Integrations. + + + +These are needed to make sure that trace propagation works correctly. Additionally, the HTTP instrumentation is configured to ensure that request isolation is automatically applied for Sentry. + +If you want to add your own http/node-fetch instrumentation, you have to follow the following steps: + +### Custom HTTP Instrumentation + +You won't be able to add `@opentelemetry/instrumentation-http` yourself and will need to use `httpIntegration` in order for Sentry to work as expected. If you want to use custom configuration for your HTTP instrumentation, you can use the httpIntegration configuration. + +### Custom Node Fetch Instrumentation + +If tracing is disabled, the Node Fetch instrumentation will not emit any spans. In this scenario, it will only inject sentry-specific trace propagation headers. You are free to add your own Node Fetch instrumentation on top of this which may emit spans as you like. + +## Using a Custom Sampler + +While you can use your own sampler, we recommend that you use the `SentrySampler`. This will ensure that the correct subset of traces will be sent to Sentry, based on your `tracesSampleRate`. It will also ensure that all other Sentry features like trace propagation work as expected. If you do need to use your own sampler, make sure to wrap your `SamplingResult` with our `wrapSamplingDecision` method like in the example below: + +```javascript +const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); +const Sentry = require("@sentry/node"); +const { + SentrySpanProcessor, + SentryPropagator, + SentrySampler, + wrapSamplingDecision +} = require("@sentry/opentelemetry"); + +// implements Sampler from "@opentelemetry/sdk-trace-node" +class CustomSampler { + shouldSample(context, _traceId, _spanName, _spanKind, attributes, _links) { + const decision = yourDecisionLogic(); + + // wrap the result + return wrapSamplingDecision({ + decision, + context, + spanAttributes: attributes, + }); + } + + toString() { + return CustomSampler.name; + } +} + +const sentryClient = Sentry.init({ + dsn: "___DSN___", + skipOpenTelemetrySetup: true, + + // By defining any sample rate, + // tracing intergations will be added by default + // omit this if you do not want any performance integrations to be added + tracesSampleRate: 0, +}); + +const provider = new NodeTracerProvider({ + sampler: new CustomSampler(), +}); + +// ...rest of your setup + +// Validate that the setup is correct +Sentry.validateOpenTelemetrySetup(); +``` diff --git a/docs/platforms/javascript/common/opentelemetry/index.mdx b/docs/platforms/javascript/common/opentelemetry/index.mdx new file mode 100644 index 0000000000000..ee78e5ea25b44 --- /dev/null +++ b/docs/platforms/javascript/common/opentelemetry/index.mdx @@ -0,0 +1,30 @@ +--- +title: OpenTelemetry Support +description: "Learn how to use OpenTelemetry with Sentry." +sidebar_order: 7000 +supported: + - javascript.nextjs + - javascript.node + - javascript.aws-lambda + - javascript.azure-functions + - javascript.connect + - javascript.express + - javascript.fastify + - javascript.gcp-functions + - javascript.hapi + - javascript.koa + - javascript.nestjs + - javascript.sveltekit + - javascript.astro + - javascript.remix +notSupported: + - javascript +--- + +The Sentry SDK uses [OpenTelemetry](https://opentelemetry.io/) under the hood. This means that any OpenTelemetry instrumentation that emits spans will automatically be picked up by Sentry without any further configuration. + +To start capturing traces and spans, set up Tracing and Performance Monitoring with your Sentry SDK. If you don't use tracing, Sentry still connects to OpenTelemetry under the hood to ensure that context isolation and trace propagation works correctly. + +By default, Sentry will automatically set up OpenTelemetry for you, but you can also use your own OpenTelemetry setup. Read the guides below to learn how to use a custom OpenTelemetry setup or how to get the most out of the Sentry and OpenTelemetry integration. + + diff --git a/docs/platforms/javascript/common/opentelemetry/using-opentelemetry-apis.mdx b/docs/platforms/javascript/common/opentelemetry/using-opentelemetry-apis.mdx new file mode 100644 index 0000000000000..fd53abddbc808 --- /dev/null +++ b/docs/platforms/javascript/common/opentelemetry/using-opentelemetry-apis.mdx @@ -0,0 +1,76 @@ +--- +title: Using OpenTelemetry APIs +description: "Learn how to use OpenTelemetry APIs with Sentry." +supported: + - javascript.nextjs + - javascript.node + - javascript.aws-lambda + - javascript.azure-functions + - javascript.connect + - javascript.express + - javascript.fastify + - javascript.gcp-functions + - javascript.hapi + - javascript.koa + - javascript.nestjs + - javascript.sveltekit + - javascript.astro + - javascript.remix +notSupported: + - javascript +sidebar_order: 1 +--- + +Sentry supports OpenTelemetry APIs out of the box. Any spans started using OpenTelemetry APIs will be automatically captured by Sentry, while any spans started using the Sentry SDK will be automatically propagated to OpenTelemetry. + +## Adding Additional OpenTelemetry Instrumentation + +While the Sentry SDK includes some OpenTelemetry instrumentation out of the box, you may want to add additional instrumentation to your application. This can be done by registering the instrumentation through OpenTelemetry like the example below: + +```javascript +const Sentry = require("@sentry/node"); +const { + GenericPoolInstrumentation, +} = require("@opentelemetry/instrumentation-generic-pool"); + +Sentry.init({ + dsn: "___DSN___", + + // The SentrySampler will use this to determine which traces to sample + tracesSampleRate: 1.0, +}); + +// Afterwards, you can add additional instrumentation: +Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation()); +``` + +Any instrumentation added like this or via `registerInstrumentations()` from `@opentelemetry/instrumentation` will be picked up by Sentry. + +## Using an OpenTelemetry Tracer + +We recommend using `Sentry.startSpan()` and related APIs to create spans, but you can also create spans using native OpenTelemetry APIs. + +You can access the tracer Sentry uses via `client.tracer` and then create spans with OpenTelemetry APIs, as shown below: + +```javascript +const Sentry = require("@sentry/node"); + +const tracer = Sentry.getClient()?.tracer; +// Now you can use native APIs on the tracer: +tracer.startActiveSpan("span name", () => { + // measure something +}); +``` + +You can also use any other tracer. All OpenTelemetry spans will be picked up by Sentry automatically. + +## Modifying the default OpenTelemetry TracerProvider + +You can access the tracer provider set up by Sentry when using Sentry's default OpenTelemetry instrumentation. This makes it easy to, for example, add additional span processors if you want to send span data to another backend or similar. + +```javascript +const Sentry = require("@sentry/node"); + +const provider = Sentry.getClient()?.traceProvider; +provider?.addSpanProcessor(new MySpanProcessor()); +``` diff --git a/docs/platforms/javascript/common/tracing/index.mdx b/docs/platforms/javascript/common/tracing/index.mdx index ae07be1d67bf0..f2b666d6f5436 100644 --- a/docs/platforms/javascript/common/tracing/index.mdx +++ b/docs/platforms/javascript/common/tracing/index.mdx @@ -14,7 +14,11 @@ If you’re adopting Tracing in a high-throughput environment, we recommend test - + + Sentry can integrate with OpenTelemetry. You can find more + information about it + here. + @@ -28,12 +32,14 @@ If you’re adopting Tracing in a high-throughput environment, we recommend test ## Configure - -First, enable tracing and configure the sampling rate for transactions. Set the sample rate for your transactions by either: + + First, enable tracing and configure the sampling rate for transactions. Set + the sample rate for your transactions by either: - -First, configure the sampling rate for transactions. Set the sample rate for your transactions by either: + + First, configure the sampling rate for transactions. Set the sample rate for + your transactions by either: - Setting a uniform sample rate for all transactions using the option in your SDK config to a number between `0` and `1`. (For example, to send 20% of transactions, set to `0.2`.) diff --git a/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx b/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx deleted file mode 100644 index 57fae8f9feff7..0000000000000 --- a/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: OpenTelemetry Support -description: "Using OpenTelemetry with Sentry Performance." -sidebar_order: 20 -supported: - - javascript.nextjs - - javascript.node - - javascript.aws-lambda - - javascript.azure-functions - - javascript.connect - - javascript.express - - javascript.fastify - - javascript.gcp-functions - - javascript.hapi - - javascript.koa - - javascript.nestjs - - javascript.sveltekit - - javascript.astro - - javascript.remix -notSupported: - - javascript ---- - -The Sentry SDK uses [OpenTelemetry](https://opentelemetry.io/) under the hood. This means that any OpenTelemetry instrumentation that emits spans will automatically be picked up by Sentry - no further configuration needed! To start using Sentry and OpenTelemetry together, set up [Tracing and Performance Monitoring with your Sentry SDK](../). - -## Using Custom OpenTelemetry Instrumentation - -While the Sentry SDK includes some OpenTelemetry instrumentation out of the box, you may want to add additional instrumentation to your application. This can be done by registering the instrumentation through OpenTelemetry like this: - -```js -const Sentry = require("@sentry/node"); -const { - GenericPoolInstrumentation, -} = require("@opentelemetry/instrumentation-generic-pool"); - -Sentry.init({ - dsn: "__DSN__", - - // The SentrySampler will use this to determine which traces to sample - tracesSampleRate: 1.0, -}); - -// Afterwards, you can add additional instrumentation: -Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation()); -``` - -Any instrumentation added like this will be automatically picked up by Sentry. - -## Using a Custom OpenTelemetry Setup - -If you already have OpenTelemetry set up yourself, you can also use your existing setup. - - - -This setup is only needed if you need to add custom span processors or exporters to your OpenTelemetry setup. Most Sentry users can follow standard SDK setup to get OpenTelemetry data with their SDK. - - - -In this case, you need to set `skipOpenTelemetrySetup: true` in your `init({})` config, and ensure you setup all the -components that Sentry needs yourself. In this case, you need to install `@sentry/opentelemetry`, and add the following: - -```js -const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); -const Sentry = require("@sentry/node"); -const { - SentrySpanProcessor, - SentryPropagator, - SentrySampler, -} = require("@sentry/opentelemetry"); - -const sentryClient = Sentry.init({ - dsn: "__DSN__", - skipOpenTelemetrySetup: true, - - // The SentrySampler will use this to determine which traces to sample - tracesSampleRate: 1.0, -}); - -// Note: This could be BasicTracerProvider or any other provider depending on -// how you are using the OpenTelemetry SDK -const provider = new NodeTracerProvider({ - // We need our sampler to ensure the correct subset of traces is sent to Sentry - sampler: sentryClient ? new SentrySampler(sentryClient) : undefined, -}); - -// We need a custom span processor -provider.addSpanProcessor(new SentrySpanProcessor()); - -// We need a custom propagator and context manager -provider.register({ - propagator: new SentryPropagator(), - contextManager: new Sentry.SentryContextManager(), -}); - -// Validate that the setup is correct -Sentry.validateOpenTelemetrySetup(); -``` - -## Using an OpenTelemetry Tracer - -We recommend using `Sentry.startSpan()` and related APIs to create spans. However, you can also use native OpenTelemetry APIs to create spans. - -You can access the tracer Sentry uses via `client.tracer` and then create spans with OpenTelemetry APIs, as shown below: - -```js -const Sentry = require("@sentry/node"); - -const tracer = Sentry.getClient()?.tracer; -// Now you can use native APIs on the tracer: -tracer.startActiveSpan("span name", () => { - // measure something -}); -``` - -You can also use any other tracer; all OpenTelemetry spans will be picked up by Sentry automatically. - -## Using a Custom Sampler - -We recommend using `SentrySampler` as this will ensure the correct subset of traces is sent to Sentry depending on your `tracesSampleRate`, as well as that all other Sentry features like trace propagation work as expected. -If you however need to use your own sampler then make sure to wrap your `SamplingResult` with our `wrapSamplingDecision` method: - -```js {filename: custom-sampler.js} -const { wrapSamplingDecision } = require("@sentry/opentelemetry"); - -// implements Sampler from "@opentelemetry/sdk-trace-node" -class CustomSampler { - shouldSample( - context, - _traceId, - _spanName, - _spanKind, - attributes, - _links - ) { - const decision = yourDecisionLogic(); - - // wrap the result - return wrapSamplingDecision({ - decision, - context, - spanAttributes: attributes, - }); - } - - toString() { - return CustomSampler.name; - } -} - -module.exports = CustomSampler; - -``` - -Now use your sampler in your `TraceProvider`: - -```js {filename: instrument.js} -const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); -const Sentry = require("@sentry/node"); -const { - SentrySpanProcessor, - SentryPropagator, - SentrySampler, -} = require("@sentry/opentelemetry"); -const CustomSampler = require("./custom-sampler"); - -const sentryClient = Sentry.init({ - dsn: "__DSN__", - skipOpenTelemetrySetup: true, - - // By defining any sample rate, - // tracing intergations will be added by default - tracesSampleRate: 0 -}); - - -const provider = new NodeTracerProvider({ - sampler: new CustomSampler(sentryClient), -}); - -// ...rest of your setup - -// Validate that the setup is correct -Sentry.validateOpenTelemetrySetup(); -``` \ No newline at end of file diff --git a/includes/migration/javascript-v8/general-other-changes.mdx b/includes/migration/javascript-v8/general-other-changes.mdx index 1012d2de71c33..ab52d9c4dc23b 100644 --- a/includes/migration/javascript-v8/general-other-changes.mdx +++ b/includes/migration/javascript-v8/general-other-changes.mdx @@ -35,7 +35,7 @@ should be set in the `Sentry.init()` options, or in your custom `Client`s option ```TypeScript Sentry.init({ - dsn: "__DSN__", + dsn: "___DSN___", integrations: [Sentry.browserTracingIntegration()], tracePropagationTargets: ["localhost", "example.com"], }); diff --git a/src/middleware.ts b/src/middleware.ts index cc52226128239..ae74ea47982f4 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1569,6 +1569,10 @@ const USER_DOCS_REDIRECTS: Redirect[] = [ from: '/platforms/javascript/guides/:guide/usage/sdk-fingerprinting/', to: '/platforms/javascript/guides/:guide/enriching-events/fingerprinting/', }, + { + from: '/platforms/javascript/guides/:guide/tracing/instrumentation/opentelemetry/', + to: '/platforms/javascript/guides/:guide/opentelemetry/', + }, { from: '/learn/cli/configuration/', to: '/cli/configuration/',