github.com/lulzWill/go-agent@v2.1.2+incompatible/GUIDE.md (about)

     1  # New Relic Go Agent Guide
     2  
     3  * [Installation](#installation)
     4  * [Config and Application](#config-and-application)
     5  * [Logging](#logging)
     6    * [logrus](#logrus)
     7  * [Transactions](#transactions)
     8  * [Segments](#segments)
     9    * [Datastore Segments](#datastore-segments)
    10    * [External Segments](#external-segments)
    11  * [Attributes](#attributes)
    12  * [Cross Application Tracing](#cross-application-tracing)
    13    * [Upgrading Applications to Support Cross Application Tracing](#upgrading-applications-to-support-cross-application-tracing)
    14  * [Custom Metrics](#custom-metrics)
    15  * [Custom Events](#custom-events)
    16  * [Request Queuing](#request-queuing)
    17  * [Error Reporting](#error-reporting)
    18    * [Advanced Error Reporting](#advanced-error-reporting)
    19  * [Naming Transactions and Metrics](#naming-transactions-and-metrics)
    20  * [For More Help](#for-more-help)
    21  
    22  ## Installation
    23  
    24  Installing the Go Agent is the same as installing any other Go library.  The
    25  simplest way is to run:
    26  
    27  ```
    28  go get github.com/lulzWill/go-agent
    29  ```
    30  
    31  Then import the `github.com/lulzWill/go-agent` package in your application.
    32  
    33  ## Config and Application
    34  
    35  * [config.go](config.go)
    36  * [application.go](application.go)
    37  
    38  In your `main` function or in an `init` block:
    39  
    40  ```go
    41  config := newrelic.NewConfig("Your Application Name", "__YOUR_NEW_RELIC_LICENSE_KEY__")
    42  app, err := newrelic.NewApplication(config)
    43  ```
    44  
    45  Find your application in the New Relic UI.  Click on it to see the Go runtime
    46  tab that shows information about goroutine counts, garbage collection, memory,
    47  and CPU usage.
    48  
    49  If you are working in a development environment or running unit tests, you may
    50  not want the Go Agent to spawn goroutines or report to New Relic.  You're in
    51  luck!  Set the config's `Enabled` field to false.  This makes the license key
    52  optional.
    53  
    54  ```go
    55  config := newrelic.NewConfig("Your Application Name", "")
    56  config.Enabled = false
    57  app, err := newrelic.NewApplication(config)
    58  ```
    59  
    60  ## Logging
    61  
    62  * [log.go](log.go)
    63  
    64  The agent's logging system is designed to be easily extensible.  By default, no
    65  logging will occur.  To enable logging, assign the `Config.Logger` field to
    66  something implementing the `Logger` interface.  A basic logging
    67  implementation is included.
    68  
    69  To log at debug level to standard out, set:
    70  
    71  ```go
    72  config.Logger = newrelic.NewDebugLogger(os.Stdout)
    73  ```
    74  
    75  To log at info level to a file, set:
    76  
    77  ```go
    78  w, err := os.OpenFile("my_log_file", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
    79  if nil == err {
    80    config.Logger = newrelic.NewLogger(w)
    81  }
    82  ```
    83  
    84  ### logrus
    85  
    86  * [_integrations/nrlogrus/nrlogrus.go](_integrations/nrlogrus/nrlogrus.go)
    87  
    88  If you are using `logrus` and would like to send the agent's log messages to its
    89  standard logger, import the
    90  `github.com/lulzWill/go-agent/_integrations/nrlogrus` package, then set:
    91  
    92  ```go
    93  config.Logger = nrlogrus.StandardLogger()
    94  ```
    95  
    96  ## Transactions
    97  
    98  * [transaction.go](transaction.go)
    99  * [Naming Transactions](#naming-transactions-and-metrics)
   100  * [More info on Transactions](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/transactions-page)
   101  
   102  Transactions time requests and background tasks.  Each transaction should only
   103  be used in a single goroutine.  Start a new transaction when you spawn a new
   104  goroutine.
   105  
   106  The simplest way to create transactions is to use
   107  `Application.StartTransaction` and `Transaction.End`.
   108  
   109  ```go
   110  txn := app.StartTransaction("transactionName", responseWriter, request)
   111  defer txn.End()
   112  ```
   113  
   114  If the response writer is provided when calling `StartTransaction`, you can
   115  then use `txn.WriteHeader` as a drop in replacement for the standard library's
   116  [`http.ResponseWriter.WriteHeader`](https://golang.org/pkg/net/http/#ResponseWriter)
   117  function. We strongly recommend doing so, as this both enables Cross
   118  Application Tracing support and ensures that attributes are added to the
   119  Transaction event capturing the response size and status code.
   120  
   121  The response writer and request parameters are optional.  Leave them `nil` to
   122  instrument a background task.
   123  
   124  ```go
   125  txn := app.StartTransaction("backgroundTask", nil, nil)
   126  defer txn.End()
   127  ```
   128  
   129  The transaction has helpful methods like `NoticeError` and `SetName`.
   130  See more in [transaction.go](transaction.go).
   131  
   132  If you are using [`http.ServeMux`](https://golang.org/pkg/net/http/#ServeMux),
   133  use `WrapHandle` and `WrapHandleFunc`.  These wrappers automatically start and
   134  end transactions with the request and response writer.  See
   135  [instrumentation.go](instrumentation.go).
   136  
   137  ```go
   138  http.HandleFunc(newrelic.WrapHandleFunc(app, "/users", usersHandler))
   139  ```
   140  
   141  To access the transaction in your handler, use type assertion on the response
   142  writer passed to the handler.
   143  
   144  ```go
   145  func myHandler(w http.ResponseWriter, r *http.Request) {
   146  	if txn, ok := w.(newrelic.Transaction); ok {
   147  		txn.NoticeError(errors.New("my error message"))
   148  	}
   149  }
   150  ```
   151  
   152  ## Segments
   153  
   154  * [segments.go](segments.go)
   155  
   156  Find out where the time in your transactions is being spent!  Each transaction
   157  should only track segments in a single goroutine.
   158  
   159  `Segment` is used to instrument functions, methods, and blocks of code. A
   160  segment begins when its `StartTime` field is populated, and finishes when its
   161  `End` method is called.
   162  
   163  ```go
   164  segment := newrelic.Segment{}
   165  segment.Name = "mySegmentName"
   166  segment.StartTime = newrelic.StartSegmentNow(txn)
   167  // ... code you want to time here ...
   168  segment.End()
   169  ```
   170  
   171  `StartSegment` is a convenient helper.  It creates a segment and starts it:
   172  
   173  ```go
   174  segment := newrelic.StartSegment(txn, "mySegmentName")
   175  // ... code you want to time here ...
   176  segment.End()
   177  ```
   178  
   179  Timing a function is easy using `StartSegment` and `defer`.  Just add the
   180  following line to the beginning of that function:
   181  
   182  ```go
   183  defer newrelic.StartSegment(txn, "mySegmentName").End()
   184  ```
   185  
   186  Segments may be nested.  The segment being ended must be the most recently
   187  started segment.
   188  
   189  ```go
   190  s1 := newrelic.StartSegment(txn, "outerSegment")
   191  s2 := newrelic.StartSegment(txn, "innerSegment")
   192  // s2 must be ended before s1
   193  s2.End()
   194  s1.End()
   195  ```
   196  
   197  A zero value segment may safely be ended.  Therefore, the following code
   198  is safe even if the conditional fails:
   199  
   200  ```go
   201  var s newrelic.Segment
   202  if txn, ok := w.(newrelic.Transaction); ok {
   203  	s.StartTime = newrelic.StartSegmentNow(txn),
   204  }
   205  // ... code you wish to time here ...
   206  s.End()
   207  ```
   208  
   209  ### Datastore Segments
   210  
   211  Datastore segments appear in the transaction "Breakdown table" and in the
   212  "Databases" tab.
   213  
   214  * [datastore.go](datastore.go)
   215  * [More info on Databases tab](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/databases-slow-queries-page)
   216  
   217  Datastore segments are instrumented using `DatastoreSegment`.  Just like basic
   218  segments, datastore segments begin when the `StartTime` field is populated and
   219  finish when the `End` method is called.  Here is an example:
   220  
   221  ```go
   222  s := newrelic.DatastoreSegment{
   223  	// Product is the datastore type.  See the constants in datastore.go.
   224  	Product: newrelic.DatastoreMySQL,
   225  	// Collection is the table or group.
   226  	Collection: "my_table",
   227  	// Operation is the relevant action, e.g. "SELECT" or "GET".
   228  	Operation: "SELECT",
   229  }
   230  s.StartTime = newrelic.StartSegmentNow(txn)
   231  // ... make the datastore call
   232  s.End()
   233  ```
   234  
   235  This may be combined into a single line when instrumenting a datastore call
   236  that spans an entire function call:
   237  
   238  ```go
   239  s := newrelic.DatastoreSegment{
   240  	StartTime:  newrelic.StartSegmentNow(txn),
   241  	Product:    newrelic.DatastoreMySQL,
   242  	Collection: "my_table",
   243  	Operation:  "SELECT",
   244  }
   245  defer s.End()
   246  ```
   247  
   248  ### External Segments
   249  
   250  External segments appear in the transaction "Breakdown table" and in the
   251  "External services" tab. Version 1.11.0 of the Go agent also adds support for
   252  Cross Application Tracing (CAT), which will result in external segments also
   253  appearing in the "Service maps" tab and being linked in transaction traces when
   254  both sides of the request have traces.
   255  
   256  * [More info on External Services tab](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/external-services-page)
   257  * [More info on Cross Application Tracing](https://docs.newrelic.com/docs/apm/transactions/cross-application-traces/introduction-cross-application-traces)
   258  
   259  External segments are instrumented using `ExternalSegment`. There are three
   260  ways to use this functionality:
   261  
   262  1. Using `StartExternalSegment` to create an `ExternalSegment` before the
   263     request is sent, and then calling `ExternalSegment.End` when the external
   264     request is complete.
   265     
   266     For CAT support to operate, an `http.Request` must be provided to
   267     `StartExternalSegment`, and the `ExternalSegment.Response` field must be set
   268     before `ExternalSegment.End` is called or deferred.
   269  
   270     For example:
   271  
   272      ```go
   273      func external(txn newrelic.Transaction, req *http.Request) (*http.Response, error) {
   274        s := newrelic.StartExternalSegment(txn, req)
   275        response, err := http.DefaultClient.Do(req)
   276        s.Response = response
   277        s.End()
   278        return response, err
   279      }
   280      ```
   281  
   282  2. Using `NewRoundTripper` to get a
   283     [`http.RoundTripper`](https://golang.org/pkg/net/http/#RoundTripper) that
   284     will automatically instrument all requests made via
   285     [`http.Client`](https://golang.org/pkg/net/http/#Client) instances that use
   286     that round tripper as their `Transport`. This option results in CAT support
   287     transparently, provided the Go agent is version 1.11.0 or later.
   288  
   289     For example:
   290  
   291      ```go
   292      client := &http.Client{}
   293      client.Transport = newrelic.NewRoundTripper(txn, nil)
   294      resp, err := client.Get("http://example.com/")
   295      ```
   296  
   297     Note that, as with all segments, the round tripper returned **must** only be
   298     used in the same goroutine as the transaction.
   299  
   300  3. Directly creating an `ExternalSegment` via a struct literal with an explicit
   301     `URL` or `Request`, and then calling `ExternalSegment.End`. This option does
   302     not support CAT, and may be removed or changed in a future major version of
   303     the Go agent. As a result, we suggest using one of the other options above
   304     wherever possible.
   305  
   306     For example:
   307  
   308      ```go
   309      func external(txn newrelic.Transaction, url string) (*http.Response, error) {
   310        es := newrelic.ExternalSegment{
   311          StartTime: newrelic.StartSegmentNow(txn),
   312          URL:   url,
   313        }
   314        defer es.End()
   315  
   316        return http.Get(url)
   317      }
   318      ```
   319  
   320  ## Attributes
   321  
   322  Attributes add context to errors and allow you to filter performance data
   323  in Insights.
   324  
   325  You may add them using the `Transaction.AddAttribute` method.
   326  
   327  ```go
   328  txn.AddAttribute("key", "value")
   329  txn.AddAttribute("product", "widget")
   330  txn.AddAttribute("price", 19.99)
   331  txn.AddAttribute("importantCustomer", true)
   332  ```
   333  
   334  * [More info on Custom Attributes](https://docs.newrelic.com/docs/insights/new-relic-insights/decorating-events/insights-custom-attributes)
   335  
   336  Some attributes are recorded automatically.  These are called agent attributes.
   337  They are listed here:
   338  
   339  * [attributes.go](attributes.go)
   340  
   341  To disable one of these agents attributes, `AttributeResponseCode` for
   342  example, modify the config like this:
   343  
   344  ```go
   345  config.Attributes.Exclude = append(config.Attributes.Exclude, newrelic.AttributeResponseCode)
   346  ```
   347  
   348  * [More info on Agent Attributes](https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-metrics/agent-attributes)
   349  
   350  ## Cross Application Tracing
   351  
   352  New Relic's
   353  [Cross Application Tracing](https://docs.newrelic.com/docs/apm/transactions/cross-application-traces/introduction-cross-application-traces)
   354  feature, or CAT for short, links transactions between applications in APM to
   355  help identify performance problems within your service-oriented architecture.
   356  Support for CAT was added in version 1.11.0 of the Go agent.
   357  
   358  As CAT uses HTTP headers to track requests across applications, the Go agent
   359  needs to be able to access and modify request and response headers both for
   360  incoming and outgoing requests.
   361  
   362  ### Upgrading Applications to Support Cross Application Tracing
   363  
   364  Although many Go applications instrumented using older versions of the Go agent
   365  will not require changes to enable CAT support, we've prepared this checklist
   366  that you can use to ensure that your application is ready to take advantage of
   367  the full functionality offered by New Relic's CAT feature:
   368  
   369  1. Ensure that incoming HTTP requests both parse any incoming CAT headers, and
   370     output the required outgoing CAT header:
   371  
   372     1. If you use `WrapHandle` or `WrapHandleFunc` to instrument a server that
   373        uses [`http.ServeMux`](https://golang.org/pkg/net/http/#ServeMux), no
   374        changes are required.
   375  
   376     2. If you use either of the Go agent's [Gin](_integrations/nrgin/v1) or
   377        [Gorilla](_integrations/nrgorilla/v1) integrations, no changes are
   378        required.
   379  
   380     3. If you use another framework or
   381        [`http.Server`](https://golang.org/pkg/net/http/#Server) directly, you
   382        will need to ensure that:
   383  
   384        1. All calls to `StartTransaction` include the response writer and
   385           request, and
   386        2. `Transaction.WriteHeader` is used instead of calling `WriteHeader`
   387           directly on the response writer, as described in the
   388           [transactions section of this guide](#transactions).
   389  
   390  2. Convert any instances of using an `ExternalSegment` literal directly to
   391     either use `StartExternalSegment` or `NewRoundTripper`, as described in the
   392     [external segments section of this guide](#external-segments).
   393  
   394  3. Ensure that calls to `StartExternalSegment` provide an `http.Request`.
   395  
   396  4. Ensure that the `Response` field is set on `ExternalSegment` values before
   397     making or deferring calls to `ExternalSegment.End`.
   398  
   399  ## Custom Metrics
   400  
   401  * [More info on Custom Metrics](https://docs.newrelic.com/docs/agents/go-agent/instrumentation/create-custom-metrics-go)
   402  
   403  You may [create custom metrics](https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/collect-custom-metrics)
   404  via the `RecordCustomMetric` method.
   405  
   406  ```go
   407  app.RecordCustomMetric(
   408  	"CustomMetricName", // Name of your metric
   409  	132,                // Value
   410  )
   411  ```
   412  
   413  **Note:** The Go Agent will automatically prepend the metric name you pass to
   414  `RecordCustomMetric` (`"CustomMetricName"` above) with the string `Custom/`.
   415  This means the above code would produce a metric named
   416  `Custom/CustomMetricName`.  You'll also want to read over the
   417  [Naming Transactions and Metrics](#naming-transactions-and-metrics) section below for
   418  advice on coming up with appropriate metric names.
   419  
   420  ## Custom Events
   421  
   422  You may track arbitrary events using custom Insights events.
   423  
   424  ```go
   425  app.RecordCustomEvent("MyEventType", map[string]interface{}{
   426  	"myString": "hello",
   427  	"myFloat":  0.603,
   428  	"myInt":    123,
   429  	"myBool":   true,
   430  })
   431  ```
   432  
   433  ## Request Queuing
   434  
   435  If you are running a load balancer or reverse web proxy then you may configure
   436  it to add a `X-Queue-Start` header with a Unix timestamp.  This will create a
   437  band on the application overview chart showing queue time.
   438  
   439  * [More info on Request Queuing](https://docs.newrelic.com/docs/apm/applications-menu/features/request-queuing-tracking-front-end-time)
   440  
   441  ## Error Reporting
   442  
   443  You may track errors using the `Transaction.NoticeError` method.  The easiest
   444  way to get started with `NoticeError` is to use errors based on
   445  [Go's standard error interface](https://blog.golang.org/error-handling-and-go).
   446  
   447  ```go
   448  txn.NoticeError(errors.New("my error message"))
   449  ```
   450  
   451  `NoticeError` will work with *any* sort of object that implements Go's standard
   452  error type interface -- not just `errorStrings` created via `errors.New`.  
   453  
   454  If you're interested in sending more than an error *message* to New Relic, the
   455  Go Agent also offers a `newrelic.Error` struct.
   456  
   457  ```go
   458  txn.NoticeError(newrelic.Error{
   459  	Message: "my error message",
   460  	Class:   "IdentifierForError",
   461  	Attributes: map[string]interface{}{
   462  		"important_number": 97232,
   463  		"relevant_string":  "zap",
   464  	},
   465  })
   466  ```
   467  
   468  Using the `newrelic.Error` struct requires you to manually marshall your error
   469  data into the `Message`, `Class`, and `Attributes` fields.  However, there's two
   470  **advantages** to using the `newrelic.Error` struct.
   471  
   472  First, by setting an error `Class`, New Relic will be able to aggregate errors
   473  in the *Error Analytics* section of APM.  Second, the `Attributes` field allows
   474  you to send through key/value pairs with additional error debugging information
   475  (also exposed in the *Error Analytics* section of APM).
   476  
   477  ### Advanced Error Reporting
   478  
   479  You're not limited to using Go's built-in error type or the provided
   480  `newrelic.Error` struct.  The Go Agent provides three error interfaces
   481  
   482  ```go
   483  type StackTracer interface {
   484  	StackTrace() []uintptr
   485  }
   486  
   487  type ErrorClasser interface {
   488  	ErrorClass() string
   489  }
   490  
   491  type ErrorAttributer interface {
   492  	ErrorAttributes() map[string]interface{}
   493  }
   494  ```
   495  
   496  If you implement any of these on your own error structs, the `txn.NoticeError`
   497  method will recognize these methods and use their return values to provide error
   498  information.
   499  
   500  For example, you could implement a custom error struct named `MyErrorWithClass`
   501  
   502  ```go
   503  type MyErrorWithClass struct {
   504  
   505  }
   506  ```
   507  
   508  Then, you could implement both an `Error` method (per Go's standard `error`
   509  interface) and an `ErrorClass` method (per the Go Agent `ErrorClasser`
   510  interface) for this struct.
   511  
   512  ```go
   513  func (e MyErrorWithClass) Error() string { return "A hard coded error message" }
   514  
   515  // ErrorClass implements the ErrorClasser interface.
   516  func (e MyErrorWithClass) ErrorClass() string { return "MyErrorClassForAggregation" }
   517  ```
   518  
   519  Finally, you'd use your new error by creating a new instance of your struct and
   520  passing it to the `NoticeError` method
   521  
   522  ```go
   523  txn.NoticeError(MyErrorWithClass{})
   524  ```
   525  
   526  While this is an oversimplified example, these interfaces give you a great deal
   527  of control over what error information is available for your application.
   528  
   529  ## Naming Transactions and Metrics
   530  
   531  You'll want to think carefully about how you name your transactions and custom
   532  metrics.  If your program creates too many unique names, you may end up with a
   533  [Metric Grouping Issue (or MGI)](https://docs.newrelic.com/docs/agents/manage-apm-agents/troubleshooting/metric-grouping-issues).
   534  
   535  MGIs occur when the granularity of names is too fine, resulting in hundreds or
   536  thousands of uniquely identified metrics and transactions.  One common cause of
   537  MGIs is relying on the full URL name for metric naming in web transactions.  A
   538  few major code paths may generate many different full URL paths to unique
   539  documents, articles, page, etc. If the unique element of the URL path is
   540  included in the metric name, each of these common paths will have its own unique
   541  metric name.
   542  
   543  
   544  ## For More Help
   545  
   546  There's a variety of places online to learn more about the Go Agent.
   547  
   548  [The New Relic docs site](https://docs.newrelic.com/docs/agents/go-agent/get-started/introduction-new-relic-go)
   549  contains a number of useful code samples and more context about how to use the Go Agent.
   550  
   551  [New Relic's discussion forums](https://discuss.newrelic.com) have a dedicated
   552  public forum [for the Go Agent](https://discuss.newrelic.com/c/support-products-agents/go-agent).
   553  
   554  When in doubt, [the New Relic support site](https://support.newrelic.com/) is
   555  the best place to get started troubleshooting an agent issue.