Enable distributed tracing for your Go applications

Read on to learn how to enable and set up distributed tracing for the New Relic's Go agent.

Enable distributed tracing

To enable distributed tracing for a Go application:

  1. Use Go agent configuration settings for the type of distributed tracing you want:
    • Standard distributed tracing
    • Infinite Tracing
  2. Continue reading the transaction and request instrumentation guidelines below.

For help understanding the different types of agent distributed tracing, see How distributed tracing works.

Instrument transactions and HTTP requests

In order for distributed tracing to work optimally, your Go application must adhere to guidelines for the following scenarios:

Instrument transactions (if using ServeMux)

If you are using Go's http.ServeMux and want to enable New Relic's distributed tracing, your Go application must be instrumented with New Relic's WrapHandle and WrapHandleFunc wrappers. These wrappers automatically start and end transactions with the request and response writer, which will automatically add the correct distributed tracing headers. For more on how header propagation works, see How distributed tracing works.

Before and after example

Here is an example of code before instrumentation:

http.HandleFunc("/users", usersHandler)

And here is an example of that same code after instrumentation:

http.HandleFunc(newrelic.WrapHandleFunc(app, "/users", usersHandler))

Read more about using these wrappers in Instrument Go transactions.

Instrument outbound HTTP requests as external segments

In order to have your outbound HTTP requests eligible for distributed tracing, create an external segment.

The easiest way to create an external segment for your outbound HTTP request is to use the newrelic.NewRoundTripper method. Here is an example of making a request to http://api.example.com that includes the outgoing distributed tracing headers:

func useNewRoundTripper(txn *newrelic.Transaction) (*http.Response, error) {
    client := &http.Client{}
    client.Transport = newrelic.NewRoundTripper(client.Transport)
    request, _ := http.NewRequest("GET", "http://example.com", nil)
    request = newrelic.RequestWithTransactionContext(request, txn)
    return client.Do(request)
}

If you have a more complex request that uses the Go standard library's http.Request, use the newrelic.StartExternalSegment method to ensure your outbound request is eligible for distributed tracing:

func external(txn *newrelic.Transaction, req *http.Request) (*http.Response, error) { 
    s := newrelic.StartExternalSegment(txn, req) 
    response, err := http.DefaultClient.Do(req) 
    s.Response = response 
    s.End() 
    return response, err
}

An ExternalSegment created with a struct literal cannot be used for distributed tracing. Because of this, New Relic recommends using newrelic.NewRoundTripper or newrelic.StartExternalSegment.

func noGoodForDt(txn *newrelic.Transaction, url string) (*http.Response, error) {
    // Distributed tracing headers are not added to the outgoing request.
    // Use newrelic.NewRoundTripper or newrelicc.StartExternalSegment instead.
    defer newrelic.ExternalSegment{
        StartTime: txn.StartSegmentNow(),
        URL:       url,
    }.End()

    return http.Get(url)
}
Manually create and accept distributed trace payload

The distributed trace payload contains information that allows New Relic to stitch together transactions occurring in multiple services into a complete transaction trace. If New Relic-monitored services are not sending trace context to each other, it will result in incomplete trace details.

For general instructions on how to use the API calls below to implement distributed tracing, first see Use distributed tracing APIs.

If you want to... Use this

Create a payload to be sent to the called service.

InsertDistributedTraceHeaders(h http.Header)

Accept a payload sent from the first service; this will link these services together in a trace.

AcceptDistributedTraceHeaders(h http.Header)

For more details on using these, see the Go agent GitHub repo.

For more help

If you need more help, check out these support and learning resources: