mirror of https://gitlab.com/ngerakines/tavern.git
97 lines
2.5 KiB
Go
97 lines
2.5 KiB
Go
package metrics
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
)
|
|
|
|
type MetricsMiddleware struct {
|
|
Requests *prometheus.CounterVec
|
|
TotalTime *prometheus.HistogramVec
|
|
RequestSize *prometheus.SummaryVec
|
|
ResponseSize *prometheus.SummaryVec
|
|
}
|
|
|
|
func NewMetricsMiddleware(namespace, subsystem string, metricFactory promauto.Factory) MetricsMiddleware {
|
|
return MetricsMiddleware{
|
|
Requests: metricFactory.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Namespace: namespace,
|
|
Subsystem: subsystem,
|
|
Name: "request_total",
|
|
Help: "Total number of HTTP Requests made.",
|
|
}, []string{"status", "endpoint", "method"},
|
|
),
|
|
TotalTime: metricFactory.NewHistogramVec(
|
|
prometheus.HistogramOpts{
|
|
Namespace: namespace,
|
|
Subsystem: subsystem,
|
|
Name: "request_duration",
|
|
Help: "HTTP request latencies in seconds.",
|
|
}, []string{"status", "endpoint", "method"},
|
|
),
|
|
RequestSize: metricFactory.NewSummaryVec(
|
|
prometheus.SummaryOpts{
|
|
Namespace: namespace,
|
|
Subsystem: subsystem,
|
|
Name: "request_size",
|
|
Help: "HTTP request sizes in bytes.",
|
|
}, []string{"status", "endpoint", "method"},
|
|
),
|
|
ResponseSize: metricFactory.NewSummaryVec(
|
|
prometheus.SummaryOpts{
|
|
Namespace: namespace,
|
|
Subsystem: subsystem,
|
|
Name: "response_size",
|
|
Help: "HTTP request sizes in bytes.",
|
|
}, []string{"status", "endpoint", "method"},
|
|
),
|
|
}
|
|
}
|
|
|
|
func (mm MetricsMiddleware) Handle(c *gin.Context) {
|
|
start := time.Now()
|
|
c.Next()
|
|
|
|
status := strconv.Itoa(c.Writer.Status())
|
|
endpoint := c.FullPath()
|
|
method := c.Request.Method
|
|
|
|
lvs := []string{status, endpoint, method}
|
|
|
|
mm.Requests.WithLabelValues(lvs...).Inc()
|
|
mm.TotalTime.WithLabelValues(lvs...).Observe(time.Since(start).Seconds())
|
|
mm.RequestSize.WithLabelValues(lvs...).Observe(CalcRequestSize(c.Request))
|
|
mm.ResponseSize.WithLabelValues(lvs...).Observe(float64(c.Writer.Size()))
|
|
}
|
|
|
|
// CalcRequestSize returns the size of request object.
|
|
func CalcRequestSize(r *http.Request) float64 {
|
|
size := 0
|
|
if r.URL != nil {
|
|
size = len(r.URL.String())
|
|
}
|
|
|
|
size += len(r.Method)
|
|
size += len(r.Proto)
|
|
|
|
for name, values := range r.Header {
|
|
size += len(name)
|
|
for _, value := range values {
|
|
size += len(value)
|
|
}
|
|
}
|
|
size += len(r.Host)
|
|
|
|
// r.Form and r.MultipartForm are assumed to be included in r.URL.
|
|
if r.ContentLength != -1 {
|
|
size += int(r.ContentLength)
|
|
}
|
|
return float64(size)
|
|
}
|