Instrumentation for Deno

Learn how to configure spans to capture trace data on any action in your app.

To add custom performance data to your application, you need to add custom instrumentation in the form of 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.

You can find a list of all tracing APIs in the Tracing API section.

To get started, import the SDK.

Copied
import * as Sentry from "___SDK_PACKAGE___";

There are three key functions for creating spans:

  • startSpan: Creates a new span that is active, and which will end automatically. You'll likely want to use this function.
  • startSpanManual: Creates a new span that is active, which has to be ended manually.
  • startInactiveSpan: Creates a new span that is inactive, which has to be ended manually.

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 execute your code in a callback (for example, when working with hooks or similar) you have to work with inactive spans, and can combine this with withActiveSpan to manually associate child spans with the correct parent span.

The following options can be used for all span starting functions:

OptionTypeDescription
namestringThe name of the span.
opstringThe operation of the span.
startTimenumberThe start time of the span.
attributesRecord<string, Primitive>Attributes to attach to the span.
parentSpanSpanIf set, make the span a child of the specified span. Otherwise, the span will be a child of the currently active span.
onlyIfParentbooleanIf true, ignore the span if there is no active parent span.
forceTransactionbooleanIf 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.

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 throws an error or rejects a promise, the span will be marked as failed.

Start a span for a synchronous operation:

Copied
const result = Sentry.startSpan({ name: "Important Function" }, () => {
  return expensiveFunction();
});

Start a span for an asynchronous operation:

Copied
const result = await Sentry.startSpan(
  { name: "Important Function" },
  async () => {
    const res = await doSomethingAsync();
    return updateRes(res);
  },
);

You can also nest spans:

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

    return updateRes(res);
  },
);

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().

Copied
// Start a span that tracks the duration of middleware
function middleware(_req, res, next) {
  return Sentry.startSpanManual({ name: "middleware" }, (span) => {
    res.once("finish", () => {
      span.setHttpStatus(res.status);
      // manually tell the span when to end
      span.end();
    });
    return next();
  });
}

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 API from above.

Copied
const span1 = Sentry.startInactiveSpan({ name: "span1" });

someWork();

span1.end();

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:

Copied
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.

We expose some helpful utilities that can help you with custom instrumentation. See Tracing Utility APIs for more information.

See custom instrumentation for details on how to manually set up distributed tracing.

Span attributes describe an operation in a trace: which provider handled a request, which fallback ran, or what outcome it produced. When investigating a slow checkout, for example, you can compare charge spans by payment.provider and open an outlier trace to see what happened. The span already records its duration, so you don't need a separate duration attribute.

Add attributes to the span for the operation they describe. If automatic instrumentation doesn't capture an important step, create a span around the work rather than starting an empty span just to hold attributes. Span attributes can be string, number, boolean, or arrays containing only one of these types. Set attributes when starting a span:

Copied
await Sentry.startSpan(
  {
    name: "Charge payment provider",
    op: "payment.charge",
    attributes: {
      "payment.provider": provider.name,
    },
  },
  async (span) => {
    const result = await provider.charge(order);
    span.setAttribute("payment.retry_count", result.retryCount);
    span.setAttribute("payment.outcome", result.outcome);
    return result;
  },
);

You can also add attributes to an existing span, for example to identify which search strategy an automatically instrumented request used:

Copied
const span = Sentry.getActiveSpan();
if (span) {
  span.setAttribute("search.strategy", "prefix");
  span.setAttributes({
    "search.fallback_used": true,
    "search.index": "products_v2",
  });
}

Choose consistent, descriptive names and values you can filter or group by. Avoid sensitive values such as raw search terms and payment details. In Trace Explorer, filter on span.op:payment.charge, compare span.duration by payment.provider, and open a slow sample to check for retries or other bottlenecks in the trace.

Attributes are part of sampled traces. For standalone counters, gauges, or distributions that track every occurrence, such as failed checkout counts or queue depth, use Application Metrics instead. For attributes that should also appear on logs and metrics, see Attributes for scope-level APIs.

To add an attribute to all spans, use the beforeSendSpan callback. In stream mode, the callback receives span attributes in span.attributes. If you opt into transaction mode with traceLifecycle: 'static', wrap the callback with Sentry.withStaticSpan() and use span.data instead:

Copied
Sentry.init({
  // dsn, ...
  beforeSendSpan(span) {
    span.attributes = {
      ...span.attributes,
      "environment.region": "us-west-2",
    };

    return span;
  },
});

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.

Sentry maintains a list of well-known span operations and it is recommended that you use one of those operations if it is applicable to your span.

Copied
const result = Sentry.startSpan({ name: 'GET /users', op: 'http.client' }, () => {
  return fetchUsers();
})

Available since: v8.47.0

You can update the name of a span at any time:

Copied
const span = Sentry.getActiveSpan();
if (span) {
  Sentry.updateSpanName(span, "New Name");
}

Automatically instrumented spans use attributes such as http.request.method and db.system.name to derive their names. These names are low-cardinality. Raw URL paths, full query statements, and other request-specific details stay in attributes instead of the span name.

Use Sentry.updateSpanName() to override the automatically generated name. Choose a name that groups similar operations, and store request-specific details in span attributes.

If you use @sentry/browser, @sentry/react, and so on in browser environments, span.updateName() and Sentry.updateSpanName() will function identically, so you can use either one of them.

By default, spans will have an unknown status. You can manually update the status of a span to indicate whether it succeeded or failed:

Copied
// Status codes:
// 0: unknown
// 1: ok
// 2: error
span.setStatus({ code: 2 });

Alternatively, you can also use the Sentry.setHttpStatus() utility function to set a more specific error status.

Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").