Skip to content

Latest commit

 

History

History
308 lines (244 loc) · 12.5 KB

instrument-go-segments.mdx

File metadata and controls

308 lines (244 loc) · 12.5 KB
title tags metaDescription redirects freshnessValidatedDate
Instrument Go segments
Agents
Go agent
Instrumentation
With APM's Go agent, you can set up segments, which measure the timing of specific blocks of code in your Golang app.
/docs/agents/go-agent/instrumentation/instrument-go-segments
/docs/agents/go-agent/get-started/new-relic-go-monitor-segments
/docs/agents/go-agent/get-started/instrument-go-segments
never

With New Relic for Go, 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 [#go-segments]

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, adding messages to queues, 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 [#segment-code-block]

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 = txn.StartSegmentNow()
// ... code you want to time here ...
segment.End()

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

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

Function segments [#segment-function]

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 txn.StartSegment("mySegmentName").End()

Nest segments [#go-nesting-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 := txn.StartSegment("outerSegment")
s2 := txn.StartSegment("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 recordSegment {
    s.StartTime = txn.StartSegmentNow()
}
// ... code you wish to time here ...
s.End()

Datastore segments [#go-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 New Relic.

If you are using a MySQL, PostgreSQL, or SQLite database driver, the easiest way to add Datastore segments is to use our pre-built integration packages. Otherwise, you can manually create Datastore segments for each database call.

There is an integration package for each database driver that we support:
<table>
  <thead>
    <tr>
      <th width={250}>
        Database library supported
      </th>

      <th>
        Integration package
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
      </td>

      <td>
        [v3/integrations/nrmysql](https://godoc.org/github.com/newrelic/go-agent/v3/integrations/nrmysql)
      </td>
    </tr>

    <tr>
      <td>
        [lib/pq](https://github.com/lib/pq)
      </td>

      <td>
        [v3/integrations/nrpq](https://godoc.org/github.com/newrelic/go-agent/v3/integrations/nrpq)
      </td>
    </tr>

    <tr>
      <td>
        [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
      </td>

      <td>
        [v3/integrations/nrsqlite3](https://godoc.org/github.com/newrelic/go-agent/v3/integrations/nrsqlite3)
      </td>
    </tr>
  </tbody>
</table>

To use one of these integrations, first replace the driver with our integration version:

```go
import (
	// import our integration package in place of "github.com/go-sql-driver/mysql"
	_ "github.com/newrelic/go-agent/v3/integrations/nrmysql"
)

func main() {
	// open "nrmysql" in place of "mysql"
	db, err := sql.Open("nrmysql", "user@unix(/path/to/socket)/dbname")
}
```

Second, use the `ExecContext`, `QueryContext`, and `QueryRowContext` methods of [sql.DB](https://golang.org/pkg/database/sql/#DB), [sql.Conn](https://golang.org/pkg/database/sql/#Conn), [sql.Tx](https://golang.org/pkg/database/sql/#Tx), and [sql.Stmt](https://golang.org/pkg/database/sql/#Stmt) and provide a transaction-containing context. Calls to `Exec`, `Query`, and `QueryRow` do not get instrumented.

```go
ctx := newrelic.NewContext(context.Background(), txn)
row := db.QueryRowContext(ctx, "SELECT count(*) from tables")
```

If you are using a [database/sql](https://golang.org/pkg/database/sql/) database not listed above, you can write your own instrumentation for it using [InstrumentConnector](https://godoc.org/github.com/newrelic/go-agent/v3/newrelic#InstrumentConnector), [InstrumentDriver](https://godoc.org/github.com/newrelic/go-agent/v3/newrelic#InstrumentDriver), and [DriverSegmentBuilder](https://godoc.org/github.com/newrelic/go-agent/v3/newrelic#DriverSegmentBuilder). The integration packages act as examples of how to do this.

<Callout variant="important">
  Datastore integration packages for MySQL, PostgreSQL, and SQLite were added in Go agent v2.8.0 and require Go v1.10 or above.
</Callout>

<Collapser id="" title={<>Use DatastoreSegment</>}

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:

```go
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 = txn.StartSegmentNow()
// ... make the datastore call
s.End()
```

For more information about:

* Assigning the `Collection`, `Operation`, `DatabaseName`, and other parameter values: See the [New Relic datastore segment documentation on GoDoc](https://godoc.org/github.com/newrelic/go-agent#DatastoreSegment).
* Available values for `Product`: See the [New Relic documentation on GitHub](https://github.com/newrelic/go-agent/blob/master/datastore.go).

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

```go
s := newrelic.DatastoreSegment{
    StartTime: txn.StartSegmentNow(),
    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 [#go-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 Transactions breakdown table and the External services page in New Relic.

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 [Distributed tracing](/docs/agents/go-agent/features/distributed-tracing-go).
```go
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
}
```

<Collapser id="new-round-tripper" title={<>Use NewRoundTripper()</>}

`NewRoundTripper` returns an [http.RoundTripper](https://golang.org/pkg/net/http/#RoundTripper), which allows you to instrument external calls without calling `StartExternalSegment` by modifying your `http.Client`'s `Transport` field. The `RoundTripper` returned will look for a `Transaction` in the request's context using [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext).

Here is an example of `NewRoundTripper` instrumentation:

```go
client := &http.Client{}
client.Transport = newrelic.NewRoundTripper(client.Transport)

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

response, err := client.Do(request)
```

Message producer segments [#go-message-producer-segments]

You can instrument Go application calls that add messages to queuing systems like RabbitMQ and Kafka. Message producer segments appear in the APM Transactions breakdown in New Relic.

There is only one way to instrument message producer segments:

Use MessageProducerSegment} > Just like basic segments, message producer segments begin when the `StartTime` field is populated, and finish when the `End` method is called. To instrument a message producer segment, place the following at the beginning of the function you want to monitor:
```go
s := newrelic.MessageProducerSegment{
    Library:              "RabbitMQ",
    DestinationType:      newrelic.MessageExchange,
    DestinationName:      "myExchange",
    DestinationTemporary: false,
}
s.StartTime = txn.StartSegmentNow()
// ... add message to queue
s.End()
```

For more information about assigning the `Library`, `DestinationType`, `DestinationName`, or `DestinationTemporary` fields, see the [New Relic message producer segment documentation on GoDoc](https://godoc.org/github.com/newrelic/go-agent#MessageProducerSegment).

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

```go
s := newrelic.MessageProducerSegment{
    StartTime:            txn.StartSegmentNow(),
    Library:              "RabbitMQ",
    DestinationType:      newrelic.MessageExchange,
    DestinationName:      "myExchange",
    DestinationTemporary: false,
}
defer s.End()
// ... add message to queue
```

<Callout variant="important">
  Message producer segments were added in Go agent version 2.14.0.
</Callout>