mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
Alerting: Log expression command types during evaluation (#84614)
This commit is contained in:
parent
09817e2c7f
commit
9dc4221508
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user