Performance Monitoring

Sentry allows you to monitor the performance of your application, showing you how latency in one service may affect another service, and letting you pinpoint exactly which parts of a given operation may be responsible. To do this, it captures distributed traces consisting of transactions and spans, which measure individual services and individual operations within those services, respectively. You can learn more about this model in our Distributed Tracing docs.

Enabling Tracing

To get started sending traces you can:

  • Set a uniform sample rate for all transactions, by setting the TracesSampleRate option in your SDK config to a number between 0 and 1. (For example, to send 20% of transactions, set TracesSampleRate to 0.2.)
  • Control the sample rate dynamically, based on the transaction itself and the context in which it's captured, by providing a function to the TracesSampler config option.
func main() {
	err := sentry.Init(sentry.ClientOptions{
		// Specify a fixed sample rate:
        TracesSampleRate: 0.2,
        // Or provide a custom sampler:
		TracesSampler: sentry.TracesSamplerFunc(func(ctx sentry.SamplingContext) sentry.Sampled {
			return sentry.SampledTrue

If either of these options is set, tracing will be enabled in your app. (The two options are mutually exclusive.)

As you're getting tracing set up, we recommend setting TracesSampleRate to 1.0, so all created transactions are sent to Sentry. Once you're done with testing, though, you'll probably want to consider either lowering your TracesSampleRate value, or switching to TracesSampler, which will allow you customize how each transaction is sampled. Without sampling, captured transactions can add up quickly. (The net/http integration, for example, will send a transaction for every request made to the server.) Sampling allows you to send representative data without overwhelming either your system or your Sentry transaction quota.

You can learn more about the TracesSampleRate and TracesSampler options in Sampling Transactions.

Manual Instrumentation

To manually instrument certain regions of your code, you can create a transaction 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:

ctx := context.Background()

for item := range ch {
	span := sentry.StartSpan(ctx, "doWork",
		sentry.TransactionName(fmt.Sprintf("doWork: %s", item.Type)))
	doWork(span.Context(), item) // doWork may create additional spans

Adding More Spans to the Transaction

The next example contains the implementation of the hypothetical doWork function called from the code snippet in the previous section. Our SDK can determine if there is currently an open transaction in the current context and add all newly created spans as child operations to that transaction. Keep in mind that each individual span also needs to be manually finished; otherwise, spans will not show up in the transaction.

You can choose the value of operation and description.

func doWork(ctx context.Context, item Item) {
	span := sentry.StartSpan(ctx, "suboperation1")
	// omitted code ...
	span := sentry.StartSpan(ctx, "suboperation2")
	// omitted code ...

All finished spans are sent together as a transaction when the root span is finished. Make sure to call Finish() appropriately. Often times defer span.Finish() is handy.

Retrieving a Transaction

In cases where you want to access the current transaction but don't have a direct reference to it, use sentry.TransactionFromContext. This function returns the root span of the current transaction, or nil if no transaction is started.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    transaction := sentry.TransactionFromContext(ctx)
    cookie, _ := r.Cookie("secret")
    transaction.SetTag("secret-cookie", cookie.Value)
    // ...
You can edit this page on GitHub.