Skip to content

Commit c4a4ab2

Browse files
authored
Add new templates to commonlib/signal (#1453)
* Add new templates to commonlib * fmt * Make sure mean target doesn't conflict by name * Fix legend rendering when aggLevel is none
1 parent 58c5ef4 commit c4a4ab2

File tree

7 files changed

+286
-3
lines changed

7 files changed

+286
-3
lines changed

common-lib/CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
# 0.3.5
2+
- [Variables] Add queriesSelectorGroupOnly, queriesSelectorFilterOnly attributes
3+
- [Signal] Add %(queriesSelectorGroupOnly)s, %(queriesSequeriesSelectorFilterOnly)s templates
4+
- [Signal] Fix legend rendering when aggLevel is none
5+
- [Panel] Fix id conflict if topkPercentage panel is used with signal.asTarget()
6+
17
# 0.3.4
28
- [Signal] Fix interval template for increase/delta functions.
39

410
# 0.3.3
5-
- [Signal] add `withQuantile(quantile=0.95)` to histogram signals.
11+
- [Signal] Add `withQuantile(quantile=0.95)` to histogram signals.
612

713
# 0.3.2
814
- [Signal] Fix combining info metrics.

common-lib/common/panels/generic/timeSeries/topk_percentage.libsonnet

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ base {
2424
);
2525
local meanTarget = target
2626
{ expr: 'avg(' + target.expr + ')' }
27-
+ g.query.prometheus.withLegendFormat('Mean');
27+
+ g.query.prometheus.withLegendFormat('Mean')
28+
+ g.query.prometheus.withRefId('Mean');
2829
super.new(title, targets=[topTarget, meanTarget], description=description)
2930
+ self.withDataLink(instanceLabels, drillDownDashboardUid),
3031

common-lib/common/signal/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ Signal's level:
111111
The following is supported in expressions and legends:
112112

113113
- `%(queriesSelector)s` - expands to filteringSelector matchers and matchers based on instanceLabels, and groupLabels
114+
- `%(queriesSelectorGroupOnly)s` - expands to filteringSelector matchers and matchers based on groupLabels only
115+
- `%(queriesSelectorFilterOnly)s` - expands to filteringSelector matchers only
114116
- `%(filteringSelector)s` - expands to filteringSelector matchers
115117
- `%(groupLabels)s` - expands to groupLabels list
116118
- `%(instanceLabels)s` - expands to instanceLabels list

common-lib/common/signal/base.libsonnet

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet';
8282
(
8383
if aggLevel == 'group' then super.groupLabels
8484
else if aggLevel == 'instance' then super.instanceLabels
85-
else if aggLevel == 'none' then []
85+
else if aggLevel == 'none' then super.instanceLabels
8686
),
8787
aggLegend: utils.labelsToPanelLegend(
8888
// keep last label
@@ -123,6 +123,8 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet';
123123
),
124124
],
125125
queriesSelector+: ',' + mixin,
126+
queriesSelectorGroupOnly+: ',' + mixin,
127+
queriesSelectorFilterOnly+: ',' + mixin,
126128
},
127129
},
128130

@@ -287,6 +289,8 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet';
287289
interval: this.vars.alertsInterval,
288290
// keep only filteringSelector, remove any Grafana dashboard variables:
289291
queriesSelector: this.vars.filteringSelector[0],
292+
queriesSelectorGroupOnly: this.vars.filteringSelector[0],
293+
queriesSelectorFilterOnly: this.vars.filteringSelector[0],
290294
}
291295
for source in this.sourceMaps
292296
]

common-lib/common/signal/signal.libsonnet

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ local info = import './info.libsonnet';
88
local log = import './log.libsonnet';
99
local raw = import './raw.libsonnet';
1010
local stub = import './stub.libsonnet';
11+
local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet';
1112
{
1213
//Expected signalsJson format:
1314
// {
@@ -211,6 +212,8 @@ local stub = import './stub.libsonnet';
211212
groupLabels: groupLabels,
212213
instanceLabels: instanceLabels,
213214
queriesSelector: grafanaVariables.queriesSelector,
215+
queriesSelectorGroupOnly: grafanaVariables.queriesSelectorGroupOnly,
216+
queriesSelectorFilterOnly: grafanaVariables.queriesSelectorFilterOnly,
214217
interval: interval,
215218
alertsInterval: alertsInterval,
216219
},
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
local signal = import './signal.libsonnet';
2+
local test = import 'jsonnetunit/test.libsonnet';
3+
4+
{
5+
queriesSelectorGroupOnly: {
6+
local signalInit = signal.init(
7+
filteringSelector=['job="integrations/agent"'],
8+
groupLabels=['job'],
9+
instanceLabels=['instance'],
10+
aggLevel='group',
11+
),
12+
13+
local testSignal = signalInit.addSignal(
14+
name='Test metric',
15+
nameShort='test',
16+
type='gauge',
17+
unit='short',
18+
description='Test metric',
19+
sourceMaps=[
20+
{
21+
expr: 'test_metric{%(queriesSelectorGroupOnly)s}',
22+
exprWrappers: [],
23+
rangeFunction: 'rate',
24+
aggFunction: 'avg',
25+
aggKeepLabels: [],
26+
infoLabel: null,
27+
type: 'gauge',
28+
legendCustomTemplate: null,
29+
valueMappings: [],
30+
quantile: 0.95,
31+
},
32+
],
33+
),
34+
35+
local raw = testSignal.asTarget(),
36+
testResult: test.suite({
37+
testExpression: {
38+
actual: raw.expr,
39+
expect: 'avg by (job) (\n test_metric{job="integrations/agent",job=~"$job"}\n)',
40+
},
41+
}),
42+
},
43+
44+
queriesSelectorFilterOnly: {
45+
local signalInit = signal.init(
46+
filteringSelector=['job="integrations/agent"'],
47+
groupLabels=['job'],
48+
instanceLabels=['instance'],
49+
aggLevel='group',
50+
),
51+
52+
local testSignal = signalInit.addSignal(
53+
name='Test metric',
54+
nameShort='test',
55+
type='gauge',
56+
unit='short',
57+
description='Test metric',
58+
sourceMaps=[
59+
{
60+
expr: 'test_metric{%(queriesSelectorFilterOnly)s}',
61+
exprWrappers: [],
62+
rangeFunction: 'rate',
63+
aggFunction: 'avg',
64+
aggKeepLabels: [],
65+
infoLabel: null,
66+
type: 'gauge',
67+
legendCustomTemplate: null,
68+
valueMappings: [],
69+
quantile: 0.95,
70+
},
71+
],
72+
),
73+
74+
local raw = testSignal.asTarget(),
75+
testResult: test.suite({
76+
testExpression: {
77+
actual: raw.expr,
78+
expect: 'avg by (job) (\n test_metric{job="integrations/agent"}\n)',
79+
},
80+
}),
81+
},
82+
83+
// Test asRuleExpression - returns expression without Grafana variables, suitable for alerts
84+
asRuleExpression: {
85+
// Test with gauge type
86+
gauge: {
87+
local signalInit = signal.init(
88+
filteringSelector=['job="integrations/agent"'],
89+
groupLabels=['job'],
90+
instanceLabels=['instance'],
91+
aggLevel='group',
92+
alertsInterval='5m',
93+
),
94+
95+
local testSignal = signalInit.addSignal(
96+
name='Test metric',
97+
nameShort='test',
98+
type='gauge',
99+
unit='short',
100+
description='Test metric',
101+
sourceMaps=[
102+
{
103+
expr: 'test_metric{%(queriesSelector)s}',
104+
exprWrappers: [],
105+
rangeFunction: 'rate',
106+
aggFunction: 'avg',
107+
aggKeepLabels: [],
108+
infoLabel: null,
109+
type: 'gauge',
110+
legendCustomTemplate: null,
111+
valueMappings: [],
112+
quantile: 0.95,
113+
},
114+
],
115+
),
116+
117+
local raw = testSignal.asRuleExpression(),
118+
testResult: test.suite({
119+
testExpression: {
120+
actual: raw,
121+
expect: 'test_metric{job="integrations/agent"}',
122+
},
123+
}),
124+
},
125+
126+
// Test with counter type
127+
counter: {
128+
local signalInit = signal.init(
129+
filteringSelector=['job="integrations/agent"'],
130+
groupLabels=['job'],
131+
instanceLabels=['instance'],
132+
aggLevel='group',
133+
alertsInterval='5m',
134+
),
135+
136+
local testSignal = signalInit.addSignal(
137+
name='Test counter',
138+
nameShort='counter',
139+
type='counter',
140+
unit='requests',
141+
description='Test counter',
142+
sourceMaps=[
143+
{
144+
expr: 'test_counter_total{%(queriesSelector)s}',
145+
exprWrappers: [],
146+
rangeFunction: 'increase',
147+
aggFunction: 'avg',
148+
aggKeepLabels: [],
149+
infoLabel: null,
150+
type: 'counter',
151+
legendCustomTemplate: null,
152+
valueMappings: [],
153+
quantile: 0.95,
154+
},
155+
],
156+
),
157+
158+
local raw = testSignal.asRuleExpression(),
159+
testResult: test.suite({
160+
testExpression: {
161+
actual: raw,
162+
expect: 'increase(test_counter_total{job="integrations/agent"}[5m:] offset -5m)',
163+
},
164+
}),
165+
},
166+
},
167+
168+
// Test withFilteringSelectorMixin - adds additional filtering selector
169+
withFilteringSelectorMixin: {
170+
// Test basic filtering selector mixin
171+
basic: {
172+
local signalInit = signal.init(
173+
filteringSelector=['job="integrations/agent"'],
174+
groupLabels=['job'],
175+
instanceLabels=['instance'],
176+
aggLevel='group',
177+
),
178+
179+
local testSignal = signalInit.addSignal(
180+
name='Test metric',
181+
nameShort='test',
182+
type='gauge',
183+
unit='short',
184+
description='Test metric',
185+
sourceMaps=[
186+
{
187+
expr: 'test_metric{%(queriesSelector)s}',
188+
exprWrappers: [],
189+
rangeFunction: 'rate',
190+
aggFunction: 'avg',
191+
aggKeepLabels: [],
192+
infoLabel: null,
193+
type: 'gauge',
194+
legendCustomTemplate: null,
195+
valueMappings: [],
196+
quantile: 0.95,
197+
},
198+
],
199+
),
200+
201+
local raw = testSignal.withFilteringSelectorMixin('environment="prod"').asTarget(),
202+
testResult: test.suite({
203+
testExpression: {
204+
actual: raw.expr,
205+
expect: 'avg by (job) (\n test_metric{job="integrations/agent",job=~"$job",instance=~"$instance",environment="prod"}\n)',
206+
},
207+
}),
208+
},
209+
210+
// Test filtering selector mixin with asRuleExpression
211+
withAsRuleExpression: {
212+
local signalInit = signal.init(
213+
filteringSelector=['job="integrations/agent"'],
214+
groupLabels=['job'],
215+
instanceLabels=['instance'],
216+
aggLevel='group',
217+
alertsInterval='5m',
218+
),
219+
220+
local testSignal = signalInit.addSignal(
221+
name='Test metric',
222+
nameShort='test',
223+
type='gauge',
224+
unit='short',
225+
description='Test metric',
226+
sourceMaps=[
227+
{
228+
expr: 'test_metric{%(queriesSelector)s}',
229+
exprWrappers: [],
230+
rangeFunction: 'rate',
231+
aggFunction: 'avg',
232+
aggKeepLabels: [],
233+
infoLabel: null,
234+
type: 'gauge',
235+
legendCustomTemplate: null,
236+
valueMappings: [],
237+
quantile: 0.95,
238+
},
239+
],
240+
),
241+
242+
local raw = testSignal.withFilteringSelectorMixin('environment="prod"').asRuleExpression(),
243+
testResult: test.suite({
244+
testExpression: {
245+
actual: raw,
246+
expect: 'test_metric{job="integrations/agent",environment="prod"}',
247+
},
248+
}),
249+
},
250+
},
251+
}

common-lib/common/variables/variables.libsonnet

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,22 @@ local utils = import '../utils.libsonnet';
101101
utils.labelsToPromQLSelector(groupLabels + instanceLabels),
102102
])
103103
),
104+
queriesSelectorGroupOnly:
105+
std.join(
106+
',',
107+
std.filter(function(x) std.length(x) > 0, [
108+
_filteringSelector,
109+
utils.labelsToPromQLSelector(groupLabels),
110+
])
111+
),
112+
queriesSelectorFilterOnly:
113+
std.join(
114+
',',
115+
std.filter(function(x) std.length(x) > 0, [
116+
_filteringSelector,
117+
'',
118+
])
119+
),
104120

105121
}
106122
+ if enableLokiLogs then self.withLokiLogs() else {},

0 commit comments

Comments
 (0)