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.