Instrument Go segments

With New Relic APM's Go agent, you can monitor the specific segments of a transaction in a Go application to get more detail about specific functions or code blocks.

Measure time for functions and code blocks

Segments are the specific parts of a transaction in an application. By instrumenting segments, you can measure the time taken by functions and code blocks, such as external calls, datastore calls, and background tasks.

Example: You have a transaction associated with a checkout process, which processes both shipping information and credit card information. You could instrument your application to break that transaction up into two pieces: one segment for shipping and one segment for payment.

Block-of-code segments

Once you instrument a transaction, you are ready to instrument one or more segments in that transaction.

To instrument an arbitrary block of code as a segment, use the following pattern, and include txn as the variable name set for the transaction:

segment := newrelic.Segment{}
segment.Name = "mySegmentName"
segment.StartTime = newrelic.StartSegmentNow(txn)
// ... code you want to time here ...
segment.End()

StartSegment is a convenient helper. It creates a segment and starts it:

segment := newrelic.StartSegment(txn, "mySegmentName")
// ... code you want to time here ...
segment.End()

Function segments

Instrumenting a function as a segment is essentially the same as instrumenting an arbitrary block of code as a segment. The main difference is that, because a function has a discrete ending, you can use Go's defer statement.

To instrument a function as a segment, add the following code at the start of the function, and include txn as the variable name set for the transaction:

defer newrelic.StartSegment(txn, "mySegmentName").End()

Nest segments

Segments can be nested. The segment being ended must be the most recently started segment.

Here's an example of a segment starting and ending inside another segment:

s1 := newrelic.StartSegment(txn, "outerSegment")
s2 := newrelic.StartSegment(txn, "innerSegment")
// s2 must end before s1
s2.End()
s1.End()

A zero value segment may safely be ended. Therefore, the following code is safe even if the conditional fails:

var s newrelic.Segment
if txn, ok := w.(newrelic.Transaction); ok {
    s.StartTime = newrelic.StartSegmentNow(txn),
}
// ... code you wish to time here ...
s.End()

Datastore segments

You can instrument Go application datastore calls. Datastore segments appear in the APM Transactions breakdown table and Databases tab of the Transactions page in the New Relic UI.

Just like basic segments, datastore segments begin when the StartTime field is populated and finish when the End method is called. To instrument a datastore segment, place the following at the beginning of the function you want to monitor:

s := newrelic.DatastoreSegment{
    Product: newrelic.DatastoreMySQL,
    Collection: "users",
    Operation: "INSERT",
    ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    QueryParameters: map[string]interface{}{
        "name": "Dracula",
        "age": 439,
    },
    Host: "mysql-server-1",
    PortPathOrID: "3306",
    DatabaseName: "my_database",
}
s.StartTime = newrelic.StartSegmentNow(txn)
// ... make the datastore call
s.End()

For more information about:

When instrumenting a datastore call that spans an entire function call, you can use the defer statement to simplify instrumentation:

s := newrelic.DatastoreSegment{
    Product: newrelic.DatastoreMySQL,
    Collection: "users",
    Operation: "INSERT",
    ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    QueryParameters: map[string]interface{}{
        "name": "Dracula",
        "age": 439,
    },
    Host: "mysql-server-1",
    PortPathOrID: "3306",
    DatabaseName: "my_database",
}
defer s.End()

External segments

You can instrument Go application calls to external services, such as web services, resources in the cloud, and any other network calls. External segments appear in the APM Transactions breakdown table and the External services page in the New Relic UI.

There are two ways to instrument external segments:

Use StartExternalSegment()

Recommendation: Use the StartExternalSegment helper, since New Relic uses it to trace activity between your applications using cross application 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
}
 
Use NewRoundTripper()

NewRoundTripper returns an http.RoundTripper, which allows you to instrument external calls without calling StartExternalSegment by modifying your http.Client's Transport field. If the Transaction parameter is nil, the RoundTripper returned will look for a Transaction in the request's context using FromContext. This is recommended because it allows you to reuse the same client for multiple transactions.

Here is an example of NewRoundTripper instrumentation:

client := &http.Client{}
client.Transport = newrelic.NewRoundTripper(nil, client.Transport)

request, _ := http.NewRequest("GET", "http://example.com", nil)
request = newrelic.RequestWithTransactionContext(request, txn)

response, err := client.Do(request)

For more help

Recommendations for learning more: