-
Notifications
You must be signed in to change notification settings - Fork 455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add default Prometheus query range route for Grafana integration #877
Changes from all commits
e864559
94edefa
90f6a88
5bd0ccd
bd9b238
0e42391
da8f2b3
6ce2735
f4c17ba
8c7f241
b90bb5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ | |
|
||
* **URL** | ||
|
||
/prom/native/read | ||
/query_range | ||
|
||
* **Method:** | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,13 +10,14 @@ m3port="localhost:7201" | |
promport="localhost:9090" | ||
curl -fsS $promport/status > /dev/null || { echo "Prom port not open"; exit 1; } | ||
curl -fsS $m3port/health > /dev/null || { echo "M3Query port not open"; exit 1; } | ||
m3command="$m3port/api/v1/prom/native/read?start=$start&end=$end&step=$step&debug=true --data-urlencode target=$target" | ||
promcommand="$promport/api/v1/query_range?start=$start&end=$end&step=$step --data-urlencode query=$target" | ||
echo $m3command | ||
echo $promcommand | ||
curl -G $m3command > m3out | ||
curl -G $promcommand > promout | ||
jq ".[]|.tags,.datapoints" m3out > m3result | ||
queryurl="/api/v1/query_range?start=$start&end=$end&step=$step --data-urlencode query=$target" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sweet! |
||
m3url="$m3port/$queryurl" | ||
promurl="$promport/$queryurl" | ||
echo $m3url | ||
echo $promurl | ||
curl -G $m3url > m3out | ||
curl -G $promurl > promout | ||
jq ".data.result|.[]|.metric,.values" m3out > m3result | ||
jq ".data.result|.[]|.metric,.values" promout > promresult | ||
echo "M3 file size" $(stat -f%z m3result) | ||
echo "Prom file size" $(stat -f%z promresult) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,7 @@ import ( | |
const ( | ||
endParam = "end" | ||
startParam = "start" | ||
targetParam = "target" | ||
queryParam = "query" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this going to work fine for the prometheus remote read end point? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wait, this is the native end point, not the remote read one. Never mind! |
||
stepParam = "step" | ||
debugParam = "debug" | ||
endExclusiveParam = "end-exclusive" | ||
|
@@ -61,11 +61,22 @@ func parseTime(r *http.Request, key string) (time.Time, error) { | |
|
||
// nolint: unparam | ||
func parseDuration(r *http.Request, key string) (time.Duration, error) { | ||
if d := r.FormValue(key); d != "" { | ||
return time.ParseDuration(d) | ||
str := r.FormValue(key) | ||
if str == "" { | ||
return 0, errors.ErrNotFound | ||
} | ||
|
||
return 0, errors.ErrNotFound | ||
value, err := time.ParseDuration(str) | ||
if err == nil { | ||
return value, nil | ||
} | ||
|
||
// Try parsing as an integer value specifying seconds, the Prometheus default | ||
if seconds, intErr := strconv.ParseInt(str, 10, 64); intErr == nil { | ||
return time.Duration(seconds) * time.Second, nil | ||
} | ||
|
||
return 0, err | ||
} | ||
|
||
// parseParams parses all params from the GET request | ||
|
@@ -98,11 +109,11 @@ func parseParams(r *http.Request) (models.RequestParams, *handler.ParseError) { | |
} | ||
params.Step = step | ||
|
||
target, err := parseTarget(r) | ||
query, err := parseQuery(r) | ||
if err != nil { | ||
return params, handler.NewParseError(fmt.Errorf(formatErrStr, targetParam, err), http.StatusBadRequest) | ||
return params, handler.NewParseError(fmt.Errorf(formatErrStr, queryParam, err), http.StatusBadRequest) | ||
} | ||
params.Target = target | ||
params.Query = query | ||
|
||
// Skip debug if unable to parse debug param | ||
debugVal := r.FormValue(debugParam) | ||
|
@@ -129,47 +140,57 @@ func parseParams(r *http.Request) (models.RequestParams, *handler.ParseError) { | |
return params, nil | ||
} | ||
|
||
func parseTarget(r *http.Request) (string, error) { | ||
targetQueries, ok := r.URL.Query()[targetParam] | ||
if !ok || len(targetQueries) == 0 || targetQueries[0] == "" { | ||
return "", errors.ErrNoTargetFound | ||
func parseQuery(r *http.Request) (string, error) { | ||
queries, ok := r.URL.Query()[queryParam] | ||
if !ok || len(queries) == 0 || queries[0] == "" { | ||
return "", errors.ErrNoQueryFound | ||
} | ||
|
||
// TODO: currently, we only support one target at a time | ||
if len(targetQueries) > 1 { | ||
if len(queries) > 1 { | ||
return "", errors.ErrBatchQuery | ||
} | ||
|
||
return targetQueries[0], nil | ||
return queries[0], nil | ||
} | ||
|
||
func renderResultsJSON(w io.Writer, series []*ts.Series, params models.RequestParams) { | ||
startIdx := 0 | ||
jw := json.NewWriter(w) | ||
jw.BeginObject() | ||
|
||
jw.BeginObjectField("status") | ||
jw.WriteString("success") | ||
|
||
jw.BeginObjectField("data") | ||
jw.BeginObject() | ||
|
||
jw.BeginObjectField("resultType") | ||
jw.WriteString("matrix") | ||
|
||
jw.BeginObjectField("result") | ||
jw.BeginArray() | ||
for _, s := range series { | ||
jw.BeginObject() | ||
jw.BeginObjectField("target") | ||
jw.WriteString(s.Name()) | ||
|
||
jw.BeginObjectField("tags") | ||
jw.BeginObjectField("metric") | ||
jw.BeginObject() | ||
for _, t := range s.Tags { | ||
jw.BeginObjectField(t.Name) | ||
jw.WriteString(t.Value) | ||
} | ||
jw.EndObject() | ||
|
||
jw.BeginObjectField("datapoints") | ||
jw.BeginObjectField("values") | ||
jw.BeginArray() | ||
vals := s.Values() | ||
for i := startIdx; i < s.Len(); i++ { | ||
length := s.Len() | ||
for i := 0; i < length; i++ { | ||
dp := vals.DatapointAt(i) | ||
// Skip points before the query boundary. Ideal place to adjust these would be at the result node but that would make it inefficient | ||
// since we would need to create another block just for the sake of restricting the bounds. | ||
// Each series have the same start time so we just need to calculate the correct startIdx once | ||
// NB(r): Removing the optimization of computing startIdx once just in case our assumptions are wrong, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit odd that you're seeing more points after deleting this. Might bear further investigation to see where our assumptions go bad |
||
// we can always add this optimization back later. Without this code I see datapoints more often. | ||
if dp.Timestamp.Before(params.Start) { | ||
startIdx = i + 1 | ||
continue | ||
} | ||
|
||
|
@@ -183,11 +204,14 @@ func renderResultsJSON(w io.Writer, series []*ts.Series, params models.RequestPa | |
fixedStep, ok := s.Values().(ts.FixedResolutionMutableValues) | ||
if ok { | ||
jw.BeginObjectField("step_size_ms") | ||
jw.WriteInt(int(util.DurationToMS(fixedStep.MillisPerStep()))) | ||
jw.WriteInt(int(fixedStep.Resolution() / time.Millisecond)) | ||
jw.EndObject() | ||
} | ||
} | ||
|
||
jw.EndArray() | ||
|
||
jw.EndObject() | ||
|
||
jw.EndObject() | ||
jw.Close() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you also want to test m3query directly ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do, I'm going to do this in a follow up change if that's ok - its not trivial.