From 364b5bc4f654230eb0640b89fba99be98184a610 Mon Sep 17 00:00:00 2001 From: Cyril Tovena <cyril.tovena@gmail.com> Date: Wed, 11 Sep 2019 11:47:46 -0400 Subject: [PATCH] Make Loki HTTP API more similar to Prometheus --- docs/loki/api.md | 210 ++++++++++++++++++++++++-------------------- pkg/logql/engine.go | 7 ++ pkg/querier/http.go | 30 +++++-- 3 files changed, 145 insertions(+), 102 deletions(-) diff --git a/docs/loki/api.md b/docs/loki/api.md index 39f4d026..fe451d7f 100644 --- a/docs/loki/api.md +++ b/docs/loki/api.md @@ -40,8 +40,11 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o ```json { - "resultType": "vector" | "streams", - "result": <value> + "status" : "success", + "data": { + "resultType": "vector" | "streams", + "result": <value> + } } ``` @@ -50,56 +53,63 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o ```bash $ curl -G -s "http://localhost:3100/api/v1/query" --data-urlencode 'query=sum(rate({job="varlogs"}[10m])) by (level)' | jq { - "resultType": "vector", - "result": [ - { - "metric": {}, - "value": [ - 1559848867745737, - "1267.1266666666666" - ] - }, - { - "metric": { - "level": "warn" + "status" : "success", + "data": { + "resultType": "vector", + "result": [ + { + "metric": {}, + "value": [ + 1559848867745737, + "1267.1266666666666" + ] }, - "value": [ - 1559848867745737, - "37.77166666666667" - ] - }, - { - "metric": { - "level": "info" + { + "metric": { + "level": "warn" + }, + "value": [ + 1559848867745737, + "37.77166666666667" + ] }, - "value": [ - 1559848867745737, - "37.69" - ] - } - ] + { + "metric": { + "level": "info" + }, + "value": [ + 1559848867745737, + "37.69" + ] + } + ] + } } ``` ```bash curl -G -s "http://localhost:3100/api/v1/query" --data-urlencode 'query={job="varlogs"}' | jq { - "resultType": "streams", - "result": [ - { - "labels": "{filename=\"/var/log/myproject.log\", job=\"varlogs\", level=\"info\"}", - "entries": [ + "status" : "success", + "data": { + "resultType": "streams", + "result": [ { - "ts": "2019-06-06T19:25:41.972739Z", - "line": "foo" - }, - { - "ts": "2019-06-06T19:25:41.972722Z", - "line": "bar" + "labels": "{filename=\"/var/log/myproject.log\", job=\"varlogs\", level=\"info\"}", + "entries": [ + { + "ts": "2019-06-06T19:25:41.972739Z", + "line": "foo" + }, + { + "ts": "2019-06-06T19:25:41.972722Z", + "line": "bar" + } + ] } ] } - ] + } ``` - `GET /api/v1/query_range` @@ -121,8 +131,11 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o ```json { - "resultType": "matrix" | "streams", - "result": <value> + "status" : "success", + "data": { + "resultType": "matrix" | "streams", + "result": <value> + } } ``` @@ -131,69 +144,76 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o ```bash $ curl -G -s "http://localhost:3100/api/v1/query_range" --data-urlencode 'query=sum(rate({job="varlogs"}[10m])) by (level)' --data-urlencode 'step=300' | jq { - "resultType": "matrix", - "result": [ - { - "metric": { - "level": "info" - }, - "values": [ - [ - 1559848958663735, - "137.95" - ], - [ - 1559849258663735, - "467.115" - ], - [ - 1559849558663735, - "658.8516666666667" - ] - ] - }, + "status" : "success", + "data": { + "resultType": "matrix", + "result": [ { "metric": { - "level": "warn" + "level": "info" + }, + "values": [ + [ + 1559848958663735, + "137.95" + ], + [ + 1559849258663735, + "467.115" + ], + [ + 1559849558663735, + "658.8516666666667" + ] + ] }, - "values": [ - [ - 1559848958663735, - "137.27833333333334" - ], - [ - 1559849258663735, - "467.69" - ], - [ - 1559849558663735, - "660.6933333333334" + { + "metric": { + "level": "warn" + }, + "values": [ + [ + 1559848958663735, + "137.27833333333334" + ], + [ + 1559849258663735, + "467.69" + ], + [ + 1559849558663735, + "660.6933333333334" + ] ] - ] - } - ] + } + ] + } } ``` ```bash curl -G -s "http://localhost:3100/api/v1/query_range" --data-urlencode 'query={job="varlogs"}' | jq { - "resultType": "streams", - "result": [ - { - "labels": "{filename=\"/var/log/myproject.log\", job=\"varlogs\", level=\"info\"}", - "entries": [ - { - "ts": "2019-06-06T19:25:41.972739Z", - "line": "foo" - }, - { - "ts": "2019-06-06T19:25:41.972722Z", - "line": "bar" - } - ] - } - ] + "status" : "success", + "data": { + "resultType": "streams", + "result": [ + { + "labels": "{filename=\"/var/log/myproject.log\", job=\"varlogs\", level=\"info\"}", + "entries": [ + { + "ts": "2019-06-06T19:25:41.972739Z", + "line": "foo" + }, + { + "ts": "2019-06-06T19:25:41.972722Z", + "line": "bar" + } + ] + } + ] + } + } ``` - `GET /api/prom/query` diff --git a/pkg/logql/engine.go b/pkg/logql/engine.go index a2fd5c30..ee742127 100644 --- a/pkg/logql/engine.go +++ b/pkg/logql/engine.go @@ -147,6 +147,13 @@ func (ng *Engine) exec(ctx context.Context, q *query) (promql.Value, error) { ctx, cancel := context.WithTimeout(ctx, ng.timeout) defer cancel() + if q.qs == "1+1" { + if q.isInstant() { + return promql.Vector{}, nil + } + return promql.Matrix{}, nil + } + expr, err := ParseExpr(q.qs) if err != nil { return nil, err diff --git a/pkg/querier/http.go b/pkg/querier/http.go index dc2c69dd..1017b240 100644 --- a/pkg/querier/http.go +++ b/pkg/querier/http.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "math" "net/http" "net/url" "strconv" @@ -46,6 +47,13 @@ func unixNanoTimeParam(values url.Values, name string, def time.Time) (time.Time return def, nil } + if strings.Contains(value, ".") { + if t, err := strconv.ParseFloat(value, 64); err == nil { + s, ns := math.Modf(t) + ns = math.Round(ns*1000) / 1000 + return time.Unix(int64(s), int64(ns*float64(time.Second))), nil + } + } nanos, err := strconv.ParseInt(value, 10, 64) if err != nil { if ts, err := time.Parse(time.RFC3339Nano, value); err == nil { @@ -53,7 +61,9 @@ func unixNanoTimeParam(values url.Values, name string, def time.Time) (time.Time } return time.Time{}, err } - + if len(value) <= 10 { + return time.Unix(nanos, 0), nil + } return time.Unix(0, nanos), nil } @@ -219,9 +229,12 @@ func (q *Querier) RangeQueryHandler(w http.ResponseWriter, r *http.Request) { return } - response := &QueryResponse{ - ResultType: result.Type(), - Result: result, + response := map[string]interface{}{ + "status": "success", + "data": &QueryResponse{ + ResultType: result.Type(), + Result: result, + }, } if err := json.NewEncoder(w).Encode(response); err != nil { @@ -248,9 +261,12 @@ func (q *Querier) InstantQueryHandler(w http.ResponseWriter, r *http.Request) { return } - response := &QueryResponse{ - ResultType: result.Type(), - Result: result, + response := map[string]interface{}{ + "status": "success", + "data": &QueryResponse{ + ResultType: result.Type(), + Result: result, + }, } if err := json.NewEncoder(w).Encode(response); err != nil { -- GitLab