Skip to content

Commit 7172059

Browse files
authored
Add withQuantile function (#1414)
1 parent a724adf commit 7172059

File tree

7 files changed

+89
-18
lines changed

7 files changed

+89
-18
lines changed

common-lib/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 0.3.3
2+
- [Signal] add `withQuantile(quantile=0.95)` to histogram signals.
3+
14
# 0.3.2
25
- [Signal] Fix combining info metrics.
36

@@ -11,7 +14,6 @@
1114
- [Signal] Add enableLokiLogs=true|false to signals init.
1215
- [Signal] `withExprWrappersMixin(offset)` - wrap signal expression into additional function on top of existing wrappers.
1316

14-
1517
# 0.2.0
1618

1719
- [Signal] `withOffset(offset)` - add offset modifier to the expression.

common-lib/common/signal/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ These functions modify one of the signal's property and then return signal back
2525
- withExprWrappersMixin(wrapper=[]) - wrap signal expression into additional function on top of existing wrappers.
2626
- withOffset(offset) - add offset modifier to the expression.
2727
- withFilteringSelectorMixin(mixin) - add additional selector to filteringSelector used.
28+
- withQuantile(quantile=0.95) - add quantile modifier to the expression for histogram signals.
2829

2930
### Render functions
3031

@@ -103,6 +104,7 @@ Signal's level:
103104
|sourceMaps[].valueMappings| Define signal's valueMappings in the same way defined in Grafana Dashboard Schema. |*|-|-|
104105
|sourceMaps[].legendCustomTemplate| A custom legend template could be defined with this to override automatic legend's generation|*|`null`|`{{topic}}`|
105106
|sourceMaps[].rangeFunction| Rate function to use for counter metrics.|rate,irate,delta,idelta,increase|`rate`|`increase`|
107+
|sourceMaps[].quantile| Only applicable to `histogram` metrics. Defines quantile for histogram metrics. |0.01-0.99|`0.99`|`0.95`|
106108

107109
## Expressions templating
108110

common-lib/common/signal/base.libsonnet

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet';
257257
type,
258258
source.expr,
259259
exprWrappers=std.get(source, 'exprWrappers', default=[]),
260+
q=std.get(source, 'quantile', default=0.95),
260261
aggLevel=aggLevel,
261262
rangeFunction=source.rangeFunction,
262263
).applyFunctions()
@@ -274,6 +275,7 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet';
274275
type,
275276
source.expr,
276277
exprWrappers=std.get(source, 'exprWrappers', default=[]),
278+
q=std.get(source, 'quantile', default=0.95),
277279
aggLevel='none',
278280
rangeFunction=source.rangeFunction,
279281
).applyFunctions()

common-lib/common/signal/histogram.libsonnet

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ base {
3030
)
3131

3232
{
33+
local this = self,
34+
withQuantile(quantile=0.95):
35+
self
36+
{
37+
sourceMaps:
38+
[
39+
source
40+
{
41+
quantile: quantile,
42+
}
43+
for source in super.sourceMaps
44+
],
45+
},
3346
},
34-
3547
}

common-lib/common/signal/signal.libsonnet

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ local stub = import './stub.libsonnet';
7070
type: std.get(signalsJson.signals[s], 'type', error 'Must provide type for signal %s' % signalsJson.signals[s].name),
7171
legendCustomTemplate: std.get(signalsJson.signals[s], 'legendCustomTemplate', std.get(signalsJson, 'legendCustomTemplate', null)),
7272
valueMappings: std.get(signalsJson.signals[s], 'valueMappings', []),
73+
quantile: std.get(signalsJson.signals[s], 'quantile', 0.95),
7374
},
7475
],
7576
)
@@ -132,6 +133,7 @@ local stub = import './stub.libsonnet';
132133
infoLabel: std.get(source.value, 'infoLabel', null),
133134
legendCustomTemplate: std.get(source.value, 'legendCustomTemplate', std.get(signalsJson, 'legendCustomTemplate', null)),
134135
valueMappings: std.get(source.value, 'valueMappings', []),
136+
quantile: std.get(source.value, 'quantile', 0.95),
135137
}
136138
for source in std.objectKeysValues(signalsJson.signals[s].sources)
137139
if std.member(validatedArr, source.key)
@@ -246,6 +248,7 @@ local stub = import './stub.libsonnet';
246248
type: type,
247249
legendCustomTemplate: null,
248250
valueMappings: [],
251+
quantile: 0.95,
249252
},
250253
],
251254
):

common-lib/common/signal/test_gauge.libsonnet

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,32 +51,49 @@ local gauge1 = signal.init(
5151
},
5252
}),
5353
},
54+
asTargetWithcombinedTransformations: {
55+
local raw = gauge1
56+
.withTopK(3)
57+
.withOffset('30m')
58+
.withFilteringSelectorMixin('region="us-east"')
59+
.asTarget(),
60+
testResult: test.suite({
61+
testExpression: {
62+
actual: raw.expr,
63+
expect: 'topk(3,\n avg by (job) (\n (up{job="integrations/agent",job=~"$job",instance=~"$instance",region="us-east"} offset 30m)\n)\n)',
64+
},
65+
testLegend: {
66+
actual: raw.legendFormat,
67+
expect: '{{job}}: Up',
68+
},
69+
}),
70+
},
5471
asTimeSeries:
5572
{
56-
raw:: gauge1.asTimeSeries(),
73+
local raw = gauge1.asTimeSeries(),
5774
testResult: test.suite({
5875
testTStitle: {
59-
actual: gauge1.asTimeSeries().title,
76+
actual: raw.title,
6077
expect: 'Up metric',
6178
},
6279
testUnit: {
63-
actual: gauge1.asTimeSeries().fieldConfig.overrides[0].properties[1].value,
80+
actual: raw.fieldConfig.overrides[0].properties[1].value,
6481
expect: 'short',
6582
},
6683
testValueMapping: {
67-
actual: gauge1.asTimeSeries().fieldConfig.overrides[0].properties[0].value,
84+
actual: raw.fieldConfig.overrides[0].properties[0].value,
6885
expect: [{ options: { '0': { color: 'light-red', index: 0, text: 'Down' }, '1': { color: 'light-green', index: 1, text: 'Up' } }, type: 'value' }],
6986
},
7087
testTStype: {
71-
actual: gauge1.asTimeSeries().type,
88+
actual: raw.type,
7289
expect: 'timeseries',
7390
},
7491
testTSversion: {
75-
actual: gauge1.asTimeSeries().pluginVersion,
92+
actual: raw.pluginVersion,
7693
expect: 'v11.0.0',
7794
},
7895
testTSUid: {
79-
actual: gauge1.asTimeSeries().datasource,
96+
actual: raw.datasource,
8097
expect: {
8198
uid: '${datasource}',
8299
type: 'prometheus',

common-lib/common/signal/test_histogram.libsonnet

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,78 @@ local m1 = signal.init(
2626

2727
{
2828
asTarget: {
29-
raw:: m1.asTarget(),
29+
local raw = m1.asTarget(),
3030
testResult: test.suite({
3131
testLegend: {
32-
actual: m1.asTarget().legendFormat,
32+
actual: raw.legendFormat,
3333
expect: '{{job}}: duration',
3434
},
3535
testExpression: {
36-
actual: m1.asTarget().expr,
36+
actual: raw.expr,
3737
expect: 'avg by (job) (\n histogram_quantile(0.95, sum(rate(apiserver_request_duration_seconds_bucket{job="abc",job=~"$job",instance=~"$instance"}[10m])) by (le,job))\n)',
3838
},
3939
}),
4040
},
4141
asTimeSeries:
4242
{
43-
raw:: m1.asTimeSeries(),
43+
local raw = m1.asTimeSeries(),
4444
testResult: test.suite({
4545
testTStitle: {
46-
actual: m1.asTimeSeries().title,
46+
actual: raw.title,
4747
expect: 'API server duration',
4848
},
4949
testUnit: {
50-
actual: m1.asTimeSeries().fieldConfig.overrides[0].properties[0].value,
50+
actual: raw.fieldConfig.overrides[0].properties[0].value,
5151
expect: 'seconds',
5252
},
5353
testTStype: {
54-
actual: m1.asTimeSeries().type,
54+
actual: raw.type,
5555
expect: 'timeseries',
5656
},
5757
testTSversion: {
58-
actual: m1.asTimeSeries().pluginVersion,
58+
actual: raw.pluginVersion,
5959
expect: 'v11.0.0',
6060
},
6161
testTSUid: {
62-
actual: m1.asTimeSeries().datasource,
62+
actual: raw.datasource,
6363
expect: {
6464
uid: '${datasource}',
6565
type: 'prometheus',
6666
},
6767
},
6868
}),
6969
},
70+
withCustomQuantile: {
71+
local customHistogram = signal.init(
72+
filteringSelector=['job="abc"'],
73+
interval='10m',
74+
aggLevel='group',
75+
aggFunction='avg',
76+
).addSignal(
77+
name='Custom quantile',
78+
nameShort='p99',
79+
type='histogram',
80+
unit='seconds',
81+
description='99th percentile',
82+
83+
sourceMaps=[{
84+
expr: 'http_request_duration_seconds_bucket{%(queriesSelector)s}',
85+
rangeFunction: 'rate',
86+
aggKeepLabels: ['handler'],
87+
quantile: 0.99,
88+
infoLabel: null,
89+
}],
90+
),
91+
92+
testResult: test.suite({
93+
testDefaultQuantile: {
94+
actual: customHistogram.asTarget().expr,
95+
expect: 'avg by (job,handler) (\n histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{job="abc",job=~"$job",instance=~"$instance"}[10m])) by (le,job,handler))\n)',
96+
},
97+
testCustomQuantile: {
98+
actual: customHistogram.withQuantile(quantile=0.50).asTarget().expr,
99+
expect: 'avg by (job,handler) (\n histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket{job="abc",job=~"$job",instance=~"$instance"}[10m])) by (le,job,handler))\n)',
100+
},
101+
}),
102+
},
70103
}

0 commit comments

Comments
 (0)