1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
13 "git.curoverse.com/arvados.git/sdk/go/stats"
14 "github.com/Sirupsen/logrus"
15 "github.com/gogo/protobuf/jsonpb"
16 "github.com/prometheus/client_golang/prometheus"
17 "github.com/prometheus/client_golang/prometheus/promhttp"
20 type Handler interface {
27 registry *prometheus.Registry
28 reqDuration *prometheus.SummaryVec
29 timeToStatus *prometheus.SummaryVec
30 exportProm http.Handler
33 func (*metrics) Levels() []logrus.Level {
34 return logrus.AllLevels
37 func (m *metrics) Fire(ent *logrus.Entry) error {
38 if tts, ok := ent.Data["timeToStatus"].(stats.Duration); !ok {
39 } else if method, ok := ent.Data["reqMethod"].(string); !ok {
40 } else if code, ok := ent.Data["respStatusCode"].(int); !ok {
42 m.timeToStatus.WithLabelValues(strconv.Itoa(code), strings.ToLower(method)).Observe(time.Duration(tts).Seconds())
47 func (m *metrics) exportJSON(w http.ResponseWriter, req *http.Request) {
48 jm := jsonpb.Marshaler{Indent: " "}
49 mfs, _ := m.registry.Gather()
51 for i, mf := range mfs {
60 func (m *metrics) ServeHTTP(w http.ResponseWriter, req *http.Request) {
62 case req.Method != "GET" && req.Method != "HEAD":
63 m.next.ServeHTTP(w, req)
64 case req.URL.Path == "/metrics.json":
66 case req.URL.Path == "/metrics":
67 m.exportProm.ServeHTTP(w, req)
69 m.next.ServeHTTP(w, req)
73 func Instrument(logger *logrus.Logger, next http.Handler) Handler {
75 logger = logrus.StandardLogger()
77 reqDuration := prometheus.NewSummaryVec(prometheus.SummaryOpts{
78 Name: "request_duration_seconds",
79 Help: "Summary of request duration.",
80 }, []string{"code", "method"})
81 timeToStatus := prometheus.NewSummaryVec(prometheus.SummaryOpts{
82 Name: "time_to_status_seconds",
83 Help: "Summary of request TTFB.",
84 }, []string{"code", "method"})
85 registry := prometheus.NewRegistry()
86 registry.MustRegister(timeToStatus)
87 registry.MustRegister(reqDuration)
89 next: promhttp.InstrumentHandlerDuration(reqDuration, next),
92 reqDuration: reqDuration,
93 timeToStatus: timeToStatus,
94 exportProm: promhttp.HandlerFor(registry, promhttp.HandlerOpts{