diff --git a/docs/platforms/javascript/common/tracing/configure-sampling/index.mdx b/docs/platforms/javascript/common/tracing/configure-sampling/index.mdx
index 63f8a49fdd86d..0b002e5d7b501 100644
--- a/docs/platforms/javascript/common/tracing/configure-sampling/index.mdx
+++ b/docs/platforms/javascript/common/tracing/configure-sampling/index.mdx
@@ -6,6 +6,14 @@ sidebar_order: 30
Sentry's tracing functionality helps you monitor application performance by capturing distributed traces, attaching attributes, and span performance across your application. However, Capturing traces for every transaction can generate significant volumes of data. Sampling allows you to control the amount of spans that are sent to Sentry from your application.
+
+
+
+If you're using stream mode, sampling works the same way as described in this guide but applies to service spans instead of transactions. See New Spans for more information.
+
+
+
+
The JavaScript SDK provides two main options for controlling the sampling rate:
1. [Uniform Sample Rate](#uniform-sample-rate-tracessamplerate) (recommended)
@@ -62,39 +70,39 @@ tracesSampler: (samplingContext) => {
const { name, attributes, inheritOrSampleWith } = samplingContext;
// Sample all checkout transactions
- if (name.includes('/checkout') || attributes?.flow === 'checkout') {
+ if (name.includes("/checkout") || attributes?.flow === "checkout") {
return 1.0;
}
// Sample 50% of login transactions
- if (name.includes('/login') || attributes?.flow === 'login') {
+ if (name.includes("/login") || attributes?.flow === "login") {
return 0.5;
}
// Sample 10% of everything else
return inheritOrSampleWith(0.1);
-}
+};
```
2. Handling Different Environments
```javascript
tracesSampler: (samplingContext) => {
- const { inheritOrSampleWith } = samplingContext;
+ const { inheritOrSampleWith } = samplingContext;
// Sample all transactions in development
- if (process.env.NODE_ENV === 'development') {
+ if (process.env.NODE_ENV === "development") {
return 1.0;
}
// Sample 5% in production
- if (process.env.NODE_ENV === 'production') {
+ if (process.env.NODE_ENV === "production") {
return 0.05;
}
// Sample 20% in staging
return inheritOrSampleWith(0.2);
-}
+};
```
3. Controlling Sampling Based on User or Transaction Properties
@@ -104,7 +112,7 @@ tracesSampler: (samplingContext) => {
const { attributes, inheritOrSampleWith } = samplingContext;
// Always sample for premium users
- if (attributes?.userTier === 'premium') {
+ if (attributes?.userTier === "premium") {
return 1.0;
}
@@ -114,13 +122,13 @@ tracesSampler: (samplingContext) => {
}
// Sample less for high-volume, low-value paths
- if (attributes?.path?.includes('/api/metrics')) {
+ if (attributes?.path?.includes("/api/metrics")) {
return 0.01;
}
// Default sampling rate
return inheritOrSampleWith(0.2);
-}
+};
```
## Sampling Decision Precedence
diff --git a/docs/platforms/javascript/common/tracing/instrumentation/automatic-instrumentation.mdx b/docs/platforms/javascript/common/tracing/instrumentation/automatic-instrumentation.mdx
index afff9b5e04d25..87cd7f9673c3a 100644
--- a/docs/platforms/javascript/common/tracing/instrumentation/automatic-instrumentation.mdx
+++ b/docs/platforms/javascript/common/tracing/instrumentation/automatic-instrumentation.mdx
@@ -14,17 +14,23 @@ Capturing spans requires that you first set up trac
+
+
+If you're using stream mode, sampling works the same way as described in this guide but applies to service spans instead of transactions. See New Spans for more information.
+
+
+
## What's Captured Automatically
Once you enable tracing, the SDK automatically captures performance data without additional code:
-| What | Description | Metrics |
-|------|-------------|---------|
-| **Page loads** | Full page load performance | LCP, CLS, TTFB |
-| **Navigations** | Client-side route changes | Duration, Web Vitals |
-| **HTTP requests** | All fetch/XHR calls | Duration, status, URL |
-| **User interactions** | Clicks, inputs that trigger work | INP (responsiveness) |
-| **Long tasks** | Main thread blocking > 50ms | Duration, attribution |
+| What | Description | Metrics |
+| --------------------- | -------------------------------- | --------------------- |
+| **Page loads** | Full page load performance | LCP, CLS, TTFB |
+| **Navigations** | Client-side route changes | Duration, Web Vitals |
+| **HTTP requests** | All fetch/XHR calls | Duration, status, URL |
+| **User interactions** | Clicks, inputs that trigger work | INP (responsiveness) |
+| **Long tasks** | Main thread blocking > 50ms | Duration, attribution |
@@ -236,7 +242,7 @@ Ignore specific resource span categories by their `op` (e.g., `resource.script`,
Sentry.init({
integrations: [
Sentry.browserTracingIntegration({
- ignoreResourceSpans: ['resource.css', 'resource.script'],
+ ignoreResourceSpans: ["resource.css", "resource.script"],
}),
],
});
@@ -252,7 +258,7 @@ Ignore spans created from `performance.mark()` and `performance.measure()`:
Sentry.init({
integrations: [
Sentry.browserTracingIntegration({
- ignorePerformanceApiSpans: ['myMeasurement', /myMark/],
+ ignorePerformanceApiSpans: ["myMeasurement", /myMark/],
}),
],
});
@@ -285,7 +291,11 @@ Sentry.init({
}),
],
tracesSampleRate: 1.0,
- tracePropagationTargets: ["localhost", /^\//, /^https:\/\/yourserver\.io\/api/],
+ tracePropagationTargets: [
+ "localhost",
+ /^\//,
+ /^https:\/\/yourserver\.io\/api/,
+ ],
});
```
diff --git a/docs/platforms/javascript/common/tracing/instrumentation/index.mdx b/docs/platforms/javascript/common/tracing/instrumentation/index.mdx
index cd2e104aaa24b..54f9d3e46ac77 100644
--- a/docs/platforms/javascript/common/tracing/instrumentation/index.mdx
+++ b/docs/platforms/javascript/common/tracing/instrumentation/index.mdx
@@ -74,15 +74,15 @@ This will revert to use the full hierarchy behavior, where spans are children of
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. |
+| 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. Not available in stream mode. Use `parentSpan: null` instead to ensure this span shows up as service span. |
Only `name` is required, all other options are optional.
@@ -102,41 +102,40 @@ Sometimes, you do not want the span to be ended automatically when the callback
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.
-
- ### Setting an inactive span active (browser only)
+### Setting an inactive span active (browser only)
-
+
- In browser environments, you might run into use cases, where the callback-based span APIs are not sufficient.
- In such cases (see example below), you can use `startInactiveSpan` to start an initially inactive span and then
- set it active until you manually end the span.
+In browser environments, you might run into use cases, where the callback-based span APIs are not sufficient.
+In such cases (see example below), you can use `startInactiveSpan` to start an initially inactive span and then
+set it active until you manually end the span.
- ```javascript
- let checkoutSpan;
+```javascript
+let checkoutSpan;
- on('startCheckout', () => {
- checkoutSpan = Sentry.startInactiveSpan({name: 'checkout-flow'});
- Sentry.setActiveSpanInBrowser(checkoutSpan);
- })
+on("startCheckout", () => {
+ checkoutSpan = Sentry.startInactiveSpan({ name: "checkout-flow" });
+ Sentry.setActiveSpanInBrowser(checkoutSpan);
+});
- doSomeWork();
+doSomeWork();
- on('endCheckout', () => {
- // Ending the span automatically removes it as the active span
- checkoutSpan.end();
- })
- ```
+on("endCheckout", () => {
+ // Ending the span automatically removes it as the active span
+ checkoutSpan.end();
+});
+```
- Using `startInactiveSpan` in combination with `setActiveSpanInBrowser` allows you to create an inactive span that can be made active until you manually end it. In contrast, [`startSpanManual`](#starting-an-active-span-with-manual-end-startspanmanual) allows you to end the span manually at any point, but it only remains active within the callback.
+Using `startInactiveSpan` in combination with `setActiveSpanInBrowser` allows you to create an inactive span that can be made active until you manually end it. In contrast, [`startSpanManual`](#starting-an-active-span-with-manual-end-startspanmanual) allows you to end the span manually at any point, but it only remains active within the callback.
- Note that `setActiveSpanInBrowser` is only available in browser environments! If you're running code in the server
- (for example for server-side rendering), make sure to guard this call to only run in the browser.
+Note that `setActiveSpanInBrowser` is only available in browser environments! If you're running code in the server
+(for example for server-side rendering), make sure to guard this call to only run in the browser.
@@ -205,9 +204,10 @@ if (span) {
### Adding attributes to all spans
-To add an attribute to all spans, use the `beforeSendSpan` callback:
+To add an attribute to all spans, use the `beforeSendSpan` callback.
+Note that the property names differ between transaction mode (the default) and stream mode:
-```javascript
+```javascript {tabTitle:Transaction Mode (Default)}
Sentry.init({
// dsn, ...
beforeSendSpan(span) {
@@ -221,6 +221,20 @@ Sentry.init({
});
```
+```javascript {tabTitle:Stream Mode}
+Sentry.init({
+ // dsn, ...
+ beforeSendSpan(span) {
+ span.attributes = {
+ ...span.attributes,
+ "environment.region": "us-west-2",
+ };
+
+ return span;
+ },
+});
+```
+
### Adding Span Operations ("op")
Spans can have an operation associated with them, which help 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.
diff --git a/docs/platforms/javascript/common/tracing/span-metrics/index.mdx b/docs/platforms/javascript/common/tracing/span-metrics/index.mdx
index 7917858b0d8f0..d634c8efe3861 100644
--- a/docs/platforms/javascript/common/tracing/span-metrics/index.mdx
+++ b/docs/platforms/javascript/common/tracing/span-metrics/index.mdx
@@ -70,9 +70,10 @@ For detailed examples of how to implement span metrics in common scenarios, see
## Adding Metrics to All Spans
-To consistently add metrics across all spans in your application, you can use the `beforeSendSpan` callback:
+To consistently add metrics across all spans in your application, you can use the `beforeSendSpan` callback.
+Note that the property names differ between transaction mode (the default) and stream mode:
-```javascript
+```javascript {tabTitle:Transaction Mode (Default)}
Sentry.init({
beforeSendSpan(span) {
span.data = {
@@ -86,6 +87,20 @@ Sentry.init({
});
```
+```javascript {tabTitle:Stream Mode}
+Sentry.init({
+ beforeSendSpan(span) {
+ span.attributes = {
+ ...span.attributes,
+ "app.version": "1.2.3",
+ "environment.region": "us-west-2",
+ };
+
+ return span;
+ },
+});
+```
+
For detailed examples of how to implement span metrics in common scenarios, see our Span Metrics Examples guide.
## Span Metrics vs. Measurements
diff --git a/docs/platforms/javascript/common/tracing/troubleshooting/index.mdx b/docs/platforms/javascript/common/tracing/troubleshooting/index.mdx
index d5b39e79a08b1..4e0e882539f4c 100644
--- a/docs/platforms/javascript/common/tracing/troubleshooting/index.mdx
+++ b/docs/platforms/javascript/common/tracing/troubleshooting/index.mdx
@@ -4,7 +4,7 @@ description: "Learn how to troubleshoot your tracing setup."
sidebar_order: 9000
---
-If you need help managing transactions, you can read more here. If you need additional help, you can ask on GitHub. Customers on a paid plan may also contact support.
+If you need help managing transactions or spans, start with this page. If you need additional help, you can ask on GitHub. Customers on a paid plan may also contact support.
## Group Transactions
@@ -27,3 +27,18 @@ For example, a 200+ character tag like this:
`https://empowerplant.io/api/0/projects/ep/setup_form/?user_id=314159265358979323846264338327&tracking_id=EasyAsABC123OrSimpleAsDoReMi&product_name=PlantToHumanTranslator&product_id=1618033988749894848`
+
+
+## Traces Miss Spans, High Memory Usage, or Data Loss After Crashes
+
+If you're hitting the 1,000-span limit, experiencing high memory usage from long-running processes, or losing span data when your process crashes, consider enabling stream mode. Stream mode sends spans to Sentry in batches as they finish rather than holding them in memory until the transaction ends.
+
+See New Spans for more information.
+
+## `ignoreSpans` Rules No Longer Work As Expected After Migrating to Stream Mode
+
+In stream mode, `ignoreSpans` is evaluated at span start rather than transaction end. If your current rules match on attributes that are added or updated while the span is active, they may no longer work as expected after migrating to stream mode.
+
+If you're auto-instrumenting and don't know what the initial name of a span is when it starts, enable SDK debug logging during development by setting `debug: true` when initializing the SDK.
+
+
diff --git a/docs/platforms/javascript/guides/node/tracing/instrumentation/automatic-instrumentation.mdx b/docs/platforms/javascript/guides/node/tracing/instrumentation/automatic-instrumentation.mdx
index 0d268743813c5..85a0049228878 100644
--- a/docs/platforms/javascript/guides/node/tracing/instrumentation/automatic-instrumentation.mdx
+++ b/docs/platforms/javascript/guides/node/tracing/instrumentation/automatic-instrumentation.mdx
@@ -1,6 +1,6 @@
---
title: Automatic Instrumentation
-description: "Learn what transactions are captured after tracing is enabled."
+description: "Learn what spans are captured after tracing is enabled."
---
diff --git a/platform-includes/distributed-tracing/custom-instrumentation/browser/javascript.mdx b/platform-includes/distributed-tracing/custom-instrumentation/browser/javascript.mdx
index 18024c01ac674..915f388d5635c 100644
--- a/platform-includes/distributed-tracing/custom-instrumentation/browser/javascript.mdx
+++ b/platform-includes/distributed-tracing/custom-instrumentation/browser/javascript.mdx
@@ -4,7 +4,7 @@ Distributed tracing will be set up automatically if you've
-When tracing is enabled, the Sentry SDK will not only create spans for pageloads and transactions but also propagate trace information to other systems. This allows you to connect multiple systems and see how they interact with each other.
+When tracing is enabled, the Sentry SDK will not only create spans for pageloads but also propagate trace information to other systems. This allows you to connect multiple systems and see how they interact with each other.
By default, outgoing HTTP requests will automatically be instrumented for you. For other cases where you may want to continue traces (for example when working with websockets), you can manually extract and inject tracing information.
@@ -54,7 +54,7 @@ To learn more about distributed tracing, see our stream mode) connected to that incoming backend trace.
Some Sentry backend SDKs provide a built-in way to inject these `` tags into rendered HTML. For example:
diff --git a/platform-includes/distributed-tracing/custom-instrumentation/javascript.mdx b/platform-includes/distributed-tracing/custom-instrumentation/javascript.mdx
index 1808848c520ea..425eb96b2d5ce 100644
--- a/platform-includes/distributed-tracing/custom-instrumentation/javascript.mdx
+++ b/platform-includes/distributed-tracing/custom-instrumentation/javascript.mdx
@@ -76,8 +76,8 @@ If you make outgoing requests from your project to other services, check if the
function sentryInterceptor(methodDescriptor, nextCall) {
// Extract Sentry trace headers from the incoming metadata
const metadata = nextCall.metadata.getMap();
- const sentryTrace = metadata['sentry-trace'];
- const baggage = metadata['baggage'];
+ const sentryTrace = metadata["sentry-trace"];
+ const baggage = metadata["baggage"];
return new grpc.ServerInterceptingCall(nextCall, {
start: (next) => {
@@ -87,12 +87,14 @@ function sentryInterceptor(methodDescriptor, nextCall) {
Sentry.startSpanManual(
{
name: methodDescriptor.path,
- op: 'grpc.server',
- forceTransaction: true, // Make this a transaction in the Sentry UI
+ op: "grpc.server",
+ // Make this a transaction in the Sentry UI.
+ // Not available in stream mode – use `parentSpan: null` to make this a service span.
+ forceTransaction: true,
attributes: {
- 'grpc.method': methodDescriptor.path,
- 'grpc.service': methodDescriptor.service.serviceName,
- 'grpc.status_code': grpc.status.OK,
+ "grpc.method": methodDescriptor.path,
+ "grpc.service": methodDescriptor.service.serviceName,
+ "grpc.status_code": grpc.status.OK,
},
},
(span) => {
@@ -108,21 +110,21 @@ function sentryInterceptor(methodDescriptor, nextCall) {
if (span) {
// Update status based on the gRPC result
if (status.code !== grpc.status.OK) {
- span.setStatus({ code: 2, message: 'error' });
- span.setAttribute('grpc.status_code', status.code);
- span.setAttribute('grpc.status_description', status.details);
+ span.setStatus({ code: 2, message: "error" });
+ span.setAttribute("grpc.status_code", status.code);
+ span.setAttribute("grpc.status_description", status.details);
}
// End the span when the call completes
span.end();
}
next(status);
- }
+ },
});
}
// Add the interceptor to your gRPC server
const server = new grpc.Server({
- interceptors: [sentryInterceptor]
+ interceptors: [sentryInterceptor],
});
// In your service implementation, use the active span
@@ -130,24 +132,27 @@ const serviceImplementation = {
myMethod: async (call, callback) => {
try {
const span = call.call?.nextCall?.sentrySpan;
-
+
// Use withActiveSpan to make the span active during service execution
await Sentry.withActiveSpan(span, async () => {
// Create child spans for operations within the service
- await Sentry.startSpan({ name: 'database.query', op: 'db' }, async (childSpan) => {
- // Database operations here
- const result = await database.query('SELECT * FROM table');
- childSpan.setAttribute('db.rows_affected', result.rowCount);
- });
-
- callback(null, { result: 'success' });
+ await Sentry.startSpan(
+ { name: "database.query", op: "db" },
+ async (childSpan) => {
+ // Database operations here
+ const result = await database.query("SELECT * FROM table");
+ childSpan.setAttribute("db.rows_affected", result.rowCount);
+ }
+ );
+
+ callback(null, { result: "success" });
});
} catch (error) {
// Capture the error with the current span as context
Sentry.captureException(error);
callback(error);
}
- }
+ },
};
```
@@ -163,22 +168,24 @@ function createGrpcClient() {
start: (callMetadata, listener, next) => {
// `callMetadata` is the metadata object for the outgoing gRPC call.
// We will add our Sentry tracing headers to this object.
-
+
// Get current trace information from Sentry
const traceData = Sentry.getTraceData();
-
+
// Add Sentry trace and baggage headers to the call's metadata
if (traceData) {
- callMetadata.set('sentry-trace', traceData['sentry-trace']);
- callMetadata.set('baggage', traceData['baggage']);
+ callMetadata.set("sentry-trace", traceData["sentry-trace"]);
+ callMetadata.set("baggage", traceData["baggage"]);
}
-
+
// Proceed with the call, now including the Sentry headers in its metadata
next(callMetadata, listener);
- }
+ },
});
- }]
+ },
+ ],
});
}
```
+
diff --git a/platform-includes/distributed-tracing/custom-instrumentation/server/javascript.mdx b/platform-includes/distributed-tracing/custom-instrumentation/server/javascript.mdx
index 7ee0106e1e1c6..fb25979f38905 100644
--- a/platform-includes/distributed-tracing/custom-instrumentation/server/javascript.mdx
+++ b/platform-includes/distributed-tracing/custom-instrumentation/server/javascript.mdx
@@ -45,7 +45,7 @@ http.createServer((request, response) => {
});
```
-In this example, we create a new transaction that is attached to the trace specified in the `sentry-trace` and `baggage` headers.
+In this example, we create a new transaction (or service span if you're using stream mode) that is attached to the trace specified in the `sentry-trace` and `baggage` headers.
### Injecting Tracing Information Into HTML
@@ -86,4 +86,4 @@ function renderHtml() {