|
|
|
@ -89,40 +89,71 @@ func withStackTracer(h http.Handler, l log.Logger) http.Handler {
|
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
requestCounter = prometheus.NewCounterVec( |
|
|
|
|
prometheus.CounterOpts{ |
|
|
|
|
Name: "prometheus_http_requests_total", |
|
|
|
|
Help: "Counter of HTTP requests.", |
|
|
|
|
}, |
|
|
|
|
[]string{"handler", "code"}, |
|
|
|
|
) |
|
|
|
|
requestDuration = prometheus.NewHistogramVec( |
|
|
|
|
prometheus.HistogramOpts{ |
|
|
|
|
Name: "prometheus_http_request_duration_seconds", |
|
|
|
|
Help: "Histogram of latencies for HTTP requests.", |
|
|
|
|
Buckets: []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, |
|
|
|
|
}, |
|
|
|
|
[]string{"handler"}, |
|
|
|
|
) |
|
|
|
|
responseSize = prometheus.NewHistogramVec( |
|
|
|
|
prometheus.HistogramOpts{ |
|
|
|
|
Name: "prometheus_http_response_size_bytes", |
|
|
|
|
Help: "Histogram of response size for HTTP requests.", |
|
|
|
|
Buckets: prometheus.ExponentialBuckets(100, 10, 8), |
|
|
|
|
}, |
|
|
|
|
[]string{"handler"}, |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
type metrics struct { |
|
|
|
|
requestCounter *prometheus.CounterVec |
|
|
|
|
requestDuration *prometheus.HistogramVec |
|
|
|
|
responseSize *prometheus.HistogramVec |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func newMetrics(r prometheus.Registerer) *metrics { |
|
|
|
|
m := &metrics{ |
|
|
|
|
requestCounter: prometheus.NewCounterVec( |
|
|
|
|
prometheus.CounterOpts{ |
|
|
|
|
Name: "prometheus_http_requests_total", |
|
|
|
|
Help: "Counter of HTTP requests.", |
|
|
|
|
}, |
|
|
|
|
[]string{"handler", "code"}, |
|
|
|
|
), |
|
|
|
|
requestDuration: prometheus.NewHistogramVec( |
|
|
|
|
prometheus.HistogramOpts{ |
|
|
|
|
Name: "prometheus_http_request_duration_seconds", |
|
|
|
|
Help: "Histogram of latencies for HTTP requests.", |
|
|
|
|
Buckets: []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, |
|
|
|
|
}, |
|
|
|
|
[]string{"handler"}, |
|
|
|
|
), |
|
|
|
|
responseSize: prometheus.NewHistogramVec( |
|
|
|
|
prometheus.HistogramOpts{ |
|
|
|
|
Name: "prometheus_http_response_size_bytes", |
|
|
|
|
Help: "Histogram of response size for HTTP requests.", |
|
|
|
|
Buckets: prometheus.ExponentialBuckets(100, 10, 8), |
|
|
|
|
}, |
|
|
|
|
[]string{"handler"}, |
|
|
|
|
), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func init() { |
|
|
|
|
prometheus.MustRegister(requestCounter, requestDuration, responseSize) |
|
|
|
|
if r != nil { |
|
|
|
|
r.MustRegister(m.requestCounter, m.requestDuration, m.responseSize) |
|
|
|
|
} |
|
|
|
|
return m |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m *metrics) instrumentHandlerWithPrefix(prefix string) func(handlerName string, handler http.HandlerFunc) http.HandlerFunc { |
|
|
|
|
return func(handlerName string, handler http.HandlerFunc) http.HandlerFunc { |
|
|
|
|
return m.instrumentHandler(prefix+handlerName, handler) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m *metrics) instrumentHandler(handlerName string, handler http.HandlerFunc) http.HandlerFunc { |
|
|
|
|
return promhttp.InstrumentHandlerCounter( |
|
|
|
|
m.requestCounter.MustCurryWith(prometheus.Labels{"handler": handlerName}), |
|
|
|
|
promhttp.InstrumentHandlerDuration( |
|
|
|
|
m.requestDuration.MustCurryWith(prometheus.Labels{"handler": handlerName}), |
|
|
|
|
promhttp.InstrumentHandlerResponseSize( |
|
|
|
|
m.responseSize.MustCurryWith(prometheus.Labels{"handler": handlerName}), |
|
|
|
|
handler, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Handler serves various HTTP endpoints of the Prometheus server
|
|
|
|
|
type Handler struct { |
|
|
|
|
logger log.Logger |
|
|
|
|
|
|
|
|
|
gatherer prometheus.Gatherer |
|
|
|
|
metrics *metrics |
|
|
|
|
|
|
|
|
|
scrapeManager *scrape.Manager |
|
|
|
|
ruleManager *rules.Manager |
|
|
|
|
queryEngine *promql.Engine |
|
|
|
@ -197,41 +228,31 @@ type Options struct {
|
|
|
|
|
PageTitle string |
|
|
|
|
RemoteReadSampleLimit int |
|
|
|
|
RemoteReadConcurrencyLimit int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func instrumentHandlerWithPrefix(prefix string) func(handlerName string, handler http.HandlerFunc) http.HandlerFunc { |
|
|
|
|
return func(handlerName string, handler http.HandlerFunc) http.HandlerFunc { |
|
|
|
|
return instrumentHandler(prefix+handlerName, handler) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func instrumentHandler(handlerName string, handler http.HandlerFunc) http.HandlerFunc { |
|
|
|
|
return promhttp.InstrumentHandlerCounter( |
|
|
|
|
requestCounter.MustCurryWith(prometheus.Labels{"handler": handlerName}), |
|
|
|
|
promhttp.InstrumentHandlerDuration( |
|
|
|
|
requestDuration.MustCurryWith(prometheus.Labels{"handler": handlerName}), |
|
|
|
|
promhttp.InstrumentHandlerResponseSize( |
|
|
|
|
responseSize.MustCurryWith(prometheus.Labels{"handler": handlerName}), |
|
|
|
|
handler, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
) |
|
|
|
|
Gatherer prometheus.Gatherer |
|
|
|
|
Registerer prometheus.Registerer |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// New initializes a new web Handler.
|
|
|
|
|
func New(logger log.Logger, o *Options) *Handler { |
|
|
|
|
router := route.New().WithInstrumentation(instrumentHandler) |
|
|
|
|
cwd, err := os.Getwd() |
|
|
|
|
if logger == nil { |
|
|
|
|
logger = log.NewNopLogger() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m := newMetrics(o.Registerer) |
|
|
|
|
router := route.New().WithInstrumentation(m.instrumentHandler) |
|
|
|
|
|
|
|
|
|
cwd, err := os.Getwd() |
|
|
|
|
if err != nil { |
|
|
|
|
cwd = "<error retrieving current working directory>" |
|
|
|
|
} |
|
|
|
|
if logger == nil { |
|
|
|
|
logger = log.NewNopLogger() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
h := &Handler{ |
|
|
|
|
logger: logger, |
|
|
|
|
logger: logger, |
|
|
|
|
|
|
|
|
|
gatherer: o.Gatherer, |
|
|
|
|
metrics: m, |
|
|
|
|
|
|
|
|
|
router: router, |
|
|
|
|
quitCh: make(chan struct{}), |
|
|
|
|
reloadCh: make(chan chan error), |
|
|
|
@ -463,7 +484,7 @@ func (h *Handler) Run(ctx context.Context) error {
|
|
|
|
|
mux := http.NewServeMux() |
|
|
|
|
mux.Handle("/", h.router) |
|
|
|
|
|
|
|
|
|
av1 := route.New().WithInstrumentation(instrumentHandlerWithPrefix("/api/v1")) |
|
|
|
|
av1 := route.New().WithInstrumentation(h.metrics.instrumentHandlerWithPrefix("/api/v1")) |
|
|
|
|
h.apiV1.Register(av1) |
|
|
|
|
apiPath := "/api" |
|
|
|
|
if h.options.RoutePrefix != "/" { |
|
|
|
@ -649,7 +670,7 @@ func (h *Handler) status(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
status.StorageRetention = status.StorageRetention + h.options.TSDBCfg.MaxBytes.String() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
metrics, err := prometheus.DefaultGatherer.Gather() |
|
|
|
|
metrics, err := h.gatherer.Gather() |
|
|
|
|
if err != nil { |
|
|
|
|
http.Error(w, fmt.Sprintf("error gathering runtime status: %s", err), http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|