mirror of
https://github.com/hanzoai/metrics.git
synced 2026-10-30 20:03:39 +00:00
### Describe Your Changes Log when the data response from vmselect is partial during rule(recording, alertingrule) evaluations. vmselect returns `isPartial: true` in case data is not fully fetched from scattered vmstorages. At the time of rule evals, it may be drifting apart from real values due to missing points. This is an important event that should be logged to inform users to see how often that happens as it may lead to false positive alerts. ### Checklist The following checks are **mandatory**: - [x] My change adheres [VictoriaMetrics contributing guidelines](https://docs.victoriametrics.com/contributing/). --------- Signed-off-by: emreya <[email protected]> Signed-off-by: emreya <[email protected]> Signed-off-by: Emre Yazici <[email protected]> (cherry picked from commit 56f60e8be93af01089aef6f7976f006f92d613a5)
141 lines
3.4 KiB
Go
141 lines
3.4 KiB
Go
package datasource
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// FakeQuerier is a mock querier that return predefined results and error message
|
|
type FakeQuerier struct {
|
|
sync.Mutex
|
|
metrics []Metric
|
|
err error
|
|
isPartial *bool
|
|
}
|
|
|
|
// SetErr sets query error message
|
|
func (fq *FakeQuerier) SetErr(err error) {
|
|
fq.Lock()
|
|
fq.err = err
|
|
fq.Unlock()
|
|
}
|
|
|
|
// SetPartialResponse marks query response as partial
|
|
func (fq *FakeQuerier) SetPartialResponse(partial bool) {
|
|
fq.Lock()
|
|
fq.isPartial = &partial
|
|
fq.Unlock()
|
|
}
|
|
|
|
// Reset reset querier's error message and results
|
|
func (fq *FakeQuerier) Reset() {
|
|
fq.Lock()
|
|
fq.err = nil
|
|
fq.metrics = fq.metrics[:0]
|
|
fq.isPartial = nil
|
|
fq.Unlock()
|
|
}
|
|
|
|
// Add appends metrics to querier result metrics
|
|
func (fq *FakeQuerier) Add(metrics ...Metric) {
|
|
fq.Lock()
|
|
fq.metrics = append(fq.metrics, metrics...)
|
|
fq.Unlock()
|
|
}
|
|
|
|
// BuildWithParams return FakeQuerier itself
|
|
func (fq *FakeQuerier) BuildWithParams(_ QuerierParams) Querier {
|
|
return fq
|
|
}
|
|
|
|
// QueryRange performs query
|
|
func (fq *FakeQuerier) QueryRange(ctx context.Context, q string, _, _ time.Time) (Result, error) {
|
|
req, _, err := fq.Query(ctx, q, time.Now())
|
|
return req, err
|
|
}
|
|
|
|
// Query returns metrics restored in querier
|
|
func (fq *FakeQuerier) Query(_ context.Context, _ string, _ time.Time) (Result, *http.Request, error) {
|
|
fq.Lock()
|
|
defer fq.Unlock()
|
|
if fq.err != nil {
|
|
return Result{}, nil, fq.err
|
|
}
|
|
cp := make([]Metric, len(fq.metrics))
|
|
copy(cp, fq.metrics)
|
|
req, _ := http.NewRequest(http.MethodPost, "foo.com", nil)
|
|
return Result{Data: cp, IsPartial: fq.isPartial}, req, nil
|
|
}
|
|
|
|
// FakeQuerierWithRegistry can store different results for different query expr
|
|
type FakeQuerierWithRegistry struct {
|
|
sync.Mutex
|
|
registry map[string][]Metric
|
|
}
|
|
|
|
// Set stores query result for given key
|
|
func (fqr *FakeQuerierWithRegistry) Set(key string, metrics ...Metric) {
|
|
fqr.Lock()
|
|
if fqr.registry == nil {
|
|
fqr.registry = make(map[string][]Metric)
|
|
}
|
|
fqr.registry[key] = metrics
|
|
fqr.Unlock()
|
|
}
|
|
|
|
// Reset clean querier's results registry
|
|
func (fqr *FakeQuerierWithRegistry) Reset() {
|
|
fqr.Lock()
|
|
fqr.registry = nil
|
|
fqr.Unlock()
|
|
}
|
|
|
|
// BuildWithParams returns itself
|
|
func (fqr *FakeQuerierWithRegistry) BuildWithParams(_ QuerierParams) Querier {
|
|
return fqr
|
|
}
|
|
|
|
// QueryRange performs query
|
|
func (fqr *FakeQuerierWithRegistry) QueryRange(ctx context.Context, q string, _, _ time.Time) (Result, error) {
|
|
req, _, err := fqr.Query(ctx, q, time.Now())
|
|
return req, err
|
|
}
|
|
|
|
// Query returns metrics restored in querier registry
|
|
func (fqr *FakeQuerierWithRegistry) Query(_ context.Context, expr string, _ time.Time) (Result, *http.Request, error) {
|
|
fqr.Lock()
|
|
defer fqr.Unlock()
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, "foo.com", nil)
|
|
metrics, ok := fqr.registry[expr]
|
|
if !ok {
|
|
return Result{}, req, nil
|
|
}
|
|
cp := make([]Metric, len(metrics))
|
|
copy(cp, metrics)
|
|
return Result{Data: cp}, req, nil
|
|
}
|
|
|
|
// FakeQuerierWithDelay mock querier with given delay duration
|
|
type FakeQuerierWithDelay struct {
|
|
FakeQuerier
|
|
Delay time.Duration
|
|
}
|
|
|
|
// Query returns query result after delay duration
|
|
func (fqd *FakeQuerierWithDelay) Query(ctx context.Context, expr string, ts time.Time) (Result, *http.Request, error) {
|
|
timer := time.NewTimer(fqd.Delay)
|
|
select {
|
|
case <-ctx.Done():
|
|
case <-timer.C:
|
|
}
|
|
return fqd.FakeQuerier.Query(ctx, expr, ts)
|
|
}
|
|
|
|
// BuildWithParams returns itself
|
|
func (fqd *FakeQuerierWithDelay) BuildWithParams(_ QuerierParams) Querier {
|
|
return fqd
|
|
}
|