From 85c1559f240011f7373e5add9e0e5ea2a88656e5 Mon Sep 17 00:00:00 2001
From: Krystof Woldrich
Date: Tue, 10 Sep 2024 18:20:35 +0200
Subject: [PATCH 01/12] Add React Native V6 Changes
---
.../enriching-events/context/index.mdx | 5 +-
.../enriching-events/scopes/index.mdx | 155 +++++++++----
.../transaction-name/index.mdx | 8 +-
docs/platforms/react-native/index.mdx | 12 +-
.../react-native/integrations/custom.mdx | 119 +++++++++-
.../react-native/integrations/default.mdx | 120 +++-------
.../integrations/error-boundary.mdx | 8 +-
.../react-native/integrations/plugin.mdx | 97 +++++++-
docs/platforms/react-native/tracing/index.mdx | 4 -
.../automatic-instrumentation.mdx | 111 ++++-----
.../custom-instrumentation.mdx | 216 +++++++++++++++++-
.../instrumentation/react-navigation-v4.mdx | 96 --------
.../configuration/integrations/plugin.mdx | 134 -----------
.../configuration/dedupe/react-native.mdx | 9 -
.../react-native.mdx | 10 -
.../react-native.mdx | 9 -
.../http-client/react-native.mdx | 26 ---
.../linked-errors/react-native.mdx | 15 --
.../rewrite-frames/react-native.mdx | 30 ---
.../enriching-events/import/react-native.mdx | 3 -
.../set-transaction-name/react-native.mdx | 3 -
.../filter-span-example/react-native.mdx | 13 --
22 files changed, 618 insertions(+), 585 deletions(-)
delete mode 100644 docs/platforms/react-native/tracing/instrumentation/react-navigation-v4.mdx
delete mode 100644 includes/platforms/configuration/integrations/plugin.mdx
delete mode 100644 platform-includes/configuration/dedupe/react-native.mdx
delete mode 100644 platform-includes/configuration/enable-pluggable-integrations-lazy/react-native.mdx
delete mode 100644 platform-includes/configuration/enable-pluggable-integrations/react-native.mdx
delete mode 100644 platform-includes/configuration/http-client/react-native.mdx
delete mode 100644 platform-includes/configuration/linked-errors/react-native.mdx
delete mode 100644 platform-includes/configuration/rewrite-frames/react-native.mdx
delete mode 100644 platform-includes/enriching-events/import/react-native.mdx
delete mode 100644 platform-includes/enriching-events/set-transaction-name/react-native.mdx
delete mode 100644 platform-includes/performance/filter-span-example/react-native.mdx
diff --git a/docs/platforms/react-native/enriching-events/context/index.mdx b/docs/platforms/react-native/enriching-events/context/index.mdx
index cb533c9061010a..fc9fe8ff41ed74 100644
--- a/docs/platforms/react-native/enriching-events/context/index.mdx
+++ b/docs/platforms/react-native/enriching-events/context/index.mdx
@@ -89,6 +89,7 @@ Sentry.captureException(new Error("something went wrong"), () => scope);
Context is held in the current scope and thus is cleared when the scope is removed ("popped"). You can push and pop your own scopes to apply context data to a specific code block or function.
+
Sentry supports two different ways for unsetting context:
1. Modifying, overwriting or clearing values on the current scope.
@@ -100,10 +101,10 @@ With the following snippet, the `user` context will be updated for all future ev
Sentry.setUser(someUser);
```
-If you want to remove data from the current scope, you can call:
+If you want to remove all data from the current scope, you can call:
```javascript
-Sentry.configureScope((scope) => scope.clear());
+Sentry.getCurrentScope().clear();
```
The following will only configure the `user` context for the error captured inside the `withScope` callback. The context will be automatically restored to the previous state afterwards:
diff --git a/docs/platforms/react-native/enriching-events/scopes/index.mdx b/docs/platforms/react-native/enriching-events/scopes/index.mdx
index b7491c6792745f..34ba5fa7a67e6f 100644
--- a/docs/platforms/react-native/enriching-events/scopes/index.mdx
+++ b/docs/platforms/react-native/enriching-events/scopes/index.mdx
@@ -1,46 +1,112 @@
---
-title: Scopes and Hubs
+title: Scopes
description: "SDKs will typically automatically manage the scopes for you in the framework integrations. Learn what a scope is and how you can use it to your advantage."
---
When an event is captured and sent to Sentry, SDKs will merge that event data with extra
information from the current scope. SDKs will typically automatically manage the scopes
for you in the framework integrations and you don't need to think about them. However,
-you should know what a scope is and how you can use it for your advantage.
+you should know what a scope is and how you can use it to your advantage.
-## What's a Scope, What's a Hub
+## What's a Scope?
-You can think of the hub as the central point that our SDKs use to route an
-event to Sentry. When you call `init()` a hub is created and a client and a
-blank scope are created on it. That hub is then associated with the current
-thread and will internally hold a stack of scopes.
-
-The scope will hold useful information that should be sent along with the
-event. For instance [contexts](../context/) or
+Scopes hold useful information that gets sent along with the
+event. For instance, [contexts](../context/) and
[breadcrumbs](../breadcrumbs/) are stored on
-the scope. When a scope is pushed, it inherits all data from the parent scope
-and when it pops all modifications are reverted.
+the scope. When a scope is forked, it inherits all data from its parent scope.
+
+The default SDK integrations will fork scopes intelligently. For
+instance, web framework integrations will fork scopes around your
+routes or request handlers.
+
+## How Scopes Work
+
+Scopes are basically a stack of data that is attached to events. When an event is captured, the SDK will merge the data from the active scopes into the event. This allows you to attach data to events that is relevant to the context in which the event was captured.
+
+A scope is generally valid inside of a callback or an execution context. This means that multiple parts of your application may have different scopes active at the same time. For instance, a web server might handle multiple requests at the same time, and each request may have different scope data to apply to its events.
+
+## Different Kinds of Scopes
+
+The Sentry SDK has three different kinds of scopes:
+
+- [Global scope](#global-scope)
+- [Isolation scope](#isolation-scope)
+- [Current scope](#current-scope)
+
+### Global Scope
+
+The global scope is applied to _all_ events, no matter where they originate. You can use it to store data that should apply to all events, such as environmental information.
+
+You can access the global scope via `Sentry.getGlobalScope()`.
+
+Note that the global scope can only be used to write data, not to capture events. Events can only be captured on the current scope (e.g. `getCurrentScope().captureException()` and similar APIs).
+
+### Isolation Scope
+
+The isolation scope is used to isolate events from each other. For example, each request in a web server might get its own isolation scope, so that events from one request don't interfere with events from another request. In most cases, you'll want to put data that should be applied to your events on the isolation scope - which is also why all `Sentry.setXXX` methods, like `Sentry.setTag()`, will write data onto the currently active isolation scope. A classic example for data that belongs on the isolation scope is a user - each request may have a different user, so you want to make sure that the user is set on the isolation scope.
-The default SDK integrations will push and pop scopes intelligently. For
-instance web framework integrations will create and destroy scopes around your
-routes or controllers.
+You can access the isolation scope via `Sentry.getIsolationScope()`, but usually you'll just use the `Sentry.setXXX` methods to set data on the currently active isolation scope:
-## How the Scope and Hub Work
+```javascript
+Sentry.setTag("my-tag", "my value");
+// Is identical to:
+Sentry.getIsolationScope().setTag("my-tag", "my value");
+```
-As you start using an SDK, a scope and hub are automatically created for you out
-of the box. It's unlikely that you'll interact with the hub directly unless you're
-writing an integration or you want to create or destroy scopes. Scopes, on the
-other hand are more user facing. You can call at any point in
-time to modify data stored on the scope. This is useful for doing things like
-[modifying the context](../context/).
+
+ In the browser, the isolation scope is never forked, because it is impossible
+ to keep track of where an isolation scope would belong to. Because of this, in
+ the browser the isolation scope is effectively global.
+
-When you call a global function such as internally Sentry
-discovers the current hub and asks it to capture an event. Internally the hub will
-then merge the event with the topmost scope's data.
+Note that the isolation scope can only be used to write data, not to capture events. Events can only be captured on the current scope (e.g. `getCurrentScope().captureException()` and similar APIs).
+
+### Current Scope
+
+The current scope is the local scope that is currently active. Unlike the rarely-forked isolation scope, the current scope may be forked more frequently and under the hood. It can be used to store data that should only be applied to specific events. In most cases, you should not access this scope directly, but use `Sentry.withScope` to create a new scope that is only active for a specific part of your code:
+
+```javascript
+Sentry.withScope((scope) => {
+ // scope is the current scope inside of this callback!
+ scope.setTag("my-tag", "my value");
+ // this tag will only be applied to events captured inside of this callback
+ // the following event will have the tag:
+ Sentry.captureException(new Error("my error"));
+});
+// this event will not have the tag:
+Sentry.captureException(new Error("my other error"));
+```
+
+You can access the current scope via `Sentry.getCurrentScope()`, but usually you should use `Sentry.withScope()` to interact with local scopes instead.
+
+## How Scope Data is Applied to Events
+
+Before an event (like an error or transaction) is sent to Sentry, the currently active scopes are applied to it.
+
+The global scope is applied first, followed by the isolation scope, and finally the current scope. This means that any data set on the current scope will take precedence over data set on the isolation and global scopes:
+
+```javascript
+Sentry.getGlobalScope().setExtras({
+ shared: "global",
+ global: "data",
+});
+Sentry.getIsolationScope().setExtras({
+ shared: "isolation",
+ isolation: "data",
+});
+Sentry.getCurrentScope().setExtras({
+ shared: "current",
+ current: "data",
+});
+
+Sentry.captureException(new Error("my error"));
+// --> Will have the following extra:
+// { shared: 'current', global: 'data', isolation: 'data', current: 'data' }
+```
## Configuring the Scope
-The most useful operation when working with scopes is the function. It can be used to reconfigure the current scope.
+There are two main ways to interact with the scope. You can access the current scope via `Sentry.getCurrentScope()` and use setters on the resulting scope, or you can use global methods like `Sentry.setTag()` directly, which will set on the respective scope under the hood (which will be the isolation scope).
You'll first need to import the SDK, as usual:
@@ -48,31 +114,32 @@ You'll first need to import the SDK, as usual:
You can, for instance, add custom tags or inform Sentry about the currently authenticated user.
-
-
-You can also apply this configuration when unsetting a user at logout:
-
-
+```javascript
+/// Usually, you don't want to write on the current scope, so use with care!
+const scope = Sentry.getCurrentScope();
+scope.setTag("my-tag", "my value");
+scope.setUser({
+ id: 42,
+ email: "john.doe@example.com",
+});
+
+// Or use the global methods (which will set data on the isolation scope):
+Sentry.setTag("my-tag", "my value");
+Sentry.setUser({
+ id: 42,
+ email: "john.doe@example.com",
+});
+```
To learn what useful information can be associated with scopes see
-[the context documentation](../context/).
+[context](../context/), [tags](../tags), [users](../identify-user) and [breadcrumbs](../breadcrumbs/).
-## Local Scopes
-
-We also support pushing and configuring a scope within a single call. This is typically
-called , or implemented as a function parameter on the capture methods, depending on the SDK. It's very helpful if
-you only want to send data for one specific event.
-
-### Using
+## Using `withScope`
In the following example we use to attach a `level` and a `tag` to only one specific error:
-While this example looks similar to , it is actually very different.
-Calls to change the current active scope; all successive calls to will maintain previously set changes unless they are explicitly unset.
-
-On the other hand, creates a clone of the current scope, and the changes
-made will stay isolated within the callback function. This allows you to
+The scope inside the `withScope()` callback is only valid inside of the callback. Once the callback ends, the scope will be removed and no longer applied. The inner scope is only applied to events that are captured inside of the callback. `withScope()` will clone (or fork) the current scope, so that the current scope is not modified. This allows you to
more easily isolate pieces of context information to specific locations in your code or
even call to briefly remove all context information.
diff --git a/docs/platforms/react-native/enriching-events/transaction-name/index.mdx b/docs/platforms/react-native/enriching-events/transaction-name/index.mdx
index 252a245f8d31b0..3d4b603d5b24e5 100644
--- a/docs/platforms/react-native/enriching-events/transaction-name/index.mdx
+++ b/docs/platforms/react-native/enriching-events/transaction-name/index.mdx
@@ -22,10 +22,14 @@ A lot of our framework integrations already set a transaction name, though you c
You'll first need to import the SDK, as usual:
-
+```javascript
+import * as Sentry from "@sentry/react-native";
+```
To override the name of the currently running transaction:
-
+```javascript
+Sentry.getCurrentScope().setTransactionName("UserListView");
+```
Please refer to [the tracing documentation](../../tracing/) for how to start and stop transactions.
diff --git a/docs/platforms/react-native/index.mdx b/docs/platforms/react-native/index.mdx
index 2d1ef4768d228d..e152b4e6d6a6a8 100644
--- a/docs/platforms/react-native/index.mdx
+++ b/docs/platforms/react-native/index.mdx
@@ -38,7 +38,7 @@ Sentry captures data by using an SDK within your application's runtime. These ar
To install, run `@sentry/wizard`:
```bash {tabTitle:npm}
-npx @sentry/wizard@latest -s -i reactNative
+npx @sentry/wizard@latest -i reactNative
```
[Sentry Wizard](https://github.com/getsentry/sentry-wizard) will patch your project accordingly, though you can [set up manually](/platforms/react-native/manual-setup/manual-setup/) if you prefer. You only need to patch the project once. Then you can add the patched files to your version control system.
@@ -65,7 +65,7 @@ If you're using Expo, [read our docs](/platforms/react-native/manual-setup/expo/
To capture all errors, initialize the Sentry React Native SDK as soon as possible.
-```javascript {filename:App.js} {"onboardingOptions": {"performance": "5-7", "profiling": "8-12"}}
+```javascript {filename:App.js} {"onboardingOptions": {"performance": "5-7", "profiling": "8-10"}}
import * as Sentry from "@sentry/react-native";
Sentry.init({
@@ -73,11 +73,9 @@ Sentry.init({
// Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
// We recommend adjusting this value in production.
tracesSampleRate: 1.0,
- _experiments: {
- // profilesSampleRate is relative to tracesSampleRate.
- // Here, we'll capture profiles for 100% of transactions.
- profilesSampleRate: 1.0,
- },
+ // profilesSampleRate is relative to tracesSampleRate.
+ // Here, we'll capture profiles for 100% of transactions.
+ profilesSampleRate: 1.0,
});
```
diff --git a/docs/platforms/react-native/integrations/custom.mdx b/docs/platforms/react-native/integrations/custom.mdx
index b80f22829f18ef..121aa54046e5d8 100644
--- a/docs/platforms/react-native/integrations/custom.mdx
+++ b/docs/platforms/react-native/integrations/custom.mdx
@@ -1,7 +1,120 @@
---
title: Custom Integrations
-description: "Learn how to enable a custom integration."
-sidebar_order: 3
+sidebar_order: 200
+description: "Learn how you can enable a custom integration."
---
-
+In addition to the integrations that come with the SDK, you can also write custom integrations.
+
+Custom integration must conform to the [Integration interface](https://github.com/getsentry/sentry-javascript/blob/master/packages/types/src/integration.ts).
+
+A custom integration can be created and added to the SDK as follows:
+
+```javascript
+function myAwesomeIntegration() {
+ return {
+ name: "MyAwesomeIntegration",
+ setup(client) {
+ // Do something when the SDK is initialized
+ // The client that is being setup is passed to the hook
+ },
+ };
+}
+
+Sentry.init({
+ // ...
+ integrations: [myAwesomeIntegration()],
+});
+```
+
+All hooks on an integration are optional. The only required field is the `name`. You can use one or multiple of the following hooks in a custom integration:
+
+### `setup`
+
+The `setup` hook is called when the SDK is initialized. It receives the client instance as an argument.
+You should use this if you want to run some code on initialization.
+
+```javascript
+const integration = {
+ name: "MyAwesomeIntegration",
+ setup(client) {
+ setupCustomSentryListener(client);
+ },
+};
+```
+
+### `processEvent`
+
+This hook can be used to modify events before they are sent to Sentry. It receives the event as an argument and should return the modified event. The hook also receives a hint object that may hold additional event metadata, and the client that is sending the event. You can also return `null` to drop the event from being sent.
+
+```javascript
+const integration = {
+ name: "MyAwesomeIntegration",
+ processEvent(event, hint, client) {
+ event.extra = {
+ ...event.extra,
+ myCustomTag: "value",
+ };
+ // Return the modified event,
+ // or return `null` to drop the event
+ return event;
+ },
+};
+```
+
+You can also return a promise that resolves with an event or `null`. However, this is not recommended and should be avoided wherever possible, because it can delay event sending.
+
+### `preprocessEvent`
+
+This hook is similar to `processEvent`, but it is called before the event is passed to any other `processEvent` hook. It can be used in places where the order of processing is important.
+
+In most cases, you should just use `processEvent`. Only use `preprocessEvent` if you need to ensure that your hook is called before any other `processEvent` hook.
+
+Similar to `processEvent`, this hooks receives the event, hint, and client as arguments. However, this hook does not allow to return a modified event or `null` to drop the event - instead, you can only mutate the passed in event in this hook:
+
+```javascript
+const integration = {
+ name: "MyAwesomeIntegration",
+ preprocessEvent(event, hint, client) {
+ event.extra = {
+ ...event.extra,
+ myCustomTag: "value",
+ };
+ // Nothing to return, just mutate the event
+ },
+};
+```
+
+### `setupOnce`
+
+This hook is similar to `setup`, but it is only run once, even if the SDK is re-initialized. It does not receive any arguments.
+You should probably not use this, but use `setup` instead. The only reason to use `setupOnce` is e.g. when you may be calling `Sentry.init()` multiple times and you want to ensure a certain piece of code is only run once.
+
+```javascript
+const integration = {
+ name: "MyAwesomeIntegration",
+ setupOnce() {
+ wrapLibrary();
+ },
+};
+```
+
+### `afterAllSetup`
+
+This hook is triggered after `setupOnce()` and `setup()` have been called for all integrations.
+You can use it if it is important that all other integrations have been run before.
+
+In most cases, you should not need to use this hook, and should use `setup` instead.
+
+The hook receives the `client` that is being set up as the first argument.
+
+```javascript
+const integration = {
+ name: "MyAwesomeIntegration",
+ afterAllSetup(client) {
+ // We can be sure that all other integrations
+ // have run their `setup` and `setupOnce` hooks now
+ startSomeThing(client);
+ },
+};
+```
diff --git a/docs/platforms/react-native/integrations/default.mdx b/docs/platforms/react-native/integrations/default.mdx
index 791a6ba0395908..36b3a856597134 100644
--- a/docs/platforms/react-native/integrations/default.mdx
+++ b/docs/platforms/react-native/integrations/default.mdx
@@ -9,7 +9,7 @@ The below system integrations are part of the standard library or the interprete
### InboundFilters
-_Import name: `Sentry.Integrations.InboundFilters`_
+_Import name: `Sentry.inboundFiltersIntegration`_
This integration allows you to ignore specific errors based on the type,
message, or URLs in a given exception.
@@ -22,23 +22,13 @@ only work for captured exceptions, not raw message events.
### FunctionToString
-_Import name: `Sentry.Integrations.FunctionToString`_
+_Import name: `Sentry.functionToStringIntegration`_
This integration allows the SDK to provide original functions and method names, even when those functions or methods are wrapped by our error or breadcrumb handlers.
-
-
-### TryCatch
-
-_Import name: `Sentry.Integrations.TryCatch`_
-
-This integration wraps native time and events APIs (`setTimeout`, `setInterval`, `requestAnimationFrame`, `addEventListener/removeEventListener`) in `try/catch` blocks to handle async exceptions.
-
-
-
### Breadcrumbs
-_Import name: `Sentry.Integrations.Breadcrumbs`_
+_Import name: `Sentry.breadcrumbsIntegration`_
This integration wraps native APIs to capture breadcrumbs. By default, the Sentry SDK wraps all APIs.
@@ -71,33 +61,12 @@ Available options:
}
```
-
-
-### GlobalHandlers
+### NativeLinkedErrors
-_Import name: `Sentry.Integrations.GlobalHandlers`_
-
-This integration attaches global handlers to capture uncaught exceptions and unhandled rejections.
-
-Available options:
-
-```javascript
-{
- onerror: boolean;
- onunhandledrejection: boolean;
-}
-```
-
-
-
-### LinkedErrors
-
-_Import name: `Sentry.Integrations.LinkedErrors`_
+_Import name: `Sentry.nativeLinkedErrorsIntegration`_
This integration allows you to configure linked errors which are recursively read up to a specified limit. A lookup by a specific key on the captured Error object is then performed. By default, the integration records up to five errors and the key used for recursion is `"cause"`.
-This integration also enhances captured error events with data from an [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) where applicable, by recursively iterating over the `errors` property on Error objects.
-
Available options:
```javascript
@@ -109,75 +78,42 @@ Available options:
Here's a code example of how this could be implemented:
-
+```javascript
+
}>
@@ -26,7 +26,7 @@ The Sentry Error Boundary is also available as a higher-order component.
```javascript
import React from "react";
-import * as Sentry from "@sentry/react";
+import * as Sentry from "@sentry/react-native";
Sentry.withErrorBoundary(Example, { fallback:
an error has occurred
});
```
@@ -41,7 +41,7 @@ In the example below, when the `` component hits an error, the `
+The Sentry SDK uses integrations to hook into the functionality of popular libraries to automatically instrument your application and give you the best data out of the box.
+
+Integrations automatically add error instrumentation, performance instrumentation, and/or extra context information to your application. Some are enabled by default, but you can disable them or modify their settings. Other can be added to extend the default functionality of the SDK.
+
+## Adding an Integration
+
+You can add additional integrations in your `init` call:
+
+```javascript
+import * as Sentry from "@sentry/react-native";
+
+Sentry.init({
+ dsn: "___PUBLIC_DSN___",
+ integrations: [Sentry.dedupeIntegration()],
+});
+```
+
+Alternatively, you can add integrations via `Sentry.addIntegration()`.
+This is useful if you only want to enable an integration in a specific environment or if you want to load an integration later.
+For all other cases, we recommend you use the `integrations` option.
+
+```javascript
+import * as Sentry from "@sentry/react-native";
+
+Sentry.init({
+ integrations: [],
+});
+
+Sentry.addIntegration(Sentry.dedupeIntegration());
+```
+
+### HttpClient
+
+_(New in version 5.3.0)_
+
+_Import name: `Sentry.httpContextIntegration`_
+
+This integration captures errors on failed requests from Fetch and XHR and attaches request and response information.
+
+By default, error events don't contain header or cookie data. You can change this behavior by setting the `sendDefaultPii` option to `true`.
+
+```javascript {tabTitle:npm}
+import * as Sentry from "@sentry/react-native";
+
+Sentry.init({
+ dsn: "___PUBLIC_DSN___",
+ integrations: [Sentry.httpClientIntegration()]
+
+ // This option is required for capturing headers and cookies.
+ sendDefaultPii: true,
+});
+```
+
+
+
+Due to the limitations of both the Fetch and XHR API, the cookie and header collection for both requests and responses is based on best effort. Certain headers may be missing in the event created by the integration.
+
+
+
+### RewriteFrames
+
+_Import name: `Sentry.rewriteFramesIntegration`_
+
+This integration allows you to apply a transformation to each frame of the stack trace. In the streamlined scenario, it can be used to change the name of the file frame it originates from, or it can be fed with an iterated function to apply any arbitrary transformation.
+
+On Windows machines, you have to use Unix paths and skip the volume letter in the `root` option to enable it. For example, `C:\\Program Files\\Apache\\www` won’t work, however, `/Program Files/Apache/www` will.
+
+```javascript
+import * as Sentry from "@sentry/react-native";
+
+Sentry.init({
+ dsn: "___PUBLIC_DSN___",
+ integrations: [Sentry.rewriteFramesIntegration(
+ {
+ // root path that will be stripped from the current frame's filename by the default iteratee if the filename is an absolute path
+ root: string;
+
+ // a custom prefix that will be used by the default iteratee (default: `app://`)
+ prefix: string;
+
+ // function that takes the frame, applies a transformation, and returns it
+ iteratee: (frame) => frame;
+ }
+ )],
+});
+```
+
+#### Usage Examples
+
+For example, if the full path to your file is `bundles/bundle1.js`:
+
+| Usage | Path in Stack Trace | Description |
+| -------------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
+| `RewriteFrames()` | `app:///bundle1.js` | The default behavior is to replace the absolute path, minus the filename, and add the default prefix (`app:///`). |
+| `RewriteFrames({root: '/bundles'})` | `app:///bundle1.js` | The `root` is defined as `/bundles`. Only that part is trimmed from the beginning of the path. |
+| `RewriteFrames({iteratee: () => {} })` | `app:///bundle.js` | The number at the end of a bundle can be a file hash. This is common in Expo apps. You can remove it in the `iteratee` callback. |
diff --git a/docs/platforms/react-native/tracing/index.mdx b/docs/platforms/react-native/tracing/index.mdx
index 2f2fbb58770ed1..42a3e094c2c4a1 100644
--- a/docs/platforms/react-native/tracing/index.mdx
+++ b/docs/platforms/react-native/tracing/index.mdx
@@ -6,10 +6,6 @@ sidebar_order: 4000
With [tracing](/product/performance/), Sentry tracks your software performance, measuring metrics like throughput and latency, and displaying the impact of errors across multiple systems. Sentry captures distributed traces consisting of transactions and spans, which measure individual services and individual operations within those services. Learn more about our model in [Distributed Tracing](/product/sentry-basics/tracing/distributed-tracing/).
-## Enable Tracing
-
-
-
## Configure
First, enable tracing and configure the sample rate for transactions. Set the sample rate for your transactions by either:
diff --git a/docs/platforms/react-native/tracing/instrumentation/automatic-instrumentation.mdx b/docs/platforms/react-native/tracing/instrumentation/automatic-instrumentation.mdx
index 3d4b21c104f457..607d6003ea9d5e 100644
--- a/docs/platforms/react-native/tracing/instrumentation/automatic-instrumentation.mdx
+++ b/docs/platforms/react-native/tracing/instrumentation/automatic-instrumentation.mdx
@@ -28,13 +28,14 @@ When no routing instrumentation is used, a transaction for `App Start` is automa
We currently provide three routing instrumentations out of the box to instrument route changes for:
+- [Expo Router](/platforms/react-native/tracing/instrumentation/expo-router/)
- [React Navigation](/platforms/react-native/tracing/instrumentation/react-navigation/)
-- [React Navigation V4 and prior](/platforms/react-native/tracing/instrumentation/react-navigation-v4/)
- [React Native Navigation](/platforms/react-native/tracing/instrumentation/react-native-navigation/)
-- [Expo Router](/platforms/react-native/tracing/instrumentation/expo-router/)
-- [Custom Instrumentation](/platforms/react-native/tracing/instrumentation/custom-navigation/), implement automatic navigation instrumentation for a custom library.
-If you have a custom routing instrumentation or use a routing library we don't yet support, you can use the [bare bones routing instrumentation](#bare-bones) or [create your own](#custom-instrumentation) by extending it.
+### Additional Instrumentation
+
+- [Custom Navigation](/platforms/react-native/tracing/instrumentation/custom-navigation/) to add custom navigation library integration
+- [Custom Instrumentation](/platforms/react-native/tracing/instrumentation/custom-navigation/) to add custom performance data to your application
## Features
@@ -52,12 +53,6 @@ If you don't [wrap your root component with Sentry](#wrap-your-root-component),
The SDK differentiates between a cold and a warm start, but doesn't track hot starts or resumes. The measurements are available under `measurements.app_start_warm` and `measurements.app_start_cold`.
-
-
-For SDKs from version `4.4.0` to `5.0.0` the app start measurements are available under `measurements.app.start.warm` and `measurements.app.start.cold` as custom measurements.
-
-
-
Cold and warm start are Mobile Vitals, which you can learn about in the [full documentation](/product/insights/mobile-vitals).
### Slow and Frozen Frames
@@ -111,90 +106,72 @@ import * as Sentry from "@sentry/react-native";
Sentry.init({
dsn: "___PUBLIC_DSN___",
- integrations: [new Sentry.ReactNativeTracing()],
+ integrations: [Sentry.reactNativeTracingIntegration()],
});
```
-For all possible options, see [ReactNativeTracingOptions](https://github.com/getsentry/sentry-react-native/blob/211ec081b6bf8d7d29541afe9d800040f61e3c4e/src/js/tracing/reactnativetracing.ts#L23).
+### tracePropagationTargets
+
+The default value of `tracePropagationTargets` is `['localhost', /^\//]`. The React Native 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 the domain there to propagate the `sentry-trace` header to the backend services, which is required to link transactions together as part of a single trace. **The `tracePropagationTargets` option matches against the entire request URL, not just the domain. Using stricter regex to match certain parts of the URL ensures that requests do not unnecessarily have the `sentry-trace` header attached.**
-### beforeNavigate
+
+
+You will need to configure your web server CORS to allow the `sentry-trace` header. The configuration might look like `"Access-Control-Allow-Headers: sentry-trace"`, but the configuration depends on your setup. If you do not allow the `sentry-trace` header, the request might be blocked.
-You can use `beforeNavigate` to modify the transaction from routing instrumentation before the transaction is created. If you prefer not to send the transaction, set `sampled = false`.
+### beforeStartSpan
+`beforeStartSpan` is called at the start of every `pageload` or `navigation` span, and is passed an object containing data about the span which will be started. With `beforeStartSpan` you can modify that data.
```javascript
Sentry.init({
dsn: "___PUBLIC_DSN___",
integrations: [
- new Sentry.ReactNativeTracing({
- routingInstrumentation,
- beforeNavigate: (context) => {
- // Decide to not send a transaction by setting sampled = false
- if (context.data.route.name === "Do Not Send") {
- context.sampled = false;
- }
-
- // Modify the transaction context
- context.name = context.name.toUpperCase();
- context.tags = {
- ...context.tags,
- customTag: "value",
+ Sentry.reactNativeTracingIntegration({
+ beforeStartSpan: (context) => {
+ return {
+ ...context,
+ attributes: {
+ ...context.attributes,
+ "custom": "value",
+ },
};
-
- return context;
},
}),
],
});
```
-If you use our routing instrumentation for **React Navigation**, the route data is set on the transaction context passed to `beforeNavigate`. This has the type:
+### shouldCreateSpanForRequest
+
+This function can be used to filter out unwanted spans such as XHRs running
+health checks or something similar. If this function isn't specified, spans
+will be created for all requests.
-```typescript
-type ReactNavigationTransactionContext = {
+```javascript
+Sentry.init({
// ...
- data: {
- route: {
- name: string;
- key: string;
- params: {
- [key: string]: any;
- };
- /** Will be true if this is not the first time this screen with this key has been seen before. */
- hasBeenSeen: boolean;
- };
- previousRoute: {
- name: string;
- key: string;
- params: {
- [key: string]: any;
- };
- } | null;
- };
-};
+ integrations: [
+ Sentry.reactNativeTracingIntegration({
+ shouldCreateSpanForRequest: (url) => {
+ // Do not create spans for outgoing requests to a `/health/` endpoint
+ return !url.match(/\/health\/?$/);
+ },
+ }),
+ ],
+});
```
-If you use **Typescript**, you can type your `beforeNavigate` function with `Sentry.ReactNavigationTransactionContext`.
-
-### tracePropagationTargets
-
-The default value of `tracePropagationTargets` is `['localhost', /^\//]`. The React Native 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 the domain there to propagate the `sentry-trace` header to the backend services, which is required to link transactions together as part of a single trace. **The `tracePropagationTargets` option matches against the entire request URL, not just the domain. Using stricter regex to match certain parts of the URL ensures that requests do not unnecessarily have the `sentry-trace` header attached.**
-
-
-
-You will need to configure your web server CORS to allow the `sentry-trace` header. The configuration might look like `"Access-Control-Allow-Headers: sentry-trace"`, but the configuration depends on your setup. If you do not allow the `sentry-trace` header, the request might be blocked.
-
-### shouldCreateSpanForRequest
+### idleTimeoutMs
-This function can be used to filter out unwanted spans, such as XHR's running health checks or something similar. By default, `shouldCreateSpanForRequest` already filters out everything except what was defined in `tracePropagationTargets`.
+The idle time, measured in ms, to wait until the transaction will be finished, if there are no unfinished spans. The transaction will use the end timestamp of the last finished span as the endtime for the transaction.
-
+The default is `1_000`.
-### maxTransactionDuration
+### finalTimeoutMs
-The maximum duration of a transaction, measured in seconds, before it will be marked as "deadline_exceeded". If you never want transactions marked that way, set `maxTransactionDuration` to 0.
+The maximum duration of the transaction, measured in ms. If the transaction duration hits the `finalTimeout` value, it will be finished.
-The default is `600`.
+The default is `60_0000`.
## Recipes
diff --git a/docs/platforms/react-native/tracing/instrumentation/custom-instrumentation.mdx b/docs/platforms/react-native/tracing/instrumentation/custom-instrumentation.mdx
index 4f9bf0322b7058..27f175c2801928 100644
--- a/docs/platforms/react-native/tracing/instrumentation/custom-instrumentation.mdx
+++ b/docs/platforms/react-native/tracing/instrumentation/custom-instrumentation.mdx
@@ -14,23 +14,209 @@ To add custom performance data to your application, you need to add custom instr
To get started, import the SDK.
-
+```javascript
+import * as Sentry from "@sentry/react-native";
+```
-
+There are three key functions for creating spans:
-## Start Span
+- [startSpan](#starting-an-active-span-startspan): Creates a new span that is active, and which is automatically ended. You'll likely want to use this function.
+- [startSpanManual](#starting-an-active-span-with-manual-end-startspanmanual): Creates a new span that is active, which has to be ended manually.
+- [startInactiveSpan](#starting-inactive-spans-startinactivespan): Creates a new span that is inactive, which has to be ended manually.
-By default, spans you create are considered active, which means they are put on the Sentry scope. This allows child spans and Sentry errors to be associated with that span. This is the recommended way to create spans.
+## Active vs. Inactive Spans
+
+When a new span is started, it will automatically be started as a child of the currently active span, if there is one. This means that if a span is started as an **active span**, any spans that are created inside of the callback where the span is active will be children of that span. Additionally, errors will be tied to the currently active span, if there is one.
+
+In contrast, **inactive spans** will never have children automatically associated with them. This is useful if you do not care about capturing child activity.
+
+A key constraint for active spans is that they can only be made active inside of a callback. This constraint exists because otherwise it becomes impossible to associate spans with the correct parent span when working with asynchronous code.
+
+In places where you are not able to wrap executing code in a callback (e.g. when working with hooks or similar) you have to work with inactive spans, and can combine this with [withActiveSpan](#withactivespan) to manually associate child spans with the correct parent span.
+
+## Span Hierarchy
+
+In browser and mobile environments, spans are by default collected in a flat hierarchy where every span is the direct child of the root span.
+
+The key reason for keeping a flat hierarchy is because it's impossible to reliably keep track of the active span across asynchronous boundaries. This means that if multiple asynchronous operations are started in parallel, it is not possible to determine which span is the parent of which child span. Imagine the following example:
+
+```javascript
+Sentry.startSpan({ name: "span 1" }, async () => {
+ await fetch("https://example.com/1");
+ await fetch("https://example.com/2");
+ await fetch("https://example.com/3");
+});
+
+Sentry.startSpan({ name: "span 2" }, async () => {
+ await fetch("https://example.com/4");
+ await fetch("https://example.com/5");
+ await fetch("https://example.com/6");
+});
+```
+
+In the browser, there would be no way to know that `span 1` is only active inside of its callback, while `span 2` is active in the other callback. Because of this, in reality, _all_ fetch spans would become children of `span 2`. This is misleading and confusing, which is why by default in the browser, **all spans will become children of the root span** (which is usually the pageload or navigation span). This means that you will always have a flat hierarchy of spans.
+
+This is a tradeoff that we have made to ensure that the data that is captured is accurate and reliable. If you need to capture a more complex hierarchy of spans, you can opt-out of this behavior by setting `parentSpanIsAlwaysRootSpan: false`:
+
+```javascript
+Sentry.init({
+ parentSpanIsAlwaysRootSpan: false,
+});
+```
+
+This will revert to use the full hierarchy behavior, where spans are children of the currently active span. However, this may lead to incorrect data in the case of multiple parallel asynchronous operations - it is up to you to ensure there are no multiple parallel asynchronous operations that start spans in this case.
+
+## Span Starting Options
+
+The following options can be used for all span starting functions:
+
+| Option | Type | Description |
+| ------------------ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
+| `name` | `string` | The name of the span. |
+| `op` | `string` | The operation of the span. |
+| `startTime` | `number` | The start time of the span. |
+| `attributes` | `Record` | Attributes to attach to the span. |
+| `parentSpan` | `Span` | If set, make the span a child of the specified span. Otherwise, the span will be a child of the currently active span. |
+| `onlyIfParent` | `boolean` | If true, ignore the span if there is no active parent span. |
+| `forceTransaction` | `boolean` | If true, ensure this span shows up as transaction in the Sentry UI. |
+
+Only `name` is required, all other options are optional.
+
+## Starting an Active Span (`startSpan`)
+
+For most scenarios, we recommend to start active spans with `Sentry.startSpan()`. This will start a new span that is active in the provided callback, and will automatically end the span when the callback is done. The callback can be synchronous, or asynchronous (a promise). In the case of an asynchronous callback, the span will be ended when the promise is resolved or rejected. If the provided callback errors or rejects, the span will be marked as failed.
-## Start Inactive Spans
+## Starting an Active Span with Manual End (`startSpanManual`)
+
+Sometimes, you do not want the span to be ended automatically when the callback is done. In this case, you can use `Sentry.startSpanManual()`. This will start a new span that is active in the provided callback, but will not be automatically ended when the callback is done. You have to manually end the span by calling `span.end()`.
+
+
-To add spans that aren't active, you can create independent spans. This is useful for when you have work that is grouped together under a single parent span, but is independent from the current active span. However, in most cases you'll want to create and use the start span API from above.
+## Starting Inactive Spans (`startInactiveSpan`)
+
+To add spans that aren't active, you can create independent spans. This is useful when you have work that is grouped together under a single parent span, but is independent from the currently active span. However, in most cases you'll want to create and use the [startSpan](#starting-an-active-span-startspan) API from above.
-## Adding Span operations
+## Starting Spans as Children of a Specific Span
+
+By default, any span that is started will be the child of the currently active span. If you want to have a different behavior, you can force spans to be the children of a specific span with the `parentSpan` option:
+
+```js
+const parentSpan = Sentry.startInactiveSpan({ name: "Parent Span" });
+const childSpan = Sentry.startInactiveSpan({ name: "Child Span", parentSpan });
+
+childSpan.end();
+parentSpan.end();
+```
+
+This option is also available for `startSpan` and `startSpanManual`.
+
+## Utilities to work with Spans
+
+We expose some helpful utilities that can help you with custom instrumentation.
+
+### `getActiveSpan`
+
+Returns the currently active span.
+
+```javascript
+const activeSpan = Sentry.getActiveSpan();
+```
+
+### `getRootSpan`
+
+Returns the root span of a given span. If the span is already the root span, it will return the span itself.
+
+```javascript
+const activeSpan = Sentry.getActiveSpan();
+const rootSpan = activeSpan ? Sentry.getRootSpan(activeSpan) : undefined;
+```
+
+### `withActiveSpan`
+
+This method allows you to make a span active for the duration of a callback. You can use this in combination with `startInactiveSpan` to manually associate child spans with the correct parent span:
+
+```javascript
+const span = Sentry.startInactiveSpan({ name: "Parent Span" });
+
+Sentry.withActiveSpan(span, () => {
+ // `span` is now active, any other spans will be children of it
+ Sentry.startSpan({ name: "Child Span" }, () => {
+ // Do something
+ });
+});
+```
+
+You can also pass `null` to `withActiveSpan` to ensure a span will not have any parent:
+
+```javascript
+Sentry.withActiveSpan(null, () => {
+ // This will not have a parent span, no matter what
+ Sentry.startSpan({ name: "Parent Span" }, () => {
+ // Do something
+ });
+});
+```
+
+Alternatively you can also use the `parentSpan` option to achieve the same:
+
+```javascript
+const span = Sentry.startInactiveSpan({ name: "Parent Span" });
+const childSpan = Sentry.startInactiveSpan({
+ name: "Child Span",
+ parentSpan: span,
+});
+```
+
+### `suppressTracing`
+
+Suppress the creation of sampled spans for the duration of the callback. This is useful when you want to prevent certain spans from being captured. For example, if you do not want to create spans for a given fetch request, you can do:
+
+```javascript
+Sentry.suppressTracing(() => {
+ fetch("https://example.com");
+});
+```
+
+## Improving Span Data
+
+### Adding Span Attributes
+
+You can capture span attributes along with your spans. Span attributes can be of type `string`, `number` or `boolean`, as well as (non-mixed) arrays of these types. You can specify attributes when starting a span:
+
+```javascript
+Sentry.startSpan(
+ {
+ attributes: {
+ attr1: "value1",
+ attr2: 42,
+ attr3: true,
+ },
+ },
+ () => {
+ // Do something
+ }
+);
+```
+
+Or you can also add attributes to an existing span:
+
+```javascript
+const span = Sentry.getActiveSpan();
+if (span) {
+ span.setAttribute("attr1", "value1");
+ // Or set multiple attributes at once:
+ span.setAttributes({
+ attr2: 42,
+ attr3: true,
+ });
+}
+```
+
+### Adding Span Operations ("op")
Spans can have an operation associated with them, which help activate Sentry identify additional context about the span. For example database related spans have the `db` span operation associated with them. The Sentry product offers additional controls, visualizations and filters for spans with known operations.
@@ -38,10 +224,18 @@ Sentry maintains a [list of well known span operations](https://develop.sentry.d
-## Start Transaction
+### Updating the Span Name
+
+You can update the name of a span at any time:
-The root span (the span that is the parent of all other spans) is known as a **transaction** in Sentry. Transactions can be accessed and created separately if you need more control over your timing data or if you use a version of the SDK that doesn't support the top-level span APIs.
+```javascript
+const span = Sentry.getActiveSpan();
+if (span) {
+ span.updateName("New Name");
+}
+```
-
+Please note that in certain scenarios, the span name will be overwritten by the SDK. This is the case for spans with any of the following attribute combinations:
-
+* Spans with `http.method` or `http.request.method` attributes will automatically have their name set to the method + the URL path
+* Spans with `db.system` attributes will automatically have their name set to the system + the statement
diff --git a/docs/platforms/react-native/tracing/instrumentation/react-navigation-v4.mdx b/docs/platforms/react-native/tracing/instrumentation/react-navigation-v4.mdx
deleted file mode 100644
index 7507a8f4849d50..00000000000000
--- a/docs/platforms/react-native/tracing/instrumentation/react-navigation-v4.mdx
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: React Navigation V4
-description: "Learn how to use Sentry's React Navigation Legacy instrumentation."
-sidebar_order: 51
----
-
-Sentry's React Native SDK package ships with instrumentation for React Navigation V4 and older. This allows you to see the performance of your navigation transitions and the errors that occur during them. This page will guide you through setting up the instrumentation and configuring it to your needs.
-
-## Initialization
-
-The code snippet below shows how to initialize the instrumentation.
-
-```jsx {tabTitle: Functional Components}
-// Construct a new instrumentation instance. This is needed to communicate between the integration and React
-const routingInstrumentation = new Sentry.ReactNavigationV4Instrumentation();
-
-Sentry.init({
- ...
- integrations: [
- new Sentry.ReactNativeTracing({
- // Pass instrumentation to be used as `routingInstrumentation`
- routingInstrumentation,
- ...
- }),
- ],
-})
-
-// Functional Component Example
-const App = () => {
- // Create a ref for the navigation container
- const appContainer = React.useRef();
-
- // Register the navigation container with the instrumentation
- React.useEffect(() => {
- routingInstrumentation.registerAppContainer(appContainer);
- }, []);
-
- return (
- // Connect the ref to the navigation container
-
- );
-};
-```
-
-```jsx {tabTitle: Class Components}
-// Construct a new instrumentation instance. This is needed to communicate between the integration and React
-const routingInstrumentation = new Sentry.ReactNavigationV4Instrumentation();
-
-Sentry.init({
- ...
- integrations: [
- new Sentry.ReactNativeTracing({
- // Pass instrumentation to be used as `routingInstrumentation`
- routingInstrumentation,
- ...
- }),
- ],
-})
-
-class App extends React.Component {
- // Create a ref for the navigation container
- appContainer = React.createRef();
-
- componentDidMount() {
- // Register the navigation container with the instrumentation
- routingInstrumentation.registerAppContainer(this.appContainer);
- }
-
- render() {
- return (
- // Connect the ref to the navigation container
-
- )
- }
-}
-```
-
-## Options
-
-You can configure the instrumentation by passing an options object to the constructor:
-
-```javascript
-new Sentry.ReactNavigationV4Instrumentation({
- routeChangeTimeoutMs: 1000, // default: 1000
-});
-```
-
-### routeChangeTimeoutMs
-
-This option specifies how long the instrumentation will wait for the **initial** route to mount after a change has been initiated before the transaction is discarded. The default value is 1000ms.
-
-## Notes
-
-- This instrumentation supports React Navigation version 4 and older. If you use React Navigation version 5 and newer, see the [instrumentation for React Navigation](/platforms/react-native/tracing/instrumentation/react-navigation/).
-
-- The instrumentation creates a transaction on every route change including `goBack` navigations.
diff --git a/includes/platforms/configuration/integrations/plugin.mdx b/includes/platforms/configuration/integrations/plugin.mdx
deleted file mode 100644
index 6cf046797e9884..00000000000000
--- a/includes/platforms/configuration/integrations/plugin.mdx
+++ /dev/null
@@ -1,134 +0,0 @@
-The below pluggable integrations are snippets of code that augment functionality for specific applications and/or frameworks. Read on to understand what they do and how to enable them.
-
-## How to Enable
-
-Install the `@sentry/integrations` package and provide a new instance with your config to the `integrations` option. Include the plugin after the SDK has been loaded.
-
-For example:
-
-
-
-Alternatively, you can add integrations lazily via `Sentry.addIntegration()`.
-This is useful if you only want to enable an integration in a specific environment or if you want to lazy-load an integration.
-For all other cases, we recommend you use the `integrations` option.
-
-
-
-
-
-
-
-### ExtraErrorData
-
-_Import name: `Sentry.Integrations.ExtraErrorData`_
-
-This integration extracts all non-native attributes from the `error` object and attaches them to the event as `extra` data. If the error object has a `.toJSON()` method, the `ExtraErrorData` integration will run it to extract additional information.
-
-Available options:
-
-
-
-
-
-### CaptureConsole
-
-_Import name: `Sentry.Integrations.CaptureConsole`_
-
-This integration captures all `Console API` calls and redirects them to Sentry using the SDK's `captureMessage` or `captureException` call, depending on the log level. It then re-triggers to preserve default native behavior.
-
-
-
-
-
-By default React [logs all errors to the console](https://github.com/facebook/react/blob/493f72b0a7111b601c16b8ad8bc2649d82c184a0/packages/react-reconciler/src/ReactFiberErrorLogger.js#L85), even if you are using an React error boundary. This means that Sentry will capture the error through the `CaptureConsole` integration and not through the error boundary. We recommend disabling logging the `error` level if using React error boundaries and the `CaptureConsole` integration.
-
-
-
-
-
-
-
-### Debug
-
-_Import name: `Sentry.Integrations.Debug`_
-
-This integration allows you to inspect the contents of a processed event and `hint` object that gets passed to `beforeSend` or `beforeSendTransaction`. It will _always_ run as the last integration, no matter when it was registered.
-
-Note that this is different than setting `debug: true` in your `Sentry.init` options, which will enable debug logging in the console.
-
-Available options:
-
-
-
-
-
-### HttpClient
-
-
-
-_(New in version 7.30.0)_
-
-
-
-
-
-_(New in version 5.3.0)_
-
-
-
-_Import name: `Sentry.Integrations.HttpClient`_
-
-This integration captures errors on failed requests from Fetch and XHR and attaches request and response information.
-
-By default, error events don't contain header or cookie data. You can change this behavior by setting the `sendDefaultPii` option to `true`.
-
-Available options:
-
-
-
-
-
-Due to the limitations of both the Fetch and XHR API, the cookie and header collection for both requests and responses is based on best effort. Certain headers may be missing in the event created by the integration.
-
-
-
-### RewriteFrames
-
-_Import name: `Sentry.Integrations.RewriteFrames`_
-
-This integration allows you to apply a transformation to each frame of the stack trace. In the streamlined scenario, it can be used to change the name of the file frame it originates from, or it can be fed with an iterated function to apply any arbitrary transformation.
-
-On Windows machines, you have to use Unix paths and skip the volume letter in the `root` option to enable it. For example, `C:\\Program Files\\Apache\\www` won’t work, however, `/Program Files/Apache/www` will.
-
-Available options:
-
-
-
-
-
-### ReportingObserver
-
-_Import name: `Sentry.Integrations.ReportingObserver`_
-
-This integration hooks into the ReportingObserver API and sends captured events through to Sentry. It can be configured to handle only specific issue types.
-
-Available options:
-
-
-
-
-
-
-
-### ContextLines
-
-_Import name: `Sentry.Integrations.ContextLines`_
-
-This integration adds source code from inline JavaScript of the current page's HTML (e.g. JS in `