instrumentation.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package newrelic
  2. import "net/http"
  3. // instrumentation.go contains helpers built on the lower level api.
  4. // WrapHandle facilitates instrumentation of handlers registered with an
  5. // http.ServeMux. For example, to instrument this code:
  6. //
  7. // http.Handle("/foo", fooHandler)
  8. //
  9. // Perform this replacement:
  10. //
  11. // http.Handle(newrelic.WrapHandle(app, "/foo", fooHandler))
  12. //
  13. // The Transaction is passed to the handler in place of the original
  14. // http.ResponseWriter, so it can be accessed using type assertion.
  15. // For example, to rename the transaction:
  16. //
  17. // // 'w' is the variable name of the http.ResponseWriter.
  18. // if txn, ok := w.(newrelic.Transaction); ok {
  19. // txn.SetName("other-name")
  20. // }
  21. //
  22. // The Transaction is added to the request's context, so it may be alternatively
  23. // accessed like this:
  24. //
  25. // // 'req' is the variable name of the *http.Request.
  26. // txn := newrelic.FromContext(req.Context())
  27. //
  28. // This function is safe to call if 'app' is nil.
  29. func WrapHandle(app Application, pattern string, handler http.Handler) (string, http.Handler) {
  30. if app == nil {
  31. return pattern, handler
  32. }
  33. return pattern, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  34. txn := app.StartTransaction(pattern, w, r)
  35. defer txn.End()
  36. r = RequestWithTransactionContext(r, txn)
  37. handler.ServeHTTP(txn, r)
  38. })
  39. }
  40. // WrapHandleFunc serves the same purpose as WrapHandle for functions registered
  41. // with ServeMux.HandleFunc.
  42. func WrapHandleFunc(app Application, pattern string, handler func(http.ResponseWriter, *http.Request)) (string, func(http.ResponseWriter, *http.Request)) {
  43. p, h := WrapHandle(app, pattern, http.HandlerFunc(handler))
  44. return p, func(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) }
  45. }
  46. // NewRoundTripper creates an http.RoundTripper to instrument external requests.
  47. // The http.RoundTripper returned will create an external segment before
  48. // delegating to the original RoundTripper provided (or http.DefaultTransport if
  49. // none is provided). If the Transaction parameter is nil, the RoundTripper
  50. // will look for a Transaction in the request's context (using FromContext).
  51. // This is STRONGLY recommended because it allows you to reuse the same client
  52. // for multiple transactions. Example use:
  53. //
  54. // client := &http.Client{}
  55. // client.Transport = newrelic.NewRoundTripper(nil, client.Transport)
  56. // request, _ := http.NewRequest("GET", "http://example.com", nil)
  57. // request = newrelic.RequestWithTransactionContext(request, txn)
  58. // resp, err := client.Do(request)
  59. //
  60. func NewRoundTripper(txn Transaction, original http.RoundTripper) http.RoundTripper {
  61. return roundTripperFunc(func(request *http.Request) (*http.Response, error) {
  62. segment := StartExternalSegment(txn, request)
  63. if nil == original {
  64. original = http.DefaultTransport
  65. }
  66. response, err := original.RoundTrip(request)
  67. segment.Response = response
  68. segment.End()
  69. return response, err
  70. })
  71. }
  72. type roundTripperFunc func(*http.Request) (*http.Response, error)
  73. func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }