From 3483b0ffaea3e1a2b4ee6e4959f7a2190136fef5 Mon Sep 17 00:00:00 2001 From: Ken Hibino Date: Tue, 30 Nov 2021 07:06:26 -0800 Subject: [PATCH] WIP: (api): Update metrics handler to take options --- handler.go | 2 +- metrics_handler.go | 60 ++++++++++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/handler.go b/handler.go index 350f12a..542bb28 100644 --- a/handler.go +++ b/handler.go @@ -188,7 +188,7 @@ func muxRouter(opts Options, rc redis.UniversalClient, inspector *asynq.Inspecto } // Time series metrics endpoints. - api.HandleFunc("/metrics", newGetMetricsHandlerFunc(http.DefaultClient)).Methods("GET") + api.HandleFunc("/metrics", newGetMetricsHandlerFunc(http.DefaultClient, opts.PrometheusAddress)).Methods("GET") // Everything else, route to uiAssetsHandler. router.NotFoundHandler = &uiAssetsHandler{ diff --git a/metrics_handler.go b/metrics_handler.go index 337f49c..41baed3 100644 --- a/metrics_handler.go +++ b/metrics_handler.go @@ -14,29 +14,21 @@ type getMetricsResponse struct { // TODO } -func unixTimeString(t time.Time) string { - return strconv.Itoa(int(t.Unix())) +type metricsFetchOptions struct { + // Specifies the number of seconds to scan for metrics. + duration time.Duration + + // Specifies the end time when fetching metrics. + endTime time.Time } -func newGetMetricsHandlerFunc(client *http.Client) http.HandlerFunc { +func newGetMetricsHandlerFunc(client *http.Client, prometheusAddr string) http.HandlerFunc { + // Optional query params: + // `duration_sec`: specifies the number of seconds to scan + // `end_time`: specifies the end_time in Unix time seconds return func(w http.ResponseWriter, r *http.Request) { - const ( - baseAddr = "http://localhost:9090" - apiPath = "/api/v1/query_range" - promQL = "asynq_queue_size" - ) - var b strings.Builder - v := url.Values{} - b.WriteString(baseAddr) - b.WriteString(apiPath) - v.Add("query", promQL) - now := time.Now() - v.Add("start", unixTimeString(now.Add(-30*time.Minute))) - v.Add("end", unixTimeString(now)) - v.Add("step", (1 * time.Minute).String()) - b.WriteString("?") - b.WriteString(v.Encode()) - url := b.String() + opts := extractMetricsFetchOptions(r) + url := buildPrometheusURL(prometheusAddr, "asynq_queue_size", opts) fmt.Printf("DEBUG: url: %s\n", url) resp, err := client.Get(url) if err != nil { @@ -50,3 +42,31 @@ func newGetMetricsHandlerFunc(client *http.Client) http.HandlerFunc { } } } + +const prometheusAPIPath = "/api/v1/query_range" + +func extractMetricsFetchOptions(r *http.Request) *metricsFetchOptions { + // TODO: Extract these options from the request if any, and default to these values if none are specified + return &metricsFetchOptions{ + duration: 60 * time.Minute, + endTime: time.Now(), + } +} + +func buildPrometheusURL(baseAddr, promQL string, opts *metricsFetchOptions) string { + var b strings.Builder + b.WriteString(strings.TrimSuffix(baseAddr, "/")) + b.WriteString(prometheusAPIPath) + v := url.Values{} + v.Add("query", promQL) + v.Add("start", unixTimeString(opts.endTime.Add(-opts.duration))) + v.Add("end", unixTimeString(opts.endTime)) + v.Add("step", (1 * time.Minute).String()) + b.WriteString("?") + b.WriteString(v.Encode()) + return b.String() +} + +func unixTimeString(t time.Time) string { + return strconv.Itoa(int(t.Unix())) +}