package metric import ( "strconv" "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" ) const ( favicon = "/favicon.ico" ) // Prometheus contains the metrics gathered by the instance and its path type Prometheus struct { reqCnt *prometheus.CounterVec reqDur *prometheus.HistogramVec } // NewPrometheus generates a new set of metrics with a certain subsystem name func NewPrometheus() (*Prometheus, error) { reqCnt := prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: namespaceAPI, Name: "requests_total", Help: "How many HTTP requests processed, partitioned by status code and HTTP method", }, []string{"code", "method", "path"}, ) if err := registerCollector(reqCnt); err != nil { return nil, err } reqDur := prometheus.NewHistogramVec( prometheus.HistogramOpts{ Namespace: namespaceAPI, Name: "request_duration_seconds", Help: "The HTTP request latencies in seconds", }, []string{"code", "method", "path"}, ) if err := registerCollector(reqDur); err != nil { return nil, err } return &Prometheus{ reqCnt: reqCnt, reqDur: reqDur, }, nil } // PrometheusMiddleware creates the prometheus collector and // defines status handler function for the middleware func PrometheusMiddleware() (gin.HandlerFunc, error) { p, err := NewPrometheus() if err != nil { return nil, err } return p.Middleware(), nil } // Middleware defines status handler function for middleware func (p *Prometheus) Middleware() gin.HandlerFunc { return func(c *gin.Context) { if c.Request.URL.Path == favicon { c.Next() return } start := time.Now() c.Next() status := strconv.Itoa(c.Writer.Status()) elapsed := float64(time.Since(start)) / float64(time.Second) fullPath := c.FullPath() p.reqDur.WithLabelValues(status, c.Request.Method, fullPath).Observe(elapsed) p.reqCnt.WithLabelValues(status, c.Request.Method, fullPath).Inc() } }