cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.15.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/range.go

99lines · modecode

1package promapi
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "strings"
8 "time"
9
10 v1 "github.com/prometheus/client_golang/api/prometheus/v1"
11 "github.com/prometheus/common/model"
12 "github.com/rs/zerolog/log"
13
14 "github.com/cloudflare/pint/internal/output"
15)
16
17type RangeQueryResult struct {
18 URI string
19 Samples []*model.SampleStream
20 Start time.Time
21 End time.Time
22 DurationSeconds float64
23}
24
25func (p *Prometheus) RangeQuery(ctx context.Context, expr string, start, end time.Time, step time.Duration) (*RangeQueryResult, error) {
26 log.Debug().
27 Str("uri", p.uri).
28 Str("query", expr).
29 Time("start", start).
30 Time("end", end).
31 Str("step", output.HumanizeDuration(step)).
32 Msg("Scheduling prometheus range query")
33
34 lockKey := "/api/v1/query/range"
35 p.lock.lock(lockKey)
36
37 cacheKey := strings.Join([]string{expr, start.String(), end.String(), step.String()}, "\n")
38 if v, ok := p.cache.Get(cacheKey); ok {
39 log.Debug().Str("key", cacheKey).Str("uri", p.uri).Msg("Range query cache hit")
40 r := v.(RangeQueryResult)
41 p.lock.unlock((lockKey))
42 return &r, nil
43 }
44
45 rctx, cancel := context.WithTimeout(ctx, p.timeout)
46 defer cancel()
47
48 prometheusQueriesTotal.WithLabelValues(p.name, "/api/v1/query_range").Inc()
49 r := v1.Range{
50 Start: start,
51 End: end,
52 Step: step,
53 }
54 qstart := time.Now()
55 result, _, err := p.api.QueryRange(rctx, expr, r)
56 duration := time.Since(qstart)
57 p.lock.unlock((lockKey))
58 log.Debug().
59 Str("uri", p.uri).
60 Str("query", expr).
61 Str("duration", output.HumanizeDuration(duration)).
62 Msg("Range query completed")
63 if err != nil {
64 log.Error().Err(err).Str("uri", p.uri).Str("query", expr).Msg("Range query failed")
65 prometheusQueryErrorsTotal.WithLabelValues(p.name, "/api/v1/query_range", errReason(err)).Inc()
66 if delta, retryOK := CanRetryError(err, end.Sub(start)); retryOK {
67 if delta < step*2 {
68 log.Error().Str("uri", p.uri).Str("query", expr).Msg("No more retries possible")
69 return nil, errors.New("no more retries possible")
70 }
71 log.Warn().Str("delta", output.HumanizeDuration(delta)).Msg("Retrying request with smaller range")
72 return p.RangeQuery(ctx, expr, start.Add(delta), end, step)
73 }
74 return nil, err
75 }
76
77 qr := RangeQueryResult{
78 URI: p.uri,
79 DurationSeconds: duration.Seconds(),
80 Start: start,
81 End: end,
82 }
83
84 switch result.Type() {
85 case model.ValMatrix:
86 samples := result.(model.Matrix)
87 qr.Samples = samples
88 default:
89 log.Error().Err(err).Str("uri", p.uri).Str("query", expr).Msgf("Range query returned unknown result type: %v", result.Type())
90 prometheusQueryErrorsTotal.WithLabelValues(p.name, "/api/v1/query_range", "unknown result type").Inc()
91 return nil, fmt.Errorf("unknown result type: %v", result.Type())
92 }
93 log.Debug().Str("uri", p.uri).Str("query", expr).Int("samples", len(qr.Samples)).Msg("Parsed range response")
94
95 log.Debug().Str("query", expr).Str("uri", p.uri).Msg("Range query cache miss")
96 p.cache.Add(cacheKey, qr)
97
98 return &qr, nil
99}
100