Cross application tracing with Go

Distributed tracing is now available; this feature improves on cross application tracing and is recommended for monitoring activity in large, distributed systems.

The Go agent includes support for New Relic APM's cross application tracing (CAT). Cross application tracing links transactions between APM apps, which is vital for applications implementing a service-oriented or microservices architecture.

Enable cross application tracing with Go

You can enable or disable cross application tracing in the Go agent by using the CrossApplicationTracer.Enabled configuration flag.

Transaction and HTTP request guidelines with Go

Even with cross application tracing enabled, you'll need to make sure your application follows a few simple conventions when responding to HTTP(s) requests, making its own HTTP(s) requests, or creating its own transactions.

Creating transactions via http.ServeMux

If you're using Go's http.ServeMux and want CAT support, you'll need to use the agent's WrapHandle and WrapHandleFunc wrappers. These wrappers automatically start and end transactions with the request and response writer, which will automatically add the correct CAT headers. Your code should look similar to the following:

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

You can read more about these wrappers in Instrument Go transactions.

Creating web transactions manually

When creating your own transactions with app.StartTransaction, ensure that all calls to StartTransaction include the response writer and request. For example, a transaction started with the following code will have CAT enabled:

    txn := app.StartTransaction("transactionName", responseWriter, request)
    defer txn.End()

However, a transaction started without the second and third parameters will not have CAT enabled:

    txn := app.StartTransaction("backgroundTask", nil, nil)
    defer txn.End()

Additionally, if you're setting HTTP response codes, use the Go agent's txn.WriteHeader method rather than the standard library's http.ResponseWriter.WriteHeader method.

    //old code
    //w.WriteHeader(http.StatusInternalServerError)
    
    //replace with this
    txn := app.StartTransaction("transaction_name", w http.ResponseWriter, r *http.Request)
    /* ... */
    txn.WriteHeader(http.StatusInternalServerError)
Making HTTP requests

In order to have your outbound HTTP(s) requests eligible for CAT, you'll need to create an external segment.

The easiest way to create an external segment for your outbound HTTP(s) request is to use the newrelic.NewRoundTripper method. For example, this code will make a request to http://api.example.com/ that includes the outgoing CAT headers.

    func useNewRoundTripper(txn newrelic.Transaction) (*http.Response, error) {
        client := &http.Client{}
        client.Transport = newrelic.NewRoundTripper(txn, nil)
        resp, err := client.Get("http://api.example.com/")
        return resp,err;
    }

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

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 }

While it's also possible to create a an ExternalSegment via a struct literal, this segment will not be eligible for CAT. Because of this, New Relic recommends using newrelic.NewRoundTripper or newrelic.ExternalSegment.

    func noGoodForCat(txn newrelic.Transaction, url string) (*http.Response, error) {
      defer newrelic.ExternalSegment{
        StartTime: newrelic.StartSegmentNow(txn),
        URL:   url,
      }.End()

      return http.Get(url)
    }   

For more help

Additional documentation resources include:

Recommendations for learning more: