Files
2026-09-15 21:27:46 +05:00

93 lines
2.3 KiB
Go

package metrics
import (
"time"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/ThreeDotsLabs/watermill/message"
)
var (
handlerLabelKeys = []string{
labelKeyHandlerName,
labelSuccess,
}
// defaultHandlerExecutionTimeBuckets are one order of magnitude smaller than default buckets (5ms~10s),
// because the handler execution times are typically shorter (µs~ms range).
defaultHandlerExecutionTimeBuckets = []float64{
0.0005,
0.001,
0.0025,
0.005,
0.01,
0.025,
0.05,
0.1,
0.25,
0.5,
1,
}
)
// HandlerPrometheusMetricsMiddleware is a middleware that captures Prometheus metrics.
type HandlerPrometheusMetricsMiddleware struct {
handlerExecutionTimeSeconds *prometheus.HistogramVec
additionalLabels []MetricLabel
}
// Middleware returns the middleware ready to be used with watermill's Router.
func (m HandlerPrometheusMetricsMiddleware) Middleware(h message.HandlerFunc) message.HandlerFunc {
return func(msg *message.Message) (msgs []*message.Message, err error) {
now := time.Now()
ctx := msg.Context()
labels := prometheus.Labels{
labelKeyHandlerName: message.HandlerNameFromCtx(ctx),
}
for _, lb := range m.additionalLabels {
labels[lb.Label] = lb.ComputeValueFn(ctx)
}
defer func() {
if err != nil {
labels[labelSuccess] = "false"
} else {
labels[labelSuccess] = "true"
}
m.handlerExecutionTimeSeconds.With(labels).Observe(time.Since(now).Seconds())
}()
return h(msg)
}
}
// NewRouterMiddleware returns new middleware.
func (b PrometheusMetricsBuilder) NewRouterMiddleware() HandlerPrometheusMetricsMiddleware {
var err error
m := HandlerPrometheusMetricsMiddleware{
additionalLabels: b.additionalLabels,
}
if b.HandlerBuckets == nil {
b.HandlerBuckets = defaultHandlerExecutionTimeBuckets
}
m.handlerExecutionTimeSeconds, err = b.registerHistogramVec(prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: b.Namespace,
Subsystem: b.Subsystem,
Name: "handler_execution_time_seconds",
Help: "The total time elapsed while executing the handler function in seconds",
Buckets: b.HandlerBuckets,
},
toLabelsSlice(handlerLabelKeys, b.additionalLabels),
))
if err != nil {
panic(errors.Wrap(err, "could not register handler execution time metric"))
}
return m
}