improve(health/dyncfg): Add source unit field to alert value (#21326)
Ilya Mashchenko committed
Nov 20, 2025 at 17:01 UTC
f81b2d18d1818571b045f9ebd6a7ab0784231556
1 file changed
+287
-73
src/health/schema.d/health%3Aalert%3Aprototype.json
+287
-73
@@ -23,8 +23,12 @@
23
"title": "The instance this rule should be applied to.",
24
"description": "You can find the instance names on all charts at the instances drop down menu. Do not include the host name in this field."
25
},
26
- "host_labels": { "$ref": "#/definitions/matchHostLabels" },
27
- "instance_labels": { "$ref": "#/definitions/matchInstanceLabels" }
26
+ "host_labels": {
27
+ "$ref": "#/definitions/matchHostLabels"
28
+ },
29
+ "instance_labels": {
30
+ "$ref": "#/definitions/matchInstanceLabels"
31
+ }
32
},
33
"required": [
34
"on",
@@ -43,8 +47,12 @@
47
"title": "The context of the instances this rule should be applied to.",
48
"description": "The context is the code-name of each chart on the dashboard, that appears at the chart title bar, between the chart title and its unit of measurement, like: system.cpu, disk.io, etc."
49
},
46
- "host_labels": { "$ref": "#/definitions/matchHostLabels" },
47
- "instance_labels": { "$ref": "#/definitions/matchInstanceLabels" }
50
+ "host_labels": {
51
+ "$ref": "#/definitions/matchHostLabels"
52
+ },
53
+ "instance_labels": {
54
+ "$ref": "#/definitions/matchInstanceLabels"
55
+ }
56
},
57
"required": [
58
"on",
@@ -90,9 +98,21 @@
98
"data_source": {
99
"type": "string",
100
"oneOf": [
93
- { "const": "samples", "title": "Samples", "description": "Use the time-series values for each dimension" },
94
- { "const": "percentages", "title": "Percentages", "description": "Use the percentage of each dimension vs the sum of all dimensions" },
95
- { "const": "anomalies", "title": "Anomalies", "description": "Use the anomaly rate of each dimension" }
101
+ {
102
+ "const": "samples",
103
+ "title": "Samples",
104
+ "description": "Use the time-series values for each dimension"
105
+ },
106
+ {
107
+ "const": "percentages",
108
+ "title": "Percentages",
109
+ "description": "Use the percentage of each dimension vs the sum of all dimensions"
110
+ },
111
+ {
112
+ "const": "anomalies",
113
+ "title": "Anomalies",
114
+ "description": "Use the anomaly rate of each dimension"
115
+ }
116
],
117
"default": "samples",
118
"title": " ",
@@ -101,20 +121,62 @@
121
"time_group": {
122
"type": "string",
123
"oneOf": [
104
- { "const": "average", "title": "Average" },
105
- { "const": "median", "title": "Median" },
106
- { "const": "min", "title": "Minimum" },
107
- { "const": "max", "title": "Maximum" },
108
- { "const": "sum", "title": "Sum" },
109
- { "const": "incremental_sum", "title": "Incremental Sum" },
110
- { "const": "stddev", "title": "Standard Deviation" },
111
- { "const": "cv", "title": "Coefficient of Variation" },
112
- { "const": "trimmed-mean", "title": "Trimmed Mean" },
113
- { "const": "trimmed-median", "title": "Trimmed Median" },
114
- { "const": "percentile", "title": "Percentile" },
115
- { "const": "ses", "title": "Simple Exponential Smoothing" },
116
- { "const": "des", "title": "Double Exponential Smoothing" },
117
- { "const": "countif", "title": "Count If" }
124
+ {
125
+ "const": "average",
126
+ "title": "Average"
127
+ },
128
+ {
129
+ "const": "median",
130
+ "title": "Median"
131
+ },
132
+ {
133
+ "const": "min",
134
+ "title": "Minimum"
135
+ },
136
+ {
137
+ "const": "max",
138
+ "title": "Maximum"
139
+ },
140
+ {
141
+ "const": "sum",
142
+ "title": "Sum"
143
+ },
144
+ {
145
+ "const": "incremental_sum",
146
+ "title": "Incremental Sum"
147
+ },
148
+ {
149
+ "const": "stddev",
150
+ "title": "Standard Deviation"
151
+ },
152
+ {
153
+ "const": "cv",
154
+ "title": "Coefficient of Variation"
155
+ },
156
+ {
157
+ "const": "trimmed-mean",
158
+ "title": "Trimmed Mean"
159
+ },
160
+ {
161
+ "const": "trimmed-median",
162
+ "title": "Trimmed Median"
163
+ },
164
+ {
165
+ "const": "percentile",
166
+ "title": "Percentile"
167
+ },
168
+ {
169
+ "const": "ses",
170
+ "title": "Simple Exponential Smoothing"
171
+ },
172
+ {
173
+ "const": "des",
174
+ "title": "Double Exponential Smoothing"
175
+ },
176
+ {
177
+ "const": "countif",
178
+ "title": "Count If"
179
+ }
180
],
181
"default": "average",
182
"title": "Time Aggregation",
@@ -135,11 +197,31 @@
197
"dims_group": {
198
"type": "string",
199
"oneOf": [
138
- { "const": "average", "title": "Average", "description": "The average of all dimensions" },
139
- { "const": "min", "title": "Minimum", "description": "The minimum of all dimensions" },
140
- { "const": "max", "title": "Maximum", "description": "The maximum of all dimensions" },
141
- { "const": "sum", "title": "Sum", "description": "The sum of all dimensions" },
142
- { "const": "min2max", "title": "Min-to-Max", "description": "The delta between the minimum of the maximum of the dimensions" }
200
+ {
201
+ "const": "average",
202
+ "title": "Average",
203
+ "description": "The average of all dimensions"
204
+ },
205
+ {
206
+ "const": "min",
207
+ "title": "Minimum",
208
+ "description": "The minimum of all dimensions"
209
+ },
210
+ {
211
+ "const": "max",
212
+ "title": "Maximum",
213
+ "description": "The maximum of all dimensions"
214
+ },
215
+ {
216
+ "const": "sum",
217
+ "title": "Sum",
218
+ "description": "The sum of all dimensions"
219
+ },
220
+ {
221
+ "const": "min2max",
222
+ "title": "Min-to-Max",
223
+ "description": "The delta between the minimum of the maximum of the dimensions"
224
+ }
225
],
226
"default": "sum",
227
"title": "Dims Aggregation",
@@ -158,14 +240,31 @@
240
"uniqueItems": true,
241
"items": {
242
"oneOf": [
161
- { "const": "unaligned", "title": "Do not shift the time-frame for visual presentation" },
162
- { "const": "absolute", "title": "Make all values positive before using them" },
163
- { "const": "null2zero", "title": "Treat gaps in the time-series as a zero value" },
164
- { "const": "match_ids", "title": "Match only dimension IDs, not Names" },
165
- { "const": "match_names", "title": "Match only dimension Names, not IDs" }
243
+ {
244
+ "const": "unaligned",
245
+ "title": "Do not shift the time-frame for visual presentation"
246
+ },
247
+ {
248
+ "const": "absolute",
249
+ "title": "Make all values positive before using them"
250
+ },
251
+ {
252
+ "const": "null2zero",
253
+ "title": "Treat gaps in the time-series as a zero value"
254
+ },
255
+ {
256
+ "const": "match_ids",
257
+ "title": "Match only dimension IDs, not Names"
258
+ },
259
+ {
260
+ "const": "match_names",
261
+ "title": "Match only dimension Names, not IDs"
262
+ }
263
]
264
},
168
- "default": [ "unaligned" ]
265
+ "default": [
266
+ "unaligned"
267
+ ]
268
}
269
},
270
"allOf": [
@@ -173,7 +272,9 @@
272
"if": {
273
"properties": {
274
"time_group": {
176
- "enum": ["trimmed-mean"]
275
+ "enum": [
276
+ "trimmed-mean"
277
+ ]
278
}
279
}
280
},
@@ -186,14 +287,18 @@
287
"description": ""
288
}
289
},
189
- "required": ["time_group_value"]
290
+ "required": [
291
+ "time_group_value"
292
+ ]
293
}
294
},
295
{
296
"if": {
297
"properties": {
298
"time_group": {
196
- "enum": ["trimmed-median"]
299
+ "enum": [
300
+ "trimmed-median"
301
+ ]
302
}
303
}
304
},
@@ -206,14 +311,18 @@
311
"description": ""
312
}
313
},
209
- "required": ["time_group_value"]
314
+ "required": [
315
+ "time_group_value"
316
+ ]
317
}
318
},
319
{
320
"if": {
321
"properties": {
322
"time_group": {
216
- "enum": ["percentile"]
323
+ "enum": [
324
+ "percentile"
325
+ ]
326
}
327
}
328
},
@@ -226,7 +335,9 @@
335
"description": ""
336
}
337
},
229
- "required": ["time_group_value"]
338
+ "required": [
339
+ "time_group_value"
340
+ ]
341
}
342
},
343
{
@@ -242,12 +353,30 @@
353
"time_group_condition": {
354
"type": "string",
355
"oneOf": [
245
- { "const": "!=", "title": "!=" },
246
- { "const": "=", "title": "==" },
247
- { "const": ">=", "title": ">=" },
248
- { "const": ">", "title": ">" },
249
- { "const": "<=", "title": "<=" },
250
- { "const": "<", "title": "<" }
356
+ {
357
+ "const": "!=",
358
+ "title": "!="
359
+ },
360
+ {
361
+ "const": "=",
362
+ "title": "=="
363
+ },
364
+ {
365
+ "const": ">=",
366
+ "title": ">="
367
+ },
368
+ {
369
+ "const": ">",
370
+ "title": ">"
371
+ },
372
+ {
373
+ "const": "<=",
374
+ "title": "<="
375
+ },
376
+ {
377
+ "const": "<",
378
+ "title": "<"
379
+ }
380
],
381
"default": "equal",
382
"title": "Condition",
@@ -260,7 +389,10 @@
389
"description": ""
390
}
391
},
263
- "required": ["time_group_condition", "time_group_value"]
392
+ "required": [
393
+ "time_group_condition",
394
+ "time_group_value"
395
+ ]
396
}
397
}
398
]
@@ -270,6 +402,12 @@
402
"title": "Calculation",
403
"description": "An expression to transform the value"
404
},
405
+ "units_placeholder": {
406
+ "type": "string",
407
+ "default": "-",
408
+ "title": "Source unit",
409
+ "description": "before scaling in UI"
410
+ },
411
"units": {
412
"type": "string",
413
"title": "Unit",
@@ -319,7 +457,10 @@
457
"uniqueItems": true,
458
"items": {
459
"oneOf": [
322
- { "const": "no-clear-notification", "title": "Do not perform any action when the alert is cleared"}
460
+ {
461
+ "const": "no-clear-notification",
462
+ "title": "Do not perform any action when the alert is cleared"
463
+ }
464
]
465
},
466
"default": []
@@ -372,15 +513,33 @@
513
"title": "Alert Configuration",
514
"description": "The properties that control the value the alert will get, the conditions it will trigger, the back-off for notifications, the auto-repeating of notifications, etc.",
515
"properties": {
375
- "match": { "$ref": "#/definitions/matchInstance" },
376
- "summary": { "$ref": "#/definitions/configSummary" },
377
- "info": { "$ref": "#/definitions/configInfo" },
378
- "type": { "$ref": "#/definitions/configType" },
379
- "component": { "$ref": "#/definitions/configComponent" },
380
- "classification": { "$ref": "#/definitions/configClassification" },
381
- "value": { "$ref": "#/definitions/configValue" },
382
- "conditions": { "$ref": "#/definitions/configConditions" },
383
- "action": { "$ref": "#/definitions/configAction" }
516
+ "match": {
517
+ "$ref": "#/definitions/matchInstance"
518
+ },
519
+ "summary": {
520
+ "$ref": "#/definitions/configSummary"
521
+ },
522
+ "info": {
523
+ "$ref": "#/definitions/configInfo"
524
+ },
525
+ "type": {
526
+ "$ref": "#/definitions/configType"
527
+ },
528
+ "component": {
529
+ "$ref": "#/definitions/configComponent"
530
+ },
531
+ "classification": {
532
+ "$ref": "#/definitions/configClassification"
533
+ },
534
+ "value": {
535
+ "$ref": "#/definitions/configValue"
536
+ },
537
+ "conditions": {
538
+ "$ref": "#/definitions/configConditions"
539
+ },
540
+ "action": {
541
+ "$ref": "#/definitions/configAction"
542
+ }
543
},
544
"required": []
545
},
@@ -389,15 +548,33 @@
548
"title": "Alert Configuration",
549
"description": "The properties that control the value the alert will get, the conditions it will trigger, the back-off for notifications, the auto-repeating of notifications, etc.",
550
"properties": {
392
- "match": { "$ref": "#/definitions/matchTemplate" },
393
- "summary": { "$ref": "#/definitions/configSummary" },
394
- "info": { "$ref": "#/definitions/configInfo" },
395
- "type": { "$ref": "#/definitions/configType" },
396
- "component": { "$ref": "#/definitions/configComponent" },
397
- "classification": { "$ref": "#/definitions/configClassification" },
398
- "value": { "$ref": "#/definitions/configValue" },
399
- "conditions": { "$ref": "#/definitions/configConditions" },
400
- "action": { "$ref": "#/definitions/configAction" }
551
+ "match": {
552
+ "$ref": "#/definitions/matchTemplate"
553
+ },
554
+ "summary": {
555
+ "$ref": "#/definitions/configSummary"
556
+ },
557
+ "info": {
558
+ "$ref": "#/definitions/configInfo"
559
+ },
560
+ "type": {
561
+ "$ref": "#/definitions/configType"
562
+ },
563
+ "component": {
564
+ "$ref": "#/definitions/configComponent"
565
+ },
566
+ "classification": {
567
+ "$ref": "#/definitions/configClassification"
568
+ },
569
+ "value": {
570
+ "$ref": "#/definitions/configValue"
571
+ },
572
+ "conditions": {
573
+ "$ref": "#/definitions/configConditions"
574
+ },
575
+ "action": {
576
+ "$ref": "#/definitions/configAction"
577
+ }
578
},
579
"required": []
580
}
@@ -425,28 +602,43 @@
602
"type": {
603
"type": "string",
604
"oneOf": [
428
- { "const": "instance" , "title": "A specific Instance" },
429
- { "const": "template" , "title": "Each of the Instances" }
605
+ {
606
+ "const": "instance",
607
+ "title": "A specific Instance"
608
+ },
609
+ {
610
+ "const": "template",
611
+ "title": "Each of the Instances"
612
+ }
613
],
614
"default": "template",
615
"title": "Apply this rule to:",
616
"description": ""
617
}
618
},
436
- "required": [ "type", "enabled" ],
619
+ "required": [
620
+ "type",
621
+ "enabled"
622
+ ],
623
"if": {
624
"properties": {
439
- "type": { "const": "instance" }
625
+ "type": {
626
+ "const": "instance"
627
+ }
628
}
629
},
630
"then": {
631
"properties": {
444
- "config": { "$ref": "#/definitions/configInstance" }
632
+ "config": {
633
+ "$ref": "#/definitions/configInstance"
634
+ }
635
}
636
},
637
"else": {
638
"properties": {
449
- "config": { "$ref": "#/definitions/configTemplate" }
639
+ "config": {
640
+ "$ref": "#/definitions/configTemplate"
641
+ }
642
}
643
}
644
}
@@ -467,7 +659,7 @@
659
"ui:widget": "hidden"
660
},
661
"rules": {
470
- "ui:openEmptyItem": true,
662
+ "ui:openEmptyItem": true,
663
"items": {
664
"ui:classNames": "dyncfg-grid dyncfg-grid-col-6",
665
"enabled": {
@@ -555,8 +747,25 @@
747
},
748
"value": {
749
"ui:classNames": "dyncfg-grid dyncfg-grid-col-6 dyncfg-grid-col-span-1-6",
750
+ "ui:order": [
751
+ "database_lookup",
752
+ "calculation",
753
+ "units",
754
+ "update_every",
755
+ "units_placeholder"
756
+ ],
757
"database_lookup": {
559
- "ui:order": ["data_source", "time_group", "time_group_condition", "time_group_value", "after", "before", "dims_group", "dimensions", "options"],
758
+ "ui:order": [
759
+ "data_source",
760
+ "time_group",
761
+ "time_group_condition",
762
+ "time_group_value",
763
+ "after",
764
+ "before",
765
+ "dims_group",
766
+ "dimensions",
767
+ "options"
768
+ ],
769
"ui:classNames": "dyncfg-grid dyncfg-grid-col-6 dyncfg-grid-col-span-1-6",
770
"ui:collapsible": true,
771
"ui:initiallyExpanded": true,
@@ -608,7 +817,12 @@
817
},
818
"update_every": {
819
"ui:help": "The frequency this alarm is to be evaluated, in seconds.",
611
- "ui:classNames": "dyncfg-grid-col-span-6-1"
820
+ "ui:classNames": "dyncfg-grid-col-span-1-2"
821
+ },
822
+ "units_placeholder": {
823
+ "ui:widget": "unitsPlaceholder",
824
+ "ui:classNames": "dyncfg-grid-col-span-5-1",
825
+ "ui:help": "Netdata may display scaled units (e.g. bytes → GiB). Use the metric’s original unit to avoid confusion when writing alert expressions."
826
}
827
},
828
"conditions": {