Register prometheus Go and process collectors alongside the router metrics so /metrics exposes standard go_* and process_* series.
109 lines
3 KiB
Go
109 lines
3 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/collectors"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
)
|
|
|
|
const (
|
|
metricRequestsTotalName = "router_requests_total"
|
|
metricRoutingErrorsTotalName = "router_routing_errors_total"
|
|
metricUpstreamRequestsTotalName = "router_upstream_requests_total"
|
|
metricUpstreamDurationName = "router_upstream_duration_seconds"
|
|
)
|
|
|
|
type Metrics struct {
|
|
gatherer prometheus.Gatherer
|
|
requestsTotal *prometheus.CounterVec
|
|
routingErrorsTotal *prometheus.CounterVec
|
|
upstreamRequestsTotal *prometheus.CounterVec
|
|
upstreamDuration *prometheus.HistogramVec
|
|
}
|
|
|
|
func NewMetrics(reg prometheus.Registerer) *Metrics {
|
|
if reg == nil {
|
|
reg = prometheus.DefaultRegisterer
|
|
}
|
|
|
|
gatherer, ok := reg.(prometheus.Gatherer)
|
|
if !ok {
|
|
gatherer = prometheus.DefaultGatherer
|
|
}
|
|
|
|
reg.MustRegister(
|
|
collectors.NewGoCollector(),
|
|
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
|
|
)
|
|
|
|
m := &Metrics{
|
|
gatherer: gatherer,
|
|
requestsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
Name: metricRequestsTotalName,
|
|
Help: "Number of push requests routed to a backend.",
|
|
}, []string{"path", "platform"}),
|
|
routingErrorsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
Name: metricRoutingErrorsTotalName,
|
|
Help: "Number of push requests that failed before reaching a backend.",
|
|
}, []string{"reason"}),
|
|
upstreamRequestsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
Name: metricUpstreamRequestsTotalName,
|
|
Help: "Number of upstream proxy responses by outcome.",
|
|
}, []string{"platform", "outcome"}),
|
|
upstreamDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
|
Name: metricUpstreamDurationName,
|
|
Help: "Upstream proxy request latency in seconds.",
|
|
Buckets: prometheus.DefBuckets,
|
|
}, []string{"platform"}),
|
|
}
|
|
|
|
reg.MustRegister(
|
|
m.requestsTotal,
|
|
m.routingErrorsTotal,
|
|
m.upstreamRequestsTotal,
|
|
m.upstreamDuration,
|
|
)
|
|
|
|
return m
|
|
}
|
|
|
|
func (m *Metrics) Handler() http.Handler {
|
|
return promhttp.HandlerFor(m.gatherer, promhttp.HandlerOpts{})
|
|
}
|
|
|
|
func (m *Metrics) incRequest(path, platform string) {
|
|
m.requestsTotal.WithLabelValues(path, platform).Inc()
|
|
}
|
|
|
|
func (m *Metrics) incRoutingError(reason string) {
|
|
m.routingErrorsTotal.WithLabelValues(reason).Inc()
|
|
}
|
|
|
|
func (m *Metrics) observeUpstream(platform, outcome string, duration time.Duration) {
|
|
m.upstreamRequestsTotal.WithLabelValues(platform, outcome).Inc()
|
|
m.upstreamDuration.WithLabelValues(platform).Observe(duration.Seconds())
|
|
}
|
|
|
|
func routePathLabel(path string) string {
|
|
path = strings.TrimPrefix(path, "/api/v1/")
|
|
if path == "" {
|
|
return "unknown"
|
|
}
|
|
return path
|
|
}
|
|
|
|
func routingErrorReason(err error) string {
|
|
msg := err.Error()
|
|
switch {
|
|
case strings.HasPrefix(msg, "invalid JSON"):
|
|
return "invalid_json"
|
|
case strings.HasPrefix(msg, "missing platform"):
|
|
return "missing_platform"
|
|
default:
|
|
return "invalid_payload"
|
|
}
|
|
}
|