Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 34784be

Browse files
authored
Merge pull request #1755 from bloomberg/func_aliasByMetric
Implementing function aliasByMetric
2 parents 45c29bb + 06ef38e commit 34784be

File tree

4 files changed

+218
-1
lines changed

4 files changed

+218
-1
lines changed

docs/graphite.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ See also:
4141
| aggregateLine | | No |
4242
| aggregateWithWildcards | | No |
4343
| alias(seriesList, alias) seriesList | | Stable |
44-
| aliasByMetric | | No |
44+
| aliasByMetric | | Stable |
4545
| aliasByNode(seriesList, nodeList) seriesList | aliasByTags | Stable |
4646
| aliasByTags | | No |
4747
| aliasQuery | | No |

expr/func_aliasbymetric.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package expr
2+
3+
import (
4+
"strings"
5+
6+
"github.com/grafana/metrictank/api/models"
7+
)
8+
9+
type FuncAliasByMetric struct {
10+
in GraphiteFunc
11+
}
12+
13+
func NewAliasByMetric() GraphiteFunc {
14+
return &FuncAliasByMetric{}
15+
}
16+
17+
func (s *FuncAliasByMetric) Signature() ([]Arg, []Arg) {
18+
return []Arg{
19+
ArgSeriesList{val: &s.in},
20+
}, []Arg{ArgSeries{}}
21+
}
22+
23+
func (s *FuncAliasByMetric) Context(context Context) Context {
24+
return context
25+
}
26+
27+
func (s *FuncAliasByMetric) Exec(dataMap DataMap) ([]models.Series, error) {
28+
series, err := s.in.Exec(dataMap)
29+
if err != nil {
30+
return nil, err
31+
}
32+
for i, serie := range series {
33+
m := strings.SplitN(extractMetric(serie.Target), ";", 2)
34+
mSlice := strings.Split(m[0], ".")
35+
base := mSlice[len(mSlice)-1]
36+
37+
// append metric tags to base
38+
if len(m) > 1 {
39+
base = strings.Join([]string{base, m[1]}, ";")
40+
}
41+
42+
series[i].Target = base
43+
series[i].QueryPatt = base
44+
}
45+
return series, nil
46+
}

expr/func_aliasbymetric_test.go

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package expr
2+
3+
import (
4+
"testing"
5+
6+
"github.com/grafana/metrictank/api/models"
7+
)
8+
9+
func TestAliasByMetricNameWithoutPeriods(t *testing.T) {
10+
// Metric base same as the metric name
11+
veryShortMetric := "veryShort"
12+
veryShortBase := veryShortMetric
13+
14+
testAliasByMetric(
15+
[]models.Series{
16+
{ // No Function wrapper
17+
Interval: 10,
18+
QueryPatt: veryShortMetric,
19+
Target: veryShortMetric,
20+
Datapoints: getCopy(a),
21+
},
22+
{ // Function wrapper - single
23+
Interval: 10,
24+
QueryPatt: veryShortMetric,
25+
Target: "functionBlah(" + veryShortMetric + ", funcValue1, funcValue2)",
26+
Datapoints: getCopy(a),
27+
},
28+
{ // Function wrapper - multiple
29+
Interval: 10,
30+
QueryPatt: veryShortMetric,
31+
Target: "functionBlah(functionBlahBlah(" + veryShortMetric + "),funcValue1, funcValue2)",
32+
Datapoints: getCopy(a),
33+
},
34+
},
35+
[]models.Series{
36+
{
37+
Interval: 10,
38+
QueryPatt: veryShortBase,
39+
Target: veryShortBase,
40+
Datapoints: getCopy(a),
41+
},
42+
{
43+
Interval: 10,
44+
QueryPatt: veryShortBase,
45+
Target: veryShortBase,
46+
Datapoints: getCopy(a),
47+
},
48+
{
49+
Interval: 10,
50+
QueryPatt: veryShortBase,
51+
Target: veryShortBase,
52+
Datapoints: getCopy(a),
53+
},
54+
},
55+
t,
56+
)
57+
}
58+
59+
func TestAliasByMetricWithoutTags(t *testing.T) {
60+
// Metric base equals string after the last period
61+
shortMetric := "my.test.metric.short"
62+
shortBase := "short"
63+
64+
testAliasByMetric(
65+
[]models.Series{
66+
{ // No Function wrapper
67+
Interval: 10,
68+
QueryPatt: shortMetric,
69+
Target: shortMetric,
70+
Datapoints: getCopy(a),
71+
},
72+
{ // Function wrapper - single
73+
Interval: 10,
74+
QueryPatt: shortMetric,
75+
Target: "functionBlah(" + shortMetric + ", funcValue1, funcValue2)",
76+
Datapoints: getCopy(a),
77+
},
78+
{ // Function wrapper - multiple
79+
Interval: 10,
80+
QueryPatt: shortMetric,
81+
Target: "functionBlah(functionBlahBlah(" + shortMetric + "),funcValue1, funcValue2)",
82+
Datapoints: getCopy(a),
83+
},
84+
},
85+
[]models.Series{
86+
{
87+
Interval: 10,
88+
QueryPatt: shortBase,
89+
Target: shortBase,
90+
Datapoints: getCopy(a),
91+
},
92+
{
93+
Interval: 10,
94+
QueryPatt: shortBase,
95+
Target: shortBase,
96+
Datapoints: getCopy(a),
97+
},
98+
{
99+
Interval: 10,
100+
QueryPatt: shortBase,
101+
Target: shortBase,
102+
Datapoints: getCopy(a),
103+
},
104+
},
105+
t,
106+
)
107+
}
108+
109+
// Long metric string with multiple tag values
110+
// which can accept chars like [a-zA-Z0-9-_./%@ +<>!]
111+
func TestAliasByMetricWithTags(t *testing.T) {
112+
// Metric base same as the metric name plus
113+
// the semicolon delimited list of tags
114+
longMetric := "my.test.metric.long;cluster=abc*;datacenter=some@wher8<>far;version=1.2-3_4.%5;stage=toInfinity;subStage=andBeyond;timezone=OST"
115+
longBase := "long;cluster=abc*;datacenter=some@wher8<>far;version=1.2-3_4.%5;stage=toInfinity;subStage=andBeyond;timezone=OST"
116+
117+
testAliasByMetric(
118+
[]models.Series{
119+
{ // No Function wrapper
120+
Interval: 10,
121+
QueryPatt: longMetric,
122+
Target: longMetric,
123+
Datapoints: getCopy(a),
124+
},
125+
{ // Function wrapper - single
126+
Interval: 10,
127+
QueryPatt: longMetric,
128+
Target: "functionBlah(" + longMetric + ", funcValue1, funcValue2)",
129+
Datapoints: getCopy(a),
130+
},
131+
{ // Function wrapper - multiple
132+
Interval: 10,
133+
QueryPatt: longMetric,
134+
Target: "functionBlah(functionBlahBlah(" + longMetric + "),funcValue1, funcValue2)",
135+
Datapoints: getCopy(a),
136+
},
137+
},
138+
[]models.Series{
139+
{
140+
Interval: 10,
141+
QueryPatt: longBase,
142+
Target: longBase,
143+
Datapoints: getCopy(a),
144+
},
145+
{
146+
Interval: 10,
147+
QueryPatt: longBase,
148+
Target: longBase,
149+
Datapoints: getCopy(a),
150+
},
151+
{
152+
Interval: 10,
153+
QueryPatt: longBase,
154+
Target: longBase,
155+
Datapoints: getCopy(a),
156+
},
157+
},
158+
t,
159+
)
160+
}
161+
162+
func testAliasByMetric(in []models.Series, out []models.Series, t *testing.T) {
163+
f := NewAliasByMetric()
164+
f.(*FuncAliasByMetric).in = NewMock(in)
165+
166+
got, err := f.Exec(make(map[Req][]models.Series))
167+
if err := equalOutput(out, got, nil, err); err != nil {
168+
t.Fatal(err)
169+
}
170+
}

expr/funcs.go

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func init() {
5555
"absolute": {NewAbsolute, true},
5656
"aggregate": {NewAggregate, true},
5757
"alias": {NewAlias, true},
58+
"aliasByMetric": {NewAliasByMetric, true},
5859
"aliasByTags": {NewAliasByNode, true},
5960
"aliasByNode": {NewAliasByNode, true},
6061
"aliasSub": {NewAliasSub, true},

0 commit comments

Comments
 (0)