cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.15.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/promapi/range.go

113lines · 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 prometheusQueriesTotal.WithLabelValues(p.name, "/api/v1/query_range").Inc()
46 r := v1.Range{
47 Start: start,
48 End: end,
49 Step: step,
50 }
51
52 p.slowQueryLock.Lock()
53 if v, ok := p.slowQueryCache.Get(expr); ok {
54 log.Debug().
55 Str("query", expr).
56 Str("delta", output.HumanizeDuration(v.(time.Duration))).
57 Msg("Got cached slow query delta")
58 r.Start.Add(v.(time.Duration))
59 }
60 p.slowQueryLock.Unlock()
61
62 rctx, cancel := context.WithTimeout(ctx, p.timeout)
63 defer cancel()
64
65 qstart := time.Now()
66 result, _, err := p.api.QueryRange(rctx, expr, r)
67 duration := time.Since(qstart)
68 p.lock.unlock((lockKey))
69 log.Debug().
70 Str("uri", p.uri).
71 Str("query", expr).
72 Str("duration", output.HumanizeDuration(duration)).
73 Msg("Range query completed")
74 if err != nil {
75 log.Error().Err(err).Str("uri", p.uri).Str("query", expr).Msg("Range query failed")
76 prometheusQueryErrorsTotal.WithLabelValues(p.name, "/api/v1/query_range", errReason(err)).Inc()
77 if delta, retryOK := CanRetryError(err, end.Sub(start)); retryOK {
78 if delta < step*2 {
79 log.Error().Str("uri", p.uri).Str("query", expr).Msg("No more retries possible")
80 return nil, errors.New("no more retries possible")
81 }
82 log.Warn().Str("delta", output.HumanizeDuration(delta)).Msg("Retrying request with smaller range")
83 p.slowQueryLock.Lock()
84 p.slowQueryCache.Add(expr, delta)
85 p.slowQueryLock.Unlock()
86 return p.RangeQuery(ctx, expr, start.Add(delta), end, step)
87 }
88 return nil, err
89 }
90
91 qr := RangeQueryResult{
92 URI: p.uri,
93 DurationSeconds: duration.Seconds(),
94 Start: start,
95 End: end,
96 }
97
98 switch result.Type() {
99 case model.ValMatrix:
100 samples := result.(model.Matrix)
101 qr.Samples = samples
102 default:
103 log.Error().Err(err).Str("uri", p.uri).Str("query", expr).Msgf("Range query returned unknown result type: %v", result.Type())
104 prometheusQueryErrorsTotal.WithLabelValues(p.name, "/api/v1/query_range", "unknown result type").Inc()
105 return nil, fmt.Errorf("unknown result type: %v", result.Type())
106 }
107 log.Debug().Str("uri", p.uri).Str("query", expr).Int("samples", len(qr.Samples)).Msg("Parsed range response")
108
109 log.Debug().Str("query", expr).Str("uri", p.uri).Msg("Range query cache miss")
110 p.cache.Add(cacheKey, qr)
111
112 return &qr, nil
113}
114