diff --git a/services/proxy/pkg/command/server.go b/services/proxy/pkg/command/server.go index fc8d9225d..e917f0ef5 100644 --- a/services/proxy/pkg/command/server.go +++ b/services/proxy/pkg/command/server.go @@ -130,7 +130,7 @@ func Server(cfg *config.Config) *cli.Command { } { - middlewares := loadMiddlewares(ctx, logger, cfg, userInfoCache, traceProvider) + middlewares := loadMiddlewares(ctx, logger, cfg, userInfoCache, traceProvider, *m) server, err := proxyHTTP.Server( proxyHTTP.Handler(lh.handler()), proxyHTTP.Logger(logger), @@ -271,7 +271,7 @@ func (h *StaticRouteHandler) backchannelLogout(w http.ResponseWriter, r *http.Re render.JSON(w, r, nil) } -func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, userInfoCache microstore.Store, traceProvider trace.TracerProvider) alice.Chain { +func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, userInfoCache microstore.Store, traceProvider trace.TracerProvider, metrics metrics.Metrics) alice.Chain { rolesClient := settingssvc.NewRoleService("com.owncloud.api.settings", cfg.GrpcClient) policiesProviderClient := policiessvc.NewPoliciesProviderService("com.owncloud.api.policies", cfg.GrpcClient) gatewaySelector, err := pool.GatewaySelector( @@ -386,6 +386,7 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, ), middleware.Tracer(traceProvider), pkgmiddleware.TraceContext, + middleware.Instrumenter(metrics), chimiddleware.RealIP, chimiddleware.RequestID, middleware.AccessLog(logger), diff --git a/services/proxy/pkg/metrics/metrics.go b/services/proxy/pkg/metrics/metrics.go index a14e94925..fe56a9ef7 100644 --- a/services/proxy/pkg/metrics/metrics.go +++ b/services/proxy/pkg/metrics/metrics.go @@ -14,8 +14,8 @@ var ( // Metrics defines the available metrics of this service. type Metrics struct { - Counter *prometheus.CounterVec - Latency *prometheus.SummaryVec + Requests *prometheus.CounterVec + Errors *prometheus.CounterVec Duration *prometheus.HistogramVec BuildInfo *prometheus.GaugeVec } @@ -23,24 +23,24 @@ type Metrics struct { // New initializes the available metrics. func New() *Metrics { m := &Metrics{ - Counter: prometheus.NewCounterVec(prometheus.CounterOpts{ + Requests: prometheus.NewCounterVec(prometheus.CounterOpts{ Namespace: Namespace, Subsystem: Subsystem, - Name: "proxy_total", - Help: "How many proxy requests processed", - }, []string{}), - Latency: prometheus.NewSummaryVec(prometheus.SummaryOpts{ + Name: "requests_total", + Help: "How many requests processed in total", + }, []string{"method"}), + Errors: prometheus.NewCounterVec(prometheus.CounterOpts{ Namespace: Namespace, Subsystem: Subsystem, - Name: "proxy_latency_microseconds", - Help: "proxy request latencies in microseconds", - }, []string{}), + Name: "errors_total", + Help: "How many requests run into errors", + }, []string{"method"}), Duration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ Namespace: Namespace, Subsystem: Subsystem, - Name: "proxy_duration_seconds", - Help: "proxy method request time in seconds", - }, []string{}), + Name: "duration_seconds", + Help: "request duration in seconds", + }, []string{"method"}), BuildInfo: prometheus.NewGaugeVec(prometheus.GaugeOpts{ Namespace: Namespace, Subsystem: Subsystem, @@ -49,8 +49,8 @@ func New() *Metrics { }, []string{"versions"}), } - _ = prometheus.Register(m.Counter) - _ = prometheus.Register(m.Latency) + _ = prometheus.Register(m.Requests) + _ = prometheus.Register(m.Errors) _ = prometheus.Register(m.Duration) _ = prometheus.Register(m.BuildInfo) return m diff --git a/services/proxy/pkg/middleware/metrics.go b/services/proxy/pkg/middleware/metrics.go new file mode 100644 index 000000000..186a180a0 --- /dev/null +++ b/services/proxy/pkg/middleware/metrics.go @@ -0,0 +1,28 @@ +package middleware + +import ( + "net/http" + "time" + + "github.com/go-chi/chi/v5/middleware" + "github.com/owncloud/ocis/v2/services/proxy/pkg/metrics" + "github.com/prometheus/client_golang/prometheus" +) + +// Instrumenter provides a middleware to create metrics +func Instrumenter(m metrics.Metrics) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) + m.Requests.With(prometheus.Labels{"method": r.Method}).Inc() + + next.ServeHTTP(ww, r) + + m.Duration.With(prometheus.Labels{"method": r.Method}).Observe(float64(time.Since(start).Seconds())) + if ww.Status() >= 500 { + m.Errors.With(prometheus.Labels{"method": r.Method}).Inc() + } + }) + } +}