Пример #1
0
// NewAggregate takes a named aggregating function `[float64] => float64` and makes it into a MetricFunction.
func NewAggregate(name string, aggregator func([]float64) float64) function.MetricFunction {
	return function.MetricFunction{
		Name:          name,
		MinArguments:  1,
		MaxArguments:  1,
		AllowsGroupBy: true,
		Compute: func(context function.EvaluationContext, args []function.Expression, groups []string) (function.Value, error) {
			argument := args[0]
			value, err := argument.Evaluate(context)
			if err != nil {
				return nil, err
			}
			seriesList, err := value.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			result := aggregate.AggregateBy(seriesList, aggregator, groups)
			groupNames := make([]string, len(groups))
			for i, group := range groups {
				groupNames[i] += group
			}
			if len(groups) == 0 {
				result.Name = fmt.Sprintf("%s(%s)", name, value.GetName())
			} else {
				result.Name = fmt.Sprintf("%s(%s group by %s)", name, value.GetName(), strings.Join(groupNames, ", "))
			}
			return function.SeriesListValue(result), nil
		},
	}
}
Пример #2
0
// NewFilter creates a new instance of a filtering function.
func NewFilter(name string, summary func([]float64) float64, ascending bool) function.MetricFunction {
	return function.MetricFunction{
		Name:         name,
		MinArguments: 2,
		MaxArguments: 2,
		Compute: func(context function.EvaluationContext, arguments []function.Expression, groups []string) (function.Value, error) {
			value, err := arguments[0].Evaluate(context)
			if err != nil {
				return nil, err
			}
			// The value must be a SeriesList.
			list, err := value.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			countValue, err := arguments[1].Evaluate(context)
			if err != nil {
				return nil, err
			}
			countFloat, err := countValue.ToScalar()
			if err != nil {
				return nil, err
			}
			// Round to the nearest integer.
			count := int(countFloat + 0.5)
			if count < 0 {
				return nil, fmt.Errorf("expected positive count but got %d", count)
			}
			result := filter.FilterBy(list, count, summary, ascending)
			result.Name = fmt.Sprintf("%s(%s, %d)", name, value.GetName(), count)
			return function.SeriesListValue(result), nil
		},
	}
}
Пример #3
0
func (expr *metricFetchExpression) Evaluate(context function.EvaluationContext) (function.Value, error) {
	// Merge predicates appropriately
	var predicate api.Predicate
	if context.Predicate == nil && expr.predicate == nil {
		predicate = api.TruePredicate
	} else if context.Predicate == nil {
		predicate = expr.predicate
	} else if expr.predicate == nil {
		predicate = context.Predicate
	} else {
		predicate = &andPredicate{[]api.Predicate{expr.predicate, context.Predicate}}
	}

	metricTagSets, err := context.API.GetAllTags(api.MetricKey(expr.metricName))
	if err != nil {
		return nil, err
	}
	filtered := applyPredicates(metricTagSets, predicate)

	ok := context.FetchLimit.Consume(len(filtered))

	if !ok {
		return nil, function.NewLimitError("fetch limit exceeded: too many series to fetch",
			context.FetchLimit.Current(),
			context.FetchLimit.Limit())
	}

	metrics := make([]api.TaggedMetric, len(filtered))
	for i := range metrics {
		metrics[i] = api.TaggedMetric{api.MetricKey(expr.metricName), filtered[i]}
	}

	serieslist, err := context.MultiBackend.FetchMultipleSeries(
		api.FetchMultipleRequest{
			metrics,
			context.SampleMethod,
			context.Timerange,
			context.API,
			context.Cancellable,
			context.Profiler,
		},
	)

	if err != nil {
		return nil, err
	}

	serieslist.Name = expr.metricName

	return function.SeriesListValue(serieslist), nil
}
Пример #4
0
// 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{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
		},
	}
}
Пример #5
0
// NewTransform takes a named transforming function `[float64], [value] => [float64]` and makes it into a MetricFunction.
func NewTransform(name string, parameterCount int, transformer func([]float64, []function.Value, float64) ([]float64, error)) function.MetricFunction {
	return function.MetricFunction{
		Name:         name,
		MinArguments: parameterCount + 1,
		MaxArguments: parameterCount + 1,
		Compute: func(context function.EvaluationContext, args []function.Expression, groups []string) (function.Value, error) {
			listValue, err := args[0].Evaluate(context)
			if err != nil {
				return nil, err
			}
			list, err := listValue.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			parameters := make([]function.Value, parameterCount)
			for i := range parameters {
				parameters[i], err = args[i+1].Evaluate(context)
				if err != nil {
					return nil, err
				}
			}
			result, err := transform.ApplyTransform(list, transformer, parameters)
			if err != nil {
				return nil, err
			}
			parameterNames := make([]string, len(parameters))
			for i, param := range parameters {
				parameterNames[i] = param.GetName()
			}
			if len(parameters) != 0 {
				result.Name = fmt.Sprintf("%s(%s, %s)", name, listValue.GetName(), strings.Join(parameterNames, ", "))
			} else {
				result.Name = fmt.Sprintf("%s(%s)", name, listValue.GetName())
			}
			return function.SeriesListValue(result), nil
		},
	}
}
Пример #6
0
			return nil, err
		}
		list, err := result.ToSeriesList(context.Timerange)
		if err != nil {
			return nil, err
		}
		value, err := arguments[1].Evaluate(context)
		if err != nil {
			return nil, err
		}
		dropTag, err := value.ToString()
		if err != nil {
			return nil, err
		}
		// Drop the tag from the list.
		return function.SeriesListValue(DropTag(list, dropTag)), nil
	},
}

// SetFunction wraps up SetTag into a MetricFunction called "tag.set"
var SetFunction = function.MetricFunction{
	Name:         "tag.set",
	MinArguments: 3,
	MaxArguments: 3,
	Compute: func(context function.EvaluationContext, arguments []function.Expression, groups function.Groups) (function.Value, error) {
		result, err := arguments[0].Evaluate(context)
		if err != nil {
			return nil, err
		}
		list, err := result.ToSeriesList(context.Timerange)
		if err != nil {
Пример #7
0
func (expr *LiteralSeriesExpression) Evaluate(context function.EvaluationContext) (function.Value, error) {
	return function.SeriesListValue(expr.list), nil
}
Пример #8
0
func (expr *LiteralExpression) Evaluate(context function.EvaluationContext) (function.Value, error) {
	return function.SeriesListValue(api.SeriesList{
		Series:    []api.Timeseries{api.Timeseries{expr.Values, api.NewTagSet()}},
		Timerange: api.Timerange{},
	}), nil
}
Пример #9
0
					sum -= series.Values[i-limit]
					count--
				}
				// Numerical error could (possibly) cause count == 0 but sum != 0.
				if i-limit+1 >= 0 {
					if count == 0 {
						results[i-limit+1] = math.NaN()
					} else {
						results[i-limit+1] = sum / float64(count)
					}
				}
			}
			list.Series[index].Values = results
		}
		list.Name = fmt.Sprintf("transform.moving_average(%s, %s)", listValue.GetName(), sizeValue.GetName())
		return function.SeriesListValue(list), nil
	},
}

var Alias = function.MetricFunction{
	Name:         "transform.alias",
	MinArguments: 2,
	MaxArguments: 2,
	Compute: func(context function.EvaluationContext, arguments []function.Expression, groups []string) (function.Value, error) {
		value, err := arguments[0].Evaluate(context)
		if err != nil {
			return nil, err
		}
		list, err := value.ToSeriesList(context.Timerange)
		if err != nil {
			return nil, err
Пример #10
0
// 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
		},
	}
}