Skip to content

feat(js): Document new performance APIs #7707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/platform-includes/performance/add-active-span/javascript.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
You can use the `Sentry.startActiveSpan` method to wrap a callback in a span to measure how long it will take. The span is automatically finished when the callback is finished. This will work with both sync and async callbacks.

```javascript
const result = Sentry.startActiveSpan({ name: "Important Function" }, () => {
return expensiveFunction();
});

const result = await Sentry.startActiveSpan(
{ name: "Important Function" },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: should we shop op as well here or do we consider this not necessary for custom instrumentation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

op is optional so I didn't include it. We need to go back and expand documentation on it, but that can happen later on.

async () => {
const res = Sentry.startActiveSpan({ name: "Child Span" }, () => {
return expensiveFunction();
});

return updateRes(res);
}
);

const result = Sentry.startActiveSpan(
{ name: "Important Function" },
(span) => {
// Can access the span to add data or set specific status.
// The span can be undefined if the span was not sampled or if performance monitoring is disabled.
span?.setData("foo", "bar");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Should we mention/explain when/why span is undefined? May not be entirely clear from the outside why this may be unset and why I need to guard here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, ill add a note

return expensiveFunction();
}
);
```

The span named `Important Function` will become the active span for the duration of the callback.
30 changes: 30 additions & 0 deletions src/platform-includes/performance/add-active-span/node.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
You can use the `Sentry.startActiveSpan` method to wrap a callback in a span to measure how long it will take. The span is automatically finished when the callback is finished. This will work with both sync and async callbacks.

```javascript
const result = Sentry.startActiveSpan({ name: "Important Function" }, () => {
return expensiveFunction();
});

const result = await Sentry.startActiveSpan(
{ name: "Important Function" },
async () => {
const res = Sentry.startActiveSpan({ name: "Child Span" }, () => {
return expensiveFunction();
});

return updateRes(res);
}
);

const result = Sentry.startActiveSpan(
{ name: "Important Function" },
(span) => {
// Can access the span to add data or set specific status.
// The span can be undefined if the span was not sampled or if performance monitoring is disabled.
span?.setData("foo", "bar");
return expensiveFunction();
}
);
```

The span named `Important Function` will become the active span for the duration of the callback.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
```javascript
const span1 = Sentry.startSpan({ name: "first-step" });

firstStep();

const span2 = Sentry.startSpan({ name: "second-step" });

secondStep();

const span3 = Sentry.startSpan({ name: "third-step" });

thirdStep();

span1.finish();
span2.finish();
span3.finish();
```
17 changes: 17 additions & 0 deletions src/platform-includes/performance/add-independent-span/node.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
```javascript
const span1 = Sentry.startSpan({ name: "first-step" });

firstStep();

const span2 = Sentry.startSpan({ name: "second-step" });

secondStep();

const span3 = Sentry.startSpan({ name: "third-step" });

thirdStep();

span1.finish();
span2.finish();
span3.finish();
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function shopCheckout() {
// If there's currently an unfinished transaction, it may be dropped
Sentry.getCurrentHub().configureScope((scope) => scope.setSpan(transaction));

// Assume this function makes an xhr/fetch call
// Assume this function makes a fetch call
const result = validateShoppingCartOnServer();

const span = transaction.startChild({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

```swift {tabTitle:Swift}
import Sentry;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction that contains an expensive operation (for example, `processOrderBatch`), and sends the result to Sentry:

```dart
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

```csharp
// Transaction can be started by providing, at minimum, the name and the operation
var transaction = SentrySdk.StartTransaction(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction span to time runs of an expensive operation on items from a channel. Timing for each operation is sent to Sentry and grouped by transaction name:

```go
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction that contains an expensive operation (for example, `processOrderBatch`), and sends the result to Sentry:

```java {tabTitle:Java}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

## Capturing Bean Method Execution

Every Spring bean method execution can be turned into a transaction or a span.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

## Capturing Bean Method Execution

Every Spring bean method execution can be turned into a transaction or a span.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

This is valid for all JavaScript SDKs (both backend and frontend) and works independently of the `Express`, `Http`, and `BrowserTracing` integrations.

```javascript
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

```c
// Enable performance monitoring by setting a sample rate above 0
sentry_options_t *options = sentry_options_new();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction for a scope that contains an expensive operation (for example, `expensive_operation`), and sends the result to Sentry:

```php
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction for a scope that contains an expensive operation (for example, `process_item`), and sends the result to Sentry:

```python
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction for a scope that contains an expensive operation (for example, `process_item`), and sends the result to Sentry:

```ruby
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
To instrument certain regions of your code, you can create transactions to capture them.

```rust
// Transaction can be started by providing the name and the operation
let tx_ctx = sentry::TransactionContext::new(
Expand Down
13 changes: 13 additions & 0 deletions src/platform-includes/performance/get-span/javascript.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
```JavaScript
const span = Sentry.getActiveSpan();

span?.setData("key", "value");

// Start a child span that will be a child of the current span.
// The child span will measure the time between span.startChild() and childSpan.finish().
const childSpan = span?.startChild({ name: "Child Span" });

expensiveCalculation();

childSpan?.finish();
```
13 changes: 13 additions & 0 deletions src/platform-includes/performance/get-span/node.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
```JavaScript
const span = Sentry.getActiveSpan();

span?.setData("key", "value");

// Start a child span that will be a child of the current span.
// The child span will measure the time between span.startChild() and childSpan.finish().
const childSpan = span?.startChild({ name: "Child Span" });

expensiveCalculation();

childSpan?.finish();
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Note>

The below span APIs (`startActiveSpan`, `startSpan`, and `getActiveSpan`) require SDK version `7.65.0` or higher. If you are using an older version of the SDK, you can use the [explicit transaction APIs](#start-transaction) for custom instrumentation.

</Note>
5 changes: 5 additions & 0 deletions src/platform-includes/performance/span-api-version/node.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Note>

The below span APIs (`startActiveSpan`, `startSpan`, and `getActiveSpan`) require SDK version `7.65.0` or higher. If you are using an older version of the SDK, you can use the [explicit transaction APIs](#start-transaction) for custom instrumentation.

</Note>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```JavaScript
const result = Sentry.startActiveSpan({ name: 'GET /users', op: 'http.client' }, () => {
return fetchUsers();
})
```
5 changes: 5 additions & 0 deletions src/platform-includes/performance/span-operations/node.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```JavaScript
const result = Sentry.startActiveSpan({ name: 'SELECT * FROM TABLE', op: 'db.query' }, () => {
return execQuery();
})
```
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,71 @@ redirect_from:

<Note>

To capture transactions customized to your organization's needs, you must first <PlatformLink to="/performance/">set up performance monitoring.</PlatformLink>
To capture transactions and spans customized to your organization's needs, you must first <PlatformLink to="/performance/">set up performance monitoring.</PlatformLink>

</Note>

To instrument certain regions of your code, you can create transactions to capture them.
<PlatformSection notSupported={["javascript", "node"]}>

<PlatformContent includePath="performance/enable-manual-instrumentation" />

<PlatformContent includePath="performance/add-spans-example" />

</PlatformSection>

<PlatformSection supported={["javascript", "node"]}>

To add custom performance data to your application, you need to create and use spans. Spans are a way to measure the time it takes for a specific action to occur. For example, you can create a span to measure the time it takes for a function to execute.

To start measuring timing data, you first need to import the SDK.

<PlatformContent includePath="enriching-events/import" />

<PlatformContent includePath="performance/span-api-version" />

## Create Active Span

By default created spans 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.

<PlatformContent includePath="performance/add-active-span" />

## Get Active Span

You can also get the current active span, which is useful for when you need to add new child spans.

<PlatformContent includePath="performance/get-span" />

## Start Independent Spans

If you want to add a span that is not active, you can create a 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. In most cases you'll want to create and use active spans.

<PlatformContent includePath="performance/add-independent-span" />

## Start Transaction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about

Suggested change
## Start Transaction
## [Deprecated] Start Transaction

or something similar that discourages folks from usingstartTransaction?

We probably need to make this JS-specific though so maybe throwing in a note/alert might also work

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't necessarily want to deprecate this method for now, but once we're more comfortable with the API we can come back and adjust.


The root span (the span that is the parent of all other spans) is known as a transaction in Sentry. This can be accessed and created separately if you need more control over the timing data or if you use a version of the SDK that does not support the top level span APIs.

<PlatformContent includePath="performance/enable-manual-instrumentation" />

<PlatformContent includePath="performance/add-spans-example" />

## Adding Span operations

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.

Sentry maintains a [list of well known span operations](https://develop.sentry.dev/sdk/performance/span-operations/#list-of-operations) and it is recommended that you use one of those operations if it is applicable to your span.

<PlatformContent includePath="performance/span-operations" />

</PlatformSection>

<PlatformSection supported={["java", "apple"]}>

<PlatformContent includePath="performance/create-transaction-bound-to-scope" />

</PlatformSection>

<PlatformSection notSupported={["java", "native", "apple"]}>
<PlatformSection notSupported={["java", "native", "apple", "javascript", "node"]}>

<PlatformContent includePath="performance/retrieve-transaction" />

Expand Down