github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/metrics/metrics.go (about) 1 package metrics 2 3 import ( 4 "bytes" 5 "os" 6 "strconv" 7 "time" 8 9 "github.com/gramework/gramework" 10 "github.com/prometheus/client_golang/prometheus" 11 "github.com/prometheus/client_golang/prometheus/promhttp" 12 ) 13 14 // Middleware handles metrics data 15 type Middleware struct { 16 httpReqCounter *prometheus.CounterVec 17 reqDuration *prometheus.HistogramVec 18 } 19 20 const ( 21 typeHTTPS = "https" 22 typeHTTP = "http" 23 24 millisecond = float64(time.Millisecond) 25 26 uvKey = "gramework.metrics.startTime" 27 ) 28 29 var metricsPath = []byte("/metrics") 30 31 // Register the middlewares 32 func Register(app *gramework.App, serviceName ...string) error { 33 var m Middleware 34 name := os.Args[0] 35 if len(serviceName) > 0 { 36 name = serviceName[0] 37 } 38 39 hostname, err := os.Hostname() 40 if err != nil { 41 return err 42 } 43 44 m.httpReqCounter = prometheus.NewCounterVec( 45 prometheus.CounterOpts{ 46 Name: "gramework_http_requests_total", 47 Help: "Total count of HTTP requests processed, partitioned by code, method, path and type (HTTP/HTTPS)", 48 ConstLabels: prometheus.Labels{ 49 "service": name, 50 "node": hostname, 51 }, 52 }, 53 []string{"code", "method", "path", "type"}, 54 ) 55 if err = prometheus.Register(m.httpReqCounter); err != nil { 56 return err 57 } 58 59 m.reqDuration = prometheus.NewHistogramVec( 60 prometheus.HistogramOpts{ 61 Name: "gramework_http_requests_duration_seconds", 62 Help: "Request processing duration, partitioned by code, method, path and type (HTTP/HTTPS)", 63 ConstLabels: prometheus.Labels{ 64 "service": name, 65 "node": hostname, 66 }, 67 }, 68 []string{"code", "method", "path", "type"}, 69 ) 70 71 if err = prometheus.Register(m.reqDuration); err != nil { 72 return err 73 } 74 75 app.GET(string(metricsPath), gramework.NewGrameHandler(promhttp.Handler())) 76 77 if err = app.UsePre(m.startReq); err != nil { 78 return err 79 } 80 81 return app.UseAfterRequest(m.endReq) 82 } 83 84 func (m *Middleware) startReq(ctx *gramework.Context) { 85 if bytes.Equal(ctx.Path(), metricsPath) { 86 return 87 } 88 ctx.SetUserValue(uvKey, gramework.Nanotime()) 89 } 90 91 func (m *Middleware) endReq(ctx *gramework.Context) { 92 if bytes.Equal(ctx.Path(), metricsPath) { 93 return 94 } 95 96 opts := []string{ 97 strconv.FormatInt(int64(ctx.Response.StatusCode()), 10), 98 string(ctx.Method()), 99 string(ctx.Path()), 100 typeHTTP, 101 } 102 103 if ctx.IsTLS() { 104 opts[3] = typeHTTPS 105 } 106 107 m.httpReqCounter.WithLabelValues(opts...).Add(1) 108 109 startTime, _ := ctx.UserValue(uvKey).(int64) 110 duration := float64(gramework.Nanotime()-startTime) / millisecond 111 112 m.reqDuration.WithLabelValues(opts...).Observe(duration) 113 }