summaryrefslogtreecommitdiffstats
path: root/src/web/api/formatters/value
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:18 +0000
commit5da14042f70711ea5cf66e034699730335462f66 (patch)
tree0f6354ccac934ed87a2d555f45be4c831cf92f4a /src/web/api/formatters/value
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-5da14042f70711ea5cf66e034699730335462f66.tar.xz
netdata-5da14042f70711ea5cf66e034699730335462f66.zip
Merging upstream version 1.45.3+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/web/api/formatters/value')
-rw-r--r--src/web/api/formatters/value/README.md28
-rw-r--r--src/web/api/formatters/value/value.c153
-rw-r--r--src/web/api/formatters/value/value.h33
3 files changed, 214 insertions, 0 deletions
diff --git a/src/web/api/formatters/value/README.md b/src/web/api/formatters/value/README.md
new file mode 100644
index 000000000..3599a836e
--- /dev/null
+++ b/src/web/api/formatters/value/README.md
@@ -0,0 +1,28 @@
+<!--
+title: "Value formatter"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/web/api/formatters/value/README.md
+sidebar_label: "Value formatter"
+learn_status: "Published"
+learn_topic_type: "References"
+learn_rel_path: "Developers/Web/Api/Formatters"
+-->
+
+# Value formatter
+
+The Value formatter presents [results of database queries](https://github.com/netdata/netdata/blob/master/src/web/api/queries/README.md) as a single value.
+
+To calculate the single value to be returned, it sums the values of all dimensions.
+
+The Value formatter respects the following API `&options=`:
+
+| option | supported | description |
+|:----: |:-------: |:---------- |
+| `percent` | yes | to replace all values with their percentage over the row total|
+| `abs` | yes | to turn all values positive, before using them |
+| `min2max` | yes | to return the delta from the minimum value to the maximum value (across dimensions)|
+
+The Value formatter is not exposed by the API by itself.
+Instead it is used by the [`ssv`](https://github.com/netdata/netdata/blob/master/src/web/api/formatters/ssv/README.md) formatter
+and [health monitoring queries](https://github.com/netdata/netdata/blob/master/src/health/README.md).
+
+
diff --git a/src/web/api/formatters/value/value.c b/src/web/api/formatters/value/value.c
new file mode 100644
index 000000000..0ec1b1265
--- /dev/null
+++ b/src/web/api/formatters/value/value.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "value.h"
+
+inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all_values_are_null, NETDATA_DOUBLE *anomaly_rate) {
+ size_t c;
+
+ NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
+ RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
+ NETDATA_DOUBLE *ar = &r->ar[ i * r->d ];
+
+ NETDATA_DOUBLE sum = 0, min = NAN, max = NAN, v = NAN;
+ size_t dims = 0;
+
+ NETDATA_DOUBLE total_anomaly_rate = 0;
+
+ // for each dimension
+ for (c = 0; c < r->d ; c++) {
+ if(unlikely(!rrdr_dimension_should_be_exposed(r->od[c], options)))
+ continue;
+
+ if(unlikely((co[c] & RRDR_VALUE_EMPTY)))
+ continue;
+
+ NETDATA_DOUBLE n = cn[c];
+
+ if(unlikely(!dims))
+ min = max = n;
+
+ sum += n;
+
+ if (n < min) min = n;
+ if (n > max) max = n;
+
+ total_anomaly_rate += ar[c];
+
+ dims++;
+ }
+
+ if(!dims) {
+ if(anomaly_rate)
+ *anomaly_rate = 0;
+
+ if(all_values_are_null)
+ *all_values_are_null = 1;
+
+ return (options & RRDR_OPTION_NULL2ZERO) ? 0 : NAN;
+ }
+
+ if(anomaly_rate)
+ *anomaly_rate = total_anomaly_rate / (NETDATA_DOUBLE)dims;
+
+ if(all_values_are_null)
+ *all_values_are_null = 0;
+
+ if(options & RRDR_OPTION_DIMS_MIN2MAX)
+ v = max - min;
+ else if(options & RRDR_OPTION_DIMS_AVERAGE)
+ v = sum / (NETDATA_DOUBLE)dims;
+ else if(options & RRDR_OPTION_DIMS_MIN)
+ v = min;
+ else if(options & RRDR_OPTION_DIMS_MAX)
+ v = max;
+ else
+ v = sum;
+
+ if((options & RRDR_OPTION_NULL2ZERO) && (isnan(v) || isinf(v)))
+ v = 0;
+
+ return v;
+}
+
+QUERY_VALUE rrdmetric2value(RRDHOST *host,
+ struct rrdcontext_acquired *rca, struct rrdinstance_acquired *ria, struct rrdmetric_acquired *rma,
+ time_t after, time_t before,
+ RRDR_OPTIONS options, RRDR_TIME_GROUPING time_group_method, const char *time_group_options,
+ size_t tier, time_t timeout, QUERY_SOURCE query_source, STORAGE_PRIORITY priority
+) {
+ QUERY_TARGET_REQUEST qtr = {
+ .version = 1,
+ .host = host,
+ .rca = rca,
+ .ria = ria,
+ .rma = rma,
+ .after = after,
+ .before = before,
+ .points = 1,
+ .options = options,
+ .time_group_method = time_group_method,
+ .time_group_options = time_group_options,
+ .tier = tier,
+ .timeout_ms = timeout,
+ .query_source = query_source,
+ .priority = priority,
+ };
+
+ ONEWAYALLOC *owa = onewayalloc_create(16 * 1024);
+ QUERY_TARGET *qt = query_target_create(&qtr);
+ RRDR *r = rrd2rrdr(owa, qt);
+
+ QUERY_VALUE qv;
+
+ if(!r || rrdr_rows(r) == 0) {
+ qv = (QUERY_VALUE) {
+ .value = NAN,
+ .anomaly_rate = NAN,
+ .sp = {
+ .count = 0,
+ .min = NAN,
+ .max = NAN,
+ .sum = NAN,
+ .anomaly_count = 0,
+ },
+ .duration_ut = (r) ? r->internal.qt->timings.executed_ut - r->internal.qt->timings.received_ut : 0,
+ };
+ }
+ else {
+ qv = (QUERY_VALUE) {
+ .after = r->view.after,
+ .before = r->view.before,
+ .points_read = r->stats.db_points_read,
+ .result_points = r->stats.result_points_generated,
+ .sp = {
+ .count = 0,
+ },
+ .duration_ut = r->internal.qt->timings.executed_ut - r->internal.qt->timings.received_ut,
+ };
+
+ for(size_t d = 0; d < r->internal.qt->query.used ;d++) {
+ if(!rrdr_dimension_should_be_exposed(r->internal.qt->query.array[d].status, options))
+ continue;
+
+ storage_point_merge_to(qv.sp, r->internal.qt->query.array[d].query_points);
+ }
+
+ for(size_t t = 0; t < storage_tiers ;t++)
+ qv.storage_points_per_tier[t] = r->internal.qt->db.tiers[t].points;
+
+ long i = (!(options & RRDR_OPTION_REVERSED))?(long)rrdr_rows(r) - 1:0;
+ int all_values_are_null = 0;
+ qv.value = rrdr2value(r, i, options, &all_values_are_null, &qv.anomaly_rate);
+ if(all_values_are_null) {
+ qv.value = NAN;
+ qv.anomaly_rate = NAN;
+ }
+ }
+
+ rrdr_free(owa, r);
+ query_target_release(qt);
+ onewayalloc_destroy(owa);
+
+ return qv;
+}
diff --git a/src/web/api/formatters/value/value.h b/src/web/api/formatters/value/value.h
new file mode 100644
index 000000000..072ca14f8
--- /dev/null
+++ b/src/web/api/formatters/value/value.h
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_API_FORMATTER_VALUE_H
+#define NETDATA_API_FORMATTER_VALUE_H
+
+#include "../rrd2json.h"
+
+typedef struct storage_value {
+ NETDATA_DOUBLE value;
+ NETDATA_DOUBLE anomaly_rate;
+ time_t after;
+ time_t before;
+ size_t points_read;
+ size_t storage_points_per_tier[RRD_STORAGE_TIERS];
+ size_t result_points;
+ STORAGE_POINT sp;
+ usec_t duration_ut;
+} QUERY_VALUE;
+
+struct rrdmetric_acquired;
+struct rrdinstance_acquired;
+struct rrdcontext_acquired;
+
+QUERY_VALUE rrdmetric2value(RRDHOST *host,
+ struct rrdcontext_acquired *rca, struct rrdinstance_acquired *ria, struct rrdmetric_acquired *rma,
+ time_t after, time_t before,
+ RRDR_OPTIONS options, RRDR_TIME_GROUPING time_group_method, const char *time_group_options,
+ size_t tier, time_t timeout, QUERY_SOURCE query_source, STORAGE_PRIORITY priority
+);
+
+NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all_values_are_null, NETDATA_DOUBLE *anomaly_rate);
+
+#endif //NETDATA_API_FORMATTER_VALUE_H