github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/tools/query-audit/auditor.go (about)

     1  package main
     2  
     3  import (
     4  	"math"
     5  
     6  	"github.com/pkg/errors"
     7  	"github.com/prometheus/common/model"
     8  )
     9  
    10  // Auditor is a struct for auditing prometheus queries
    11  type Auditor struct{}
    12  
    13  // Diff stores a difference between two queries
    14  type Diff struct {
    15  	Series      int
    16  	Diff        float64   // avg proportional diff across all series & samples
    17  	sampleDiffs []float64 // proportional diffs as measured by x/control
    18  }
    19  
    20  // Audit audits two prometheus queries
    21  func (a *Auditor) Audit(control, x model.Value) (Diff, error) {
    22  	if x.Type() == model.ValMatrix && control.Type() == model.ValMatrix {
    23  		return a.auditMatrix(x.(model.Matrix), control.(model.Matrix))
    24  	}
    25  
    26  	if x.Type() == model.ValVector && control.Type() == model.ValVector {
    27  		return a.auditVector(x.(model.Vector), control.(model.Vector))
    28  	}
    29  
    30  	return Diff{}, errors.Errorf("unsupported types for equality: got %s & %s", control.Type().String(), x.Type().String())
    31  }
    32  
    33  func (a *Auditor) auditMatrix(x, y model.Matrix) (diff Diff, err error) {
    34  	// different # of returned series
    35  	if len(x) != len(y) {
    36  		return diff, errors.Errorf("different # of series: control=%d, other=%d", len(x), len(y))
    37  	}
    38  
    39  	for i := 0; i < len(x); i++ {
    40  		xSeries, ySeries := x[i], y[i]
    41  		if !xSeries.Metric.Equal(ySeries.Metric) {
    42  			return diff, errors.Errorf("mismatched metrics: %v vs %v", xSeries.Metric, ySeries.Metric)
    43  		}
    44  
    45  		xVals, yVals := xSeries.Values, ySeries.Values
    46  		if len(xVals) != len(yVals) {
    47  			return diff, errors.Errorf(
    48  				"mismatched number of samples for series %v. control=%d, other=%d",
    49  				xSeries.Metric,
    50  				len(xVals),
    51  				len(yVals),
    52  			)
    53  		}
    54  
    55  		for j := 0; j < len(xVals); j++ {
    56  			xSample, ySample := xVals[j], yVals[j]
    57  
    58  			if xSample.Timestamp != ySample.Timestamp {
    59  				return diff, errors.Errorf(
    60  					"mismatched timestamp for %d sample of series %v. control=%d, other=%d",
    61  					j,
    62  					xSeries.Metric,
    63  					xSample.Timestamp,
    64  					ySample.Timestamp,
    65  				)
    66  			}
    67  
    68  			absDiff := math.Abs(float64(ySample.Value-xSample.Value)) / math.Abs(float64(xSample.Value))
    69  
    70  			// 0/0 -> no diff
    71  			if math.IsNaN(absDiff) {
    72  				absDiff = 0
    73  			}
    74  
    75  			diff.sampleDiffs = append(diff.sampleDiffs, absDiff)
    76  
    77  		}
    78  	}
    79  
    80  	diff.Series = len(x)
    81  	var avgDiffProportion float64
    82  	for _, d := range diff.sampleDiffs {
    83  		avgDiffProportion += d
    84  	}
    85  	diff.Diff = avgDiffProportion / float64(len(diff.sampleDiffs))
    86  
    87  	return diff, nil
    88  }
    89  
    90  func (a *Auditor) auditVector(x, y model.Vector) (Diff, error) {
    91  	return Diff{}, errors.New("unimplemented")
    92  }