@cryptotaxi247 / netdata-1 / commits / f81b2d18d

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": {