Custom Instrumentation
To capture transactions customized to your organization's needs, you must first set up performance monitoring.
To instrument certain regions of your code, you can create transactions to capture them.
// Transaction can be started by providing, at minimum, the name and the operation
var transaction = SentrySdk.StartTransaction(
"test-transaction-name",
"test-transaction-operation"
);
// Transactions can have child spans (and those spans can have child spans as well)
var span = transaction.StartChild("test-child-operation");
// ...
// (Perform the operation represented by the span/transaction)
// ...
span.Finish(); // Mark the span as finished
transaction.Finish(); // Mark the transaction as finished and send it to Sentry
For example, if you want to create a transaction for a user interaction in your application:
// Let's say this method is invoked when a user clicks on the checkout button of your shop
public async Task PerformCheckoutAsync()
{
// This will create a new Transaction for you
var transaction = SentrySdk.StartTransaction(
"checkout", // name
"perform-checkout" // operation
);
// Set transaction on scope to associate with errors and get included span instrumentation
// If there's currently an unfinished transaction, it may be dropped
SentrySdk.ConfigureScope(scope => scope.Transaction = transaction);
// Validate the cart
var validationSpan = transaction.StartChild(
"validation", // operation
"validating shopping cart" // description
);
await ValidateShoppingCartAsync();
validationSpan.Finish();
// Process the oder
var processSpan = transaction.StartChild(
"process", // operation
"processing shopping cart" // description
)
await ProcessShoppingCartAsync();
processSpan.Finish();
transaction.Finish();
}
This example will send a transaction checkout
to Sentry. The transaction will contain a validation
span that measures how long ValidateShoppingCartAsync
took and a process
span that measures ProcessShoppingCartAsync
. Finally, the call to transaction.Finish()
will finish the transaction and send it to Sentry.
Retrieve a Transaction
In cases where you want to attach Spans to an already ongoing Transaction you can use Sentry#GetSpan
. This method will return a SentryTransaction
in case there is a running Transaction or a Span
in case there is already a running Span, otherwise it returns null
.
using Sentry;
var span = SentrySdk.GetSpan();
if (span == null)
{
span = SentrySdk.StartTransaction("task", "op");
}
else
{
span = span.StartChild("subtask");
}
Distributed Tracing
Traces can bridge across multiple software services. Each span in a trace can be represented as a sentry-trace
header, containing the trace id, span id, and sampling details. This sentry-trace
header can be passed to downstream services so that they can create spans that are a continuation of the trace started in the originating service.
To obtain a trace header from the span, use ISpan.GetTraceHeader()
method, then pass it to the downstream service.
For HTTP communications, Sentry's SDK provides SentryHttpMessageHandler
, which can be used to automatically attach trace headers to outgoing HTTP requests.
The code snippet below demonstrates propagating the trace programatically. Even though SentryHttpMessageHandler
does that automatically for you, this illustrates the mechanism so it can be replicated in other protocols and technologies such a messaging systems.
using System;
using System.Net.Http;
using Sentry;
var transaction = SentrySdk.StartTransaction("name", "op");
var sentryTraceHeader = transaction.GetTraceHeader();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com");
request.Headers.Add("sentry-trace", sentryTraceHeader.ToString());
To create a span as a continuation of the trace retrieved from the upstream service, pass the sentry-trace
header value to the StartTransaction(...)
method:
using System;
using Sentry;
var httpContext = ...;
if (httpContext.Request.Headers.TryGetValue("sentry-trace", out var sentryTraceHeaderValue))
{
try
{
var sentryTraceHeader = SentryTraceHeader.Parse(sentryTraceHeaderValue);
var transaction = SentrySdk.StartTransaction("name", "op", sentryTraceHeader);
}
catch (FormatException e)
{
// Handle invalid trace header
e.Data["bad-sentry-header"] = sentryTraceHeaderValue;
SentrySdk.CaptureException(e);
}
}
In Sentry's ASP.NET Core integration, trace headers are handled automatically by the tracing middleware.
- Package:
- nuget:Sentry.AspNetCore
- Version:
- 4.9.0
- Repository:
- https://github.com/getsentry/sentry-dotnet