// Query handles the /api/query endpoint. func (api *API) Query(w http.ResponseWriter, r *http.Request) { setAccessControlHeaders(w) w.Header().Set("Content-Type", "application/json") params := httputil.GetQueryParams(r) expr := params.Get("expr") timestamp, err := parseTimestampOrNow(params.Get("timestamp"), api.Now()) if err != nil { httpJSONError(w, fmt.Errorf("invalid query timestamp %s", err), http.StatusBadRequest) return } query, err := api.QueryEngine.NewInstantQuery(expr, timestamp) if err != nil { httpJSONError(w, err, http.StatusOK) return } res := query.Exec() if res.Err != nil { httpJSONError(w, res.Err, http.StatusOK) return } log.Debugf("Instant query: %s\nQuery stats:\n%s\n", expr, query.Stats()) httputil.RespondJSON(w, res.Value) }
// QueryRange handles the /api/query_range endpoint. func (api *API) QueryRange(w http.ResponseWriter, r *http.Request) { setAccessControlHeaders(w) w.Header().Set("Content-Type", "application/json") params := httputil.GetQueryParams(r) expr := params.Get("expr") duration, err := parseDuration(params.Get("range")) if err != nil { httpJSONError(w, fmt.Errorf("invalid query range: %s", err), http.StatusBadRequest) return } step, err := parseDuration(params.Get("step")) if err != nil { httpJSONError(w, fmt.Errorf("invalid query resolution: %s", err), http.StatusBadRequest) return } end, err := parseTimestampOrNow(params.Get("end"), api.Now()) if err != nil { httpJSONError(w, fmt.Errorf("invalid query timestamp: %s", err), http.StatusBadRequest) return } // TODO(julius): Remove this special-case handling a while after PromDash and // other API consumers have been changed to no longer set "end=0" for setting // the current time as the end time. Instead, the "end" parameter should // simply be omitted or set to an empty string for that case. if end == 0 { end = api.Now() } // For safety, limit the number of returned points per timeseries. // This is sufficient for 60s resolution for a week or 1h resolution for a year. if duration/step > 11000 { err := errors.New("exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)") httpJSONError(w, err, http.StatusBadRequest) return } // Align the start to step "tick" boundary. end = end.Add(-time.Duration(end.UnixNano() % int64(step))) start := end.Add(-duration) query, err := api.QueryEngine.NewRangeQuery(expr, start, end, step) if err != nil { httpJSONError(w, err, http.StatusOK) return } matrix, err := query.Exec().Matrix() if err != nil { httpJSONError(w, err, http.StatusOK) return } log.Debugf("Range query: %s\nQuery stats:\n%s\n", expr, query.Stats()) httputil.RespondJSON(w, matrix) }