-
Notifications
You must be signed in to change notification settings - Fork 140
/
function.go
138 lines (119 loc) · 4.07 KB
/
function.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package divideSeries
import (
"context"
"errors"
"fmt"
"math"
"github.com/go-graphite/carbonapi/expr/helper"
"github.com/go-graphite/carbonapi/expr/interfaces"
"github.com/go-graphite/carbonapi/expr/types"
"github.com/go-graphite/carbonapi/pkg/parser"
)
type divideSeries struct {
interfaces.FunctionBase
}
func GetOrder() interfaces.Order {
return interfaces.Any
}
func New(configFile string) []interfaces.FunctionMetadata {
res := make([]interfaces.FunctionMetadata, 0)
f := ÷Series{}
functions := []string{"divideSeries"}
for _, n := range functions {
res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
}
return res
}
// divideSeries(dividendSeriesList, divisorSeriesList)
func (f *divideSeries) Do(ctx context.Context, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
if e.ArgsLen() < 1 {
return nil, parser.ErrMissingTimeseries
}
firstArg, err := helper.GetSeriesArg(ctx, e.Arg(0), from, until, values)
if err != nil {
return nil, err
}
var useMetricNames bool
var numerators []*types.MetricData
var denominator *types.MetricData
var results []*types.MetricData
if e.ArgsLen() == 2 {
useMetricNames = true
numerators = firstArg
denominators, err := helper.GetSeriesArg(ctx, e.Arg(1), from, until, values)
if err != nil {
return nil, err
}
if len(denominators) == 0 {
results := make([]*types.MetricData, 0, len(numerators))
for _, numerator := range numerators {
r := numerator.CopyLink()
r.Values = make([]float64, len(numerator.Values))
r.Name = fmt.Sprintf("divideSeries(%s,MISSING)", numerator.Name)
for i := range numerator.Values {
r.Values[i] = math.NaN()
}
results = append(results, r)
}
return results, nil
}
if len(denominators) > 1 {
return nil, types.ErrWildcardNotAllowed
}
denominator = denominators[0]
} else if len(firstArg) == 2 && e.ArgsLen() == 1 {
numerators = append(numerators, firstArg[0])
denominator = firstArg[1]
} else {
return nil, errors.New("must be called with 2 series or a wildcard that matches exactly 2 series")
}
for _, numerator := range numerators {
var name string
if useMetricNames {
name = "divideSeries(" + numerator.Name + "," + denominator.Name + ")"
} else {
name = "divideSeries(" + e.RawArgs() + ")"
}
numerator, denominator = helper.ConsolidateSeriesByStep(numerator, denominator)
r := numerator.CopyTag(name, numerator.Tags)
r.Values = make([]float64, len(numerator.Values))
for i, v := range numerator.Values {
// math.IsNaN(v) || math.IsNaN(denominator.Values[i]) covered by nature of math.NaN
if denominator.Values[i] == 0 {
r.Values[i] = math.NaN()
} else {
r.Values[i] = v / denominator.Values[i]
}
}
results = append(results, r)
}
return results, nil
}
// Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
func (f *divideSeries) Description() map[string]types.FunctionDescription {
return map[string]types.FunctionDescription{
"divideSeries": {
Description: "Takes a dividend metric and a divisor metric and draws the division result.\nA constant may *not* be passed. To divide by a constant, use the scale()\nfunction (which is essentially a multiplication operation) and use the inverse\nof the dividend. (Division by 8 = multiplication by 1/8 or 0.125)\n\nExample:\n\n.. code-block:: none\n\n &target=divideSeries(Series.dividends,Series.divisors)",
Function: "divideSeries(dividendSeriesList, divisorSeries)",
Group: "Combine",
Module: "graphite.render.functions",
Name: "divideSeries",
Params: []types.FunctionParam{
{
Name: "dividendSeriesList",
Required: true,
Type: types.SeriesList,
},
{
Name: "divisorSeries",
Required: true,
Type: types.SeriesList,
},
},
SeriesChange: true, // function aggregate metrics or change series items count
NameChange: true, // name changed
TagsChange: true, // name tag changed
ValuesChange: true, // values changed
},
}
}