Alerting: Log expression command types during evaluation (#84614)

This commit is contained in:
Yuri Tseretyan 2024-03-19 10:00:03 -04:00 committed by GitHub
parent 09817e2c7f
commit 9dc4221508
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 101 additions and 0 deletions

View File

@ -216,6 +216,10 @@ func (cmd *ConditionsCmd) executeCond(_ context.Context, _ time.Time, cond condi
return isCondFiring, isCondNoData, matches, nil
}
func (cmd *ConditionsCmd) Type() string {
return "classic_condition"
}
func compareWithOperator(b1, b2 bool, operator ConditionOperatorType) bool {
if operator == "or" {
return b1 || b2

View File

@ -19,6 +19,7 @@ import (
type Command interface {
NeedsVars() []string
Execute(ctx context.Context, now time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error)
Type() string
}
// MathCommand is a command for a math expression such as "1 + $GA / 2"
@ -75,6 +76,10 @@ func (gm *MathCommand) Execute(ctx context.Context, _ time.Time, vars mathexp.Va
return gm.Expression.Execute(gm.refID, vars, tracer)
}
func (gm *MathCommand) Type() string {
return TypeMath.String()
}
// ReduceCommand is an expression command for reduction of a timeseries such as a min, mean, or max.
type ReduceCommand struct {
Reducer mathexp.ReducerID
@ -201,6 +206,10 @@ func (gr *ReduceCommand) Execute(ctx context.Context, _ time.Time, vars mathexp.
return newRes, nil
}
func (gr *ReduceCommand) Type() string {
return TypeReduce.String()
}
// ResampleCommand is an expression command for resampling of a timeseries.
type ResampleCommand struct {
Window time.Duration
@ -312,6 +321,10 @@ func (gr *ResampleCommand) Execute(ctx context.Context, now time.Time, vars math
return newRes, nil
}
func (gr *ResampleCommand) Type() string {
return TypeResample.String()
}
// CommandType is the type of the expression command.
type CommandType int
@ -342,6 +355,8 @@ func (gt CommandType) String() string {
return "resample"
case TypeClassicConditions:
return "classic_conditions"
case TypeThreshold:
return "threshold"
case TypeSQL:
return "sql"
default:

View File

@ -4,9 +4,11 @@ import (
"context"
"encoding/json"
"fmt"
"slices"
"time"
"go.opentelemetry.io/otel/attribute"
"golang.org/x/exp/maps"
"gonum.org/v1/gonum/graph/simple"
"gonum.org/v1/gonum/graph/topo"
@ -123,6 +125,56 @@ func (dp *DataPipeline) execute(c context.Context, now time.Time, s *Service) (m
return vars, nil
}
// GetDatasourceTypes returns an unique list of data source types used in the query. Machine learning node is encoded as `ml_<type>`, e.g. ml_outlier
func (dp *DataPipeline) GetDatasourceTypes() []string {
if dp == nil {
return nil
}
m := make(map[string]struct{}, 2)
for _, node := range *dp {
name := ""
switch t := node.(type) {
case *DSNode:
if t.datasource != nil {
name = t.datasource.Type
}
case *MLNode:
name = fmt.Sprintf("ml_%s", t.command.Type())
}
if name == "" {
continue
}
m[name] = struct{}{}
}
result := maps.Keys(m)
slices.Sort(result)
return result
}
// GetCommandTypes returns a sorted unique list of all server-side expression commands used in the pipeline.
func (dp *DataPipeline) GetCommandTypes() []string {
if dp == nil {
return nil
}
m := make(map[string]struct{}, 5) // 5 is big enough to cover most of the cases
for _, node := range *dp {
name := ""
switch t := node.(type) {
case *CMDNode:
if t.Command != nil {
name = t.Command.Type()
}
}
if name == "" {
continue
}
m[name] = struct{}{}
}
result := maps.Keys(m)
slices.Sort(result)
return result
}
// BuildPipeline builds a graph of the nodes, and returns the nodes in an
// executable order.
func (s *Service) buildPipeline(req *Request) (DataPipeline, error) {

View File

@ -77,6 +77,10 @@ func (h *HysteresisCommand) Execute(ctx context.Context, now time.Time, vars mat
return mathexp.Results{Values: append(loadingResults.Values, unloadingResults.Values...)}, nil
}
func (h HysteresisCommand) Type() string {
return "hysteresis"
}
func NewHysteresisCommand(refID string, referenceVar string, loadCondition ThresholdCommand, unloadCondition ThresholdCommand, l Fingerprints) (*HysteresisCommand, error) {
return &HysteresisCommand{
RefID: refID,

View File

@ -31,6 +31,8 @@ type Command interface {
// Execute creates a payload send request to the ML API by calling the function argument sendRequest, and then parses response.
// Function sendRequest is supposed to abstract the client configuration such creating http request, adding authorization parameters, host etc.
Execute(from, to time.Time, sendRequest func(method string, path string, payload []byte) (response.Response, error)) (*backend.QueryDataResponse, error)
Type() string
}
// UnmarshalCommand parses a config parameters and creates a command. Requires key `type` to be specified.

View File

@ -19,6 +19,10 @@ type OutlierCommand struct {
var _ Command = OutlierCommand{}
func (c OutlierCommand) Type() string {
return "outlier"
}
func (c OutlierCommand) DatasourceUID() string {
return c.config.DatasourceUID
}

View File

@ -42,3 +42,7 @@ func (f *FakeCommand) Execute(from, to time.Time, executor func(method string, p
}
return f.Response, f.Error
}
func (f *FakeCommand) Type() string {
return "fake"
}

View File

@ -187,6 +187,13 @@ type DSNode struct {
request Request
}
func (dn *DSNode) String() string {
if dn.datasource == nil {
return "unknown"
}
return dn.datasource.Type
}
// NodeType returns the data pipeline node type.
func (dn *DSNode) NodeType() NodeType {
return TypeDatasourceNode

View File

@ -103,3 +103,7 @@ func (gr *SQLCommand) Execute(ctx context.Context, now time.Time, vars mathexp.V
return rsp, nil
}
func (gr *SQLCommand) Type() string {
return TypeSQL.String()
}

View File

@ -128,6 +128,10 @@ func (tc *ThresholdCommand) Execute(ctx context.Context, now time.Time, vars mat
return mathCommand.Execute(ctx, now, vars, tracer)
}
func (tc *ThresholdCommand) Type() string {
return TypeThreshold.String()
}
// createMathExpression converts all the info we have about a "threshold" expression in to a Math expression
func createMathExpression(referenceVar string, thresholdFunc ThresholdType, args []float64, invert bool) (string, error) {
var exp string

View File

@ -73,6 +73,7 @@ func (r *conditionEvaluator) EvaluateRaw(ctx context.Context, now time.Time) (re
defer cancel()
execCtx = timeoutCtx
}
logger.FromContext(ctx).Debug("Executing pipeline", "commands", strings.Join(r.pipeline.GetCommandTypes(), ","), "datasources", strings.Join(r.pipeline.GetDatasourceTypes(), ","))
return r.expressionService.ExecutePipeline(execCtx, now, r.pipeline)
}