github.com/lulzWill/go-agent@v2.1.2+incompatible/_integrations/nrgin/v1/nrgin.go (about) 1 // Package nrgin introduces middleware to support the Gin framework. 2 // 3 // router := gin.Default() 4 // router.Use(nrgin.Middleware(app)) 5 // 6 package nrgin 7 8 import ( 9 "net/http" 10 11 "github.com/gin-gonic/gin" 12 "github.com/lulzWill/go-agent" 13 "github.com/lulzWill/go-agent/internal" 14 ) 15 16 func init() { internal.TrackUsage("integration", "framework", "gin", "v1") } 17 18 // headerResponseWriter exists to give the transaction access to response 19 // headers. 20 type headerResponseWriter struct{ w gin.ResponseWriter } 21 22 func (w *headerResponseWriter) Header() http.Header { return w.w.Header() } 23 func (w *headerResponseWriter) Write([]byte) (int, error) { return 0, nil } 24 func (w *headerResponseWriter) WriteHeader(int) {} 25 26 var _ http.ResponseWriter = &headerResponseWriter{} 27 28 type replacementResponseWriter struct { 29 gin.ResponseWriter 30 txn newrelic.Transaction 31 code int 32 written bool 33 } 34 35 var _ gin.ResponseWriter = &replacementResponseWriter{} 36 37 func (w *replacementResponseWriter) flushHeader() { 38 if !w.written { 39 w.txn.WriteHeader(w.code) 40 w.written = true 41 } 42 } 43 44 func (w *replacementResponseWriter) WriteHeader(code int) { 45 w.code = code 46 w.ResponseWriter.WriteHeader(code) 47 } 48 49 func (w *replacementResponseWriter) Write(data []byte) (int, error) { 50 w.flushHeader() 51 return w.ResponseWriter.Write(data) 52 } 53 54 func (w *replacementResponseWriter) WriteString(s string) (int, error) { 55 w.flushHeader() 56 return w.ResponseWriter.WriteString(s) 57 } 58 59 func (w *replacementResponseWriter) WriteHeaderNow() { 60 w.flushHeader() 61 w.ResponseWriter.WriteHeaderNow() 62 } 63 64 var ( 65 ctxKey = "newRelicTransaction" 66 ) 67 68 // Transaction returns the transaction stored inside the context, or nil if not 69 // found. 70 func Transaction(c *gin.Context) newrelic.Transaction { 71 if v, exists := c.Get(ctxKey); exists { 72 if txn, ok := v.(newrelic.Transaction); ok { 73 return txn 74 } 75 } 76 return nil 77 } 78 79 // Middleware creates Gin middleware that instruments requests. 80 // 81 // router := gin.Default() 82 // router.Use(nrgin.Middleware(app)) 83 // 84 func Middleware(app newrelic.Application) gin.HandlerFunc { 85 return func(c *gin.Context) { 86 name := c.HandlerName() 87 w := &headerResponseWriter{w: c.Writer} 88 txn := app.StartTransaction(name, w, c.Request) 89 defer txn.End() 90 91 c.Writer = &replacementResponseWriter{ 92 ResponseWriter: c.Writer, 93 txn: txn, 94 code: http.StatusOK, 95 } 96 c.Set(ctxKey, txn) 97 c.Next() 98 } 99 }