// NewOperator creates a new binary operator function. // the binary operators display a natural join semantic. func NewOperator(op string, operator func(float64, float64) float64) function.MetricFunction { return function.MetricFunction{ Name: op, MinArguments: 2, MaxArguments: 2, Compute: func(context *function.EvaluationContext, args []function.Expression, groups function.Groups) (function.Value, error) { evaluated, err := function.EvaluateMany(context, args) if err != nil { return nil, err } leftValue := evaluated[0] rightValue := evaluated[1] leftList, err := leftValue.ToSeriesList(context.Timerange) if err != nil { return nil, err } rightList, err := rightValue.ToSeriesList(context.Timerange) if err != nil { return nil, err } joined := join.Join([]api.SeriesList{leftList, rightList}) result := make([]api.Timeseries, len(joined.Rows)) for i, row := range joined.Rows { left := row.Row[0] right := row.Row[1] array := make([]float64, len(left.Values)) for j := 0; j < len(left.Values); j++ { array[j] = operator(left.Values[j], right.Values[j]) } result[i] = api.Timeseries{Values: array, TagSet: row.TagSet} } query := fmt.Sprintf("(%s %s %s)", leftValue.GetName(), op, rightValue.GetName()) return api.SeriesList{ Series: result, Timerange: context.Timerange, Name: query, Query: query, }, nil }, } }
// NewOperator creates a new binary operator function. // the binary operators display a natural join semantic. func NewOperator(op string, operator func(float64, float64) float64) function.MetricFunction { return function.MetricFunction{ Name: op, MinArguments: 2, MaxArguments: 2, Compute: func(context function.EvaluationContext, args []function.Expression, groups []string) (function.Value, error) { leftChannel := make(chan function.Value, 1) rightChannel := make(chan function.Value, 1) errs := make(chan error, 2) go func() { leftValue, err := args[0].Evaluate(context) leftChannel <- leftValue errs <- err }() go func() { rightValue, err := args[1].Evaluate(context) rightChannel <- rightValue errs <- err }() err := <-errs if err != nil { return nil, err } err = <-errs if err != nil { return nil, err } leftValue := <-leftChannel rightValue := <-rightChannel leftList, err := leftValue.ToSeriesList(context.Timerange) if err != nil { return nil, err } rightList, err := rightValue.ToSeriesList(context.Timerange) if err != nil { return nil, err } joined := join.Join([]api.SeriesList{leftList, rightList}) result := make([]api.Timeseries, len(joined.Rows)) for i, row := range joined.Rows { left := row.Row[0] right := row.Row[1] array := make([]float64, len(left.Values)) for j := 0; j < len(left.Values); j++ { array[j] = operator(left.Values[j], right.Values[j]) } result[i] = api.Timeseries{array, row.TagSet} } return function.SeriesListValue(api.SeriesList{ Series: result, Timerange: context.Timerange, Name: fmt.Sprintf("(%s %s %s)", leftValue.GetName(), op, rightValue.GetName()), }), nil }, } }