github.com/newrelic/go-agent@v3.26.0+incompatible/_integrations/nrhttprouter/nrhttprouter.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // Package nrhttprouter instruments https://github.com/julienschmidt/httprouter
     5  // applications.
     6  //
     7  // Use this package to instrument inbound requests handled by a
     8  // httprouter.Router. Use an *nrhttprouter.Router in place of your
     9  // *httprouter.Router.  Example:
    10  //
    11  //   package main
    12  //
    13  //   import (
    14  //   	"fmt"
    15  //   	"net/http"
    16  //   	"os"
    17  //
    18  //   	"github.com/julienschmidt/httprouter"
    19  //   	newrelic "github.com/newrelic/go-agent"
    20  //   	"github.com/newrelic/go-agent/_integrations/nrhttprouter"
    21  //   )
    22  //
    23  //   func main() {
    24  //   	cfg := newrelic.NewConfig("httprouter App", os.Getenv("NEW_RELIC_LICENSE_KEY"))
    25  //   	app, _ := newrelic.NewApplication(cfg)
    26  //
    27  //   	// Create the Router replacement:
    28  //   	router := nrhttprouter.New(app)
    29  //
    30  //   	router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    31  //   		w.Write([]byte("welcome\n"))
    32  //   	})
    33  //   	router.GET("/hello/:name", (w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    34  //   		w.Write([]byte(fmt.Sprintf("hello %s\n", ps.ByName("name"))))
    35  //   	})
    36  //   	http.ListenAndServe(":8000", router)
    37  //   }
    38  //
    39  // Runnable example: https://github.com/newrelic/go-agent/tree/master/_integrations/nrhttprouter/example/main.go
    40  package nrhttprouter
    41  
    42  import (
    43  	"net/http"
    44  
    45  	"github.com/julienschmidt/httprouter"
    46  	newrelic "github.com/newrelic/go-agent"
    47  	"github.com/newrelic/go-agent/internal"
    48  )
    49  
    50  func init() { internal.TrackUsage("integration", "framework", "httprouter") }
    51  
    52  // Router should be used in place of httprouter.Router.  Create it using
    53  // New().
    54  type Router struct {
    55  	*httprouter.Router
    56  
    57  	application newrelic.Application
    58  }
    59  
    60  // New creates a new Router to be used in place of httprouter.Router.
    61  func New(app newrelic.Application) *Router {
    62  	return &Router{
    63  		Router:      httprouter.New(),
    64  		application: app,
    65  	}
    66  }
    67  
    68  func txnName(method, path string) string {
    69  	return method + " " + path
    70  }
    71  
    72  func (r *Router) handle(method string, path string, original httprouter.Handle) {
    73  	handle := original
    74  	if nil != r.application {
    75  		handle = func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
    76  			txn := r.application.StartTransaction(txnName(method, path), w, req)
    77  			defer txn.End()
    78  
    79  			req = newrelic.RequestWithTransactionContext(req, txn)
    80  
    81  			original(txn, req, ps)
    82  		}
    83  	}
    84  	r.Router.Handle(method, path, handle)
    85  }
    86  
    87  // DELETE replaces httprouter.Router.DELETE.
    88  func (r *Router) DELETE(path string, h httprouter.Handle) {
    89  	r.handle(http.MethodDelete, path, h)
    90  }
    91  
    92  // GET replaces httprouter.Router.GET.
    93  func (r *Router) GET(path string, h httprouter.Handle) {
    94  	r.handle(http.MethodGet, path, h)
    95  }
    96  
    97  // HEAD replaces httprouter.Router.HEAD.
    98  func (r *Router) HEAD(path string, h httprouter.Handle) {
    99  	r.handle(http.MethodHead, path, h)
   100  }
   101  
   102  // OPTIONS replaces httprouter.Router.OPTIONS.
   103  func (r *Router) OPTIONS(path string, h httprouter.Handle) {
   104  	r.handle(http.MethodOptions, path, h)
   105  }
   106  
   107  // PATCH replaces httprouter.Router.PATCH.
   108  func (r *Router) PATCH(path string, h httprouter.Handle) {
   109  	r.handle(http.MethodPatch, path, h)
   110  }
   111  
   112  // POST replaces httprouter.Router.POST.
   113  func (r *Router) POST(path string, h httprouter.Handle) {
   114  	r.handle(http.MethodPost, path, h)
   115  }
   116  
   117  // PUT replaces httprouter.Router.PUT.
   118  func (r *Router) PUT(path string, h httprouter.Handle) {
   119  	r.handle(http.MethodPut, path, h)
   120  }
   121  
   122  // Handle replaces httprouter.Router.Handle.
   123  func (r *Router) Handle(method, path string, h httprouter.Handle) {
   124  	r.handle(method, path, h)
   125  }
   126  
   127  // Handler replaces httprouter.Router.Handler.
   128  func (r *Router) Handler(method, path string, handler http.Handler) {
   129  	_, h := newrelic.WrapHandle(r.application, txnName(method, path), handler)
   130  	r.Router.Handler(method, path, h)
   131  }
   132  
   133  // HandlerFunc replaces httprouter.Router.HandlerFunc.
   134  func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
   135  	r.Handler(method, path, handler)
   136  }
   137  
   138  // ServeHTTP replaces httprouter.Router.ServeHTTP.
   139  func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   140  	if nil != r.application {
   141  		h, _, _ := r.Router.Lookup(req.Method, req.URL.Path)
   142  		if nil == h {
   143  			txn := r.application.StartTransaction("NotFound", w, req)
   144  			defer txn.End()
   145  			w = txn
   146  			req = newrelic.RequestWithTransactionContext(req, txn)
   147  		}
   148  	}
   149  
   150  	r.Router.ServeHTTP(w, req)
   151  }