summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorCosta Tsaousis <costa@netdata.cloud>2023-03-21 21:53:47 +0200
committerGitHub <noreply@github.com>2023-03-21 21:53:47 +0200
commit5eed0545d46c3d227b87a23b0d0362a4f63e1bf0 (patch)
treef1d539574341a513d688277f3854ac055e1940ae /web
parent757c01aacfbe8cae892935a262f180c52355b874 (diff)
/api/v2/X part 5 (#14718)
* query timestamps are now pre-determined and alignment on timestamps is guarranteed * turn internal_fatal() to internal_error() to investigate the issue * handle query when no data exist in the db * check for non NULL dict when running dictionary garbage collect * support API v2 requests via ACLK * add nodes detailed information to /api/v2/nodes * fixed keys and added dummy nodes for completeness * added nodes_hard_hash, alerts_hard_hash, alerts_soft_hash; started building a nodes status object to reflect the current status of a node * make sure replication does not double count charts that are already being replicated * expose min and max in sts structures * added view_minimum_value and view_maximum_value; percentage calculation is now an additional pass on the data, removed from formatters; absolute value calculation is now done at the query level, removed from formatters * respect trimming in percentage calculation; updated swagger * api/v2/weights preparative work to support multi-node queries - still single node though * multi-node /api/v2/weights endpoint, supporting all the filtering parameters of /api/v2/data * when passing the raw option, the query exposes the hidden dimensions * fix compilation issues on older systems * the query engine now calculates per dimension min, max, sum, count, anomaly count * use the macro to calculate storage point anomaly rate * weights endpoint exposing version hashes * weights method=value shows min, max, average, sum, count, anomaly count, anomaly rate * query: expose RESET flag; do not add the same point multiple times to the aggregated point * weights: more compact output * weights requests can be interrupted * all /api/v2 requests can be interrupted and timeout * allow relative timestamps in weights * fix macos compilation warnings * Revert "fix macos compilation warnings" This reverts commit 8a1d24e41e9b58de566ac59f0c4b1c465bcc0592. * /api/v2/data group-by now works on dimension names, not ids * /api/v2/weights does not query metrics without retention and new output format * /api/v2/weights value and anomaly queries do context queries when contexts are filtered; query timeout is now always in ms
Diffstat (limited to 'web')
-rw-r--r--web/api/formatters/csv/csv.c35
-rw-r--r--web/api/formatters/json/json.c74
-rw-r--r--web/api/formatters/json_wrapper.c137
-rw-r--r--web/api/formatters/json_wrapper.h3
-rw-r--r--web/api/formatters/rrd2json.c4
-rw-r--r--web/api/formatters/rrd2json.h6
-rw-r--r--web/api/formatters/value/value.c52
-rw-r--r--web/api/formatters/value/value.h3
-rw-r--r--web/api/netdata-swagger.yaml37
-rw-r--r--web/api/queries/query.c536
-rw-r--r--web/api/queries/rrdr.c4
-rw-r--r--web/api/queries/rrdr.h5
-rw-r--r--web/api/queries/weights.c855
-rw-r--r--web/api/queries/weights.h38
-rw-r--r--web/api/web_api.c123
-rw-r--r--web/api/web_api.h2
-rw-r--r--web/api/web_api_v1.c98
-rw-r--r--web/api/web_api_v1.h3
-rw-r--r--web/api/web_api_v2.c23
-rw-r--r--web/server/web_client.h4
20 files changed, 1396 insertions, 646 deletions
diff --git a/web/api/formatters/csv/csv.c b/web/api/formatters/csv/csv.c
index 0c4580fb99..8f4950ddd8 100644
--- a/web/api/formatters/csv/csv.c
+++ b/web/api/formatters/csv/csv.c
@@ -61,7 +61,6 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
}
// for each line in the array
- NETDATA_DOUBLE total = 1;
for(i = start; i != end ;i += step) {
NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
@@ -84,22 +83,6 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
- if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
- total = 0;
- for(c = 0; c < used ;c++) {
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
-
- NETDATA_DOUBLE n = cn[c];
-
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- total += n;
- }
- // prevent a division by zero
- if(total == 0) total = 1;
- }
-
// for each dimension
for(c = 0; c < used ;c++) {
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
@@ -115,24 +98,8 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
else
buffer_strcat(wb, "null");
}
- else {
- if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
- n = n * 100 / total;
-
- if(unlikely(i == start && c == 0)) {
- r->view.min = r->view.max = n;
- }
- else {
- if (n < r->view.min) r->view.min = n;
- if (n > r->view.max) r->view.max = n;
- }
- }
-
+ else
buffer_print_netdata_double(wb, n);
- }
}
buffer_strcat(wb, endline);
diff --git a/web/api/formatters/json/json.c b/web/api/formatters/json/json.c
index dae0cc99cf..700f804d34 100644
--- a/web/api/formatters/json/json.c
+++ b/web/api/formatters/json/json.c
@@ -149,7 +149,6 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
);
// for each line in the array
- NETDATA_DOUBLE total = 1;
for(i = start; i != end ;i += step) {
NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
@@ -210,26 +209,6 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
buffer_fast_strcat(wb, post_date, post_date_len);
}
- if(unlikely((options & RRDR_OPTION_PERCENTAGE) && !(options & (RRDR_OPTION_INTERNAL_AR)))) {
- total = 0;
- for(c = 0; c < used ;c++) {
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
-
- NETDATA_DOUBLE n;
- if(unlikely(options & RRDR_OPTION_INTERNAL_AR))
- n = ar[c];
- else
- n = cn[c];
-
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- total += n;
- }
- // prevent a division by zero
- if(total == 0) total = 1;
- }
-
// for each dimension
for(c = 0; c < used ;c++) {
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
@@ -252,24 +231,8 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
else
buffer_fast_strcat(wb, "null", 4);
}
- else {
- if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- if(unlikely((options & RRDR_OPTION_PERCENTAGE) && !(options & (RRDR_OPTION_INTERNAL_AR)))) {
- n = n * 100 / total;
-
- if(unlikely(i == start && c == 0)) {
- r->view.min = r->view.max = n;
- }
- else {
- if (n < r->view.min) r->view.min = n;
- if (n > r->view.max) r->view.max = n;
- }
- }
-
+ else
buffer_print_netdata_double(wb, n);
- }
buffer_fast_strcat(wb, post_value, post_value_len);
}
@@ -335,23 +298,6 @@ void rrdr2json_v2(RRDR *r, BUFFER *wb) {
else
buffer_json_add_array_item_time_t(wb, now); // the time
- NETDATA_DOUBLE total = 1;
- if(unlikely((options & RRDR_OPTION_PERCENTAGE))) {
- total = 0;
- for(d = 0; d < used ; d++) {
- if(unlikely(!(r->od[d] & RRDR_DIMENSION_QUERIED))) continue;
-
- NETDATA_DOUBLE n = cn[d];
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- total += n;
- }
-
- // prevent a division by zero
- if(total == 0) total = 1;
- }
-
for (d = 0; d < used; d++) {
if (!rrdr_dimension_should_be_exposed(r->od[d], options))
continue;
@@ -369,24 +315,8 @@ void rrdr2json_v2(RRDR *r, BUFFER *wb) {
else
buffer_json_add_array_item_double(wb, NAN);
}
- else {
- if (unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- if (unlikely((options & RRDR_OPTION_PERCENTAGE))) {
- n = n * 100 / total;
- }
-
- if(unlikely(i == start && d == 0)) {
- r->view.min = r->view.max = n;
- }
- else {
- if (n < r->view.min) r->view.min = n;
- if (n > r->view.max) r->view.max = n;
- }
-
+ else
buffer_json_add_array_item_double(wb, n);
- }
// add the anomaly
buffer_json_add_array_item_double(wb, ar[d]);
diff --git a/web/api/formatters/json_wrapper.c b/web/api/formatters/json_wrapper.c
index b7c5720589..d4c1e8a5ac 100644
--- a/web/api/formatters/json_wrapper.c
+++ b/web/api/formatters/json_wrapper.c
@@ -213,6 +213,10 @@ static inline void query_target_data_statistics(BUFFER *wb, QUERY_TARGET *qt, st
return;
buffer_json_member_add_object(wb, "sts");
+
+ buffer_json_member_add_double(wb, "min", d->min);
+ buffer_json_member_add_double(wb, "max", d->max);
+
if(query_target_aggregatable(qt)) {
buffer_json_member_add_uint64(wb, "cnt", d->group_points);
@@ -397,15 +401,24 @@ static void query_target_summary_dimensions_v12(BUFFER *wb, QUERY_TARGET *qt, co
qm = tqm;
}
- snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
- rrdmetric_acquired_id(rma),
- rrdmetric_acquired_name(rma));
-
- z = dictionary_set(dict, name, NULL, sizeof(*z));
- if(!z->id)
- z->id = rrdmetric_acquired_id(rma);
- if(!z->name)
- z->name = rrdmetric_acquired_name(rma);
+ if(v2) {
+ z = dictionary_set(dict, rrdmetric_acquired_name(rma), NULL, sizeof(*z));
+ if(!z->id)
+ z->id = rrdmetric_acquired_name(rma);
+ if(!z->name)
+ z->name = rrdmetric_acquired_name(rma);
+ }
+ else {
+ snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
+ rrdmetric_acquired_id(rma),
+ rrdmetric_acquired_name(rma));
+
+ z = dictionary_set(dict, name, NULL, sizeof(*z));
+ if (!z->id)
+ z->id = rrdmetric_acquired_id(rma);
+ if (!z->name)
+ z->name = rrdmetric_acquired_name(rma);
+ }
if(qm) {
z->metrics.selected += (qm->status & RRDR_DIMENSION_SELECTED) ? 1 : 0;
@@ -423,7 +436,9 @@ static void query_target_summary_dimensions_v12(BUFFER *wb, QUERY_TARGET *qt, co
if(v2) {
buffer_json_add_array_item_object(wb);
buffer_json_member_add_string(wb, "id", z->id);
- buffer_json_member_add_string(wb, "nm", z->name);
+ if(z->id != z->name)
+ buffer_json_member_add_string(wb, "nm", z->name);
+
query_target_metric_counts(wb, &z->metrics);
query_target_data_statistics(wb, qt, &z->query_stats);
buffer_json_object_close(wb);
@@ -676,30 +691,10 @@ static inline long query_target_metrics_latest_values(BUFFER *wb, const char *ke
return i;
}
-static inline size_t rrdr_dimension_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
- size_t c, i;
-
+static inline size_t rrdr_dimension_view_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
buffer_json_member_add_array(wb, key);
- NETDATA_DOUBLE total = 1;
-
- if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
- total = 0;
- for(c = 0; c < r->d ; c++) {
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
-
- NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
- NETDATA_DOUBLE n = cn[c];
-
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- total += n;
- }
- // prevent a division by zero
- if(total == 0) total = 1;
- }
-
+ size_t c, i;
for(c = 0, i = 0; c < r->d ; c++) {
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
continue;
@@ -716,15 +711,8 @@ static inline size_t rrdr_dimension_latest_values(BUFFER *wb, const char *key, R
else
buffer_json_add_array_item_double(wb, NAN);
}
- else {
- if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- if(unlikely(options & RRDR_OPTION_PERCENTAGE))
- n = n * 100 / total;
-
+ else
buffer_json_add_array_item_double(wb, n);
- }
}
buffer_json_array_close(wb);
@@ -732,31 +720,49 @@ static inline size_t rrdr_dimension_latest_values(BUFFER *wb, const char *key, R
return i;
}
-static inline void rrdr_dimension_average_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
+static inline void rrdr_dimension_view_average_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
if(!r->dv)
return;
buffer_json_member_add_array(wb, key);
- bool percentage = r->internal.qt->request.options & RRDR_OPTION_PERCENTAGE;
- NETDATA_DOUBLE total = 0;
- if(percentage) {
- for(size_t c = 0; c < r->d ; c++) {
- if(!(r->od[c] & RRDR_DIMENSION_QUERIED))
- continue;
+ for(size_t c = 0; c < r->d ; c++) {
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
+ continue;
- total += r->dv[c];
- }
+ buffer_json_add_array_item_double(wb, r->dv[c]);
}
+ buffer_json_array_close(wb);
+}
+
+static inline void rrdr_dimension_view_minimum_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
+ if(!r->dmin)
+ return;
+
+ buffer_json_member_add_array(wb, key);
+
for(size_t c = 0; c < r->d ; c++) {
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
continue;
- if(percentage)
- buffer_json_add_array_item_double(wb, r->dv[c] * 100.0 / total);
- else
- buffer_json_add_array_item_double(wb, r->dv[c]);
+ buffer_json_add_array_item_double(wb, r->dmin[c]);
+ }
+
+ buffer_json_array_close(wb);
+}
+
+static inline void rrdr_dimension_view_maximum_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
+ if(!r->dmin)
+ return;
+
+ buffer_json_member_add_array(wb, key);
+
+ for(size_t c = 0; c < r->d ; c++) {
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
+ continue;
+
+ buffer_json_add_array_item_double(wb, r->dmax[c]);
}
buffer_json_array_close(wb);
@@ -831,7 +837,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb) {
if(!query_target_metrics_latest_values(wb, "latest_values", r, options))
rows = 0;
- size_t dimensions = rrdr_dimension_latest_values(wb, "view_latest_values", r, options);
+ size_t dimensions = rrdr_dimension_view_latest_values(wb, "view_latest_values", r, options);
if(!dimensions)
rows = 0;
@@ -1172,6 +1178,16 @@ static void query_target_detailed_objects_tree(BUFFER *wb, RRDR *r, RRDR_OPTIONS
buffer_json_object_close(wb); // hosts
}
+void version_hashes_api_v2(BUFFER *wb, struct query_versions *versions) {
+ buffer_json_member_add_object(wb, "versions");
+ buffer_json_member_add_uint64(wb, "nodes_hard_hash", dictionary_version(rrdhost_root_index));
+ buffer_json_member_add_uint64(wb, "contexts_hard_hash", versions->contexts_hard_hash);
+ buffer_json_member_add_uint64(wb, "contexts_soft_hash", versions->contexts_soft_hash);
+ buffer_json_member_add_uint64(wb, "alerts_hard_hash", versions->alerts_hard_hash);
+ buffer_json_member_add_uint64(wb, "alerts_soft_hash", versions->alerts_soft_hash);
+ buffer_json_object_close(wb);
+}
+
void rrdr_json_wrapper_begin2(RRDR *r, BUFFER *wb) {
QUERY_TARGET *qt = r->internal.qt;
RRDR_OPTIONS options = qt->request.options;
@@ -1251,15 +1267,12 @@ void rrdr_json_wrapper_begin2(RRDR *r, BUFFER *wb) {
}
buffer_json_object_close(wb); // aggregations
- buffer_json_member_add_uint64(wb, "timeout", qt->request.timeout);
+ buffer_json_member_add_uint64(wb, "timeout", qt->request.timeout_ms);
}
buffer_json_object_close(wb); // request
}
- buffer_json_member_add_object(wb, "versions");
- buffer_json_member_add_uint64(wb, "contexts_hard_hash", qt->versions.contexts_hard_hash);
- buffer_json_member_add_uint64(wb, "contexts_soft_hash", qt->versions.contexts_soft_hash);
- buffer_json_object_close(wb);
+ version_hashes_api_v2(wb, &qt->versions);
buffer_json_member_add_object(wb, "summary");
struct summary_total_counts
@@ -1432,8 +1445,10 @@ void rrdr_json_wrapper_end2(RRDR *r, BUFFER *wb) {
rrdr_dimension_units_array_v2(wb, "units", r, options);
rrdr_dimension_priority_array_v2(wb, "priorities", r, options);
rrdr_dimension_aggregated_array_v2(wb, "aggregated", r, options);
- rrdr_dimension_average_values(wb, "view_average_values", r, options);
- size_t dims = rrdr_dimension_latest_values(wb, "view_latest_values", r, options);
+ rrdr_dimension_view_minimum_values(wb, "view_minimum_values", r, options);
+ rrdr_dimension_view_maximum_values(wb, "view_maximum_values", r, options);
+ rrdr_dimension_view_average_values(wb, "view_average_values", r, options);
+ size_t dims = rrdr_dimension_view_latest_values(wb, "view_latest_values", r, options);
buffer_json_member_add_uint64(wb, "count", dims);
rrdr_json_group_by_labels(wb, "labels", r, options);
}
diff --git a/web/api/formatters/json_wrapper.h b/web/api/formatters/json_wrapper.h
index 93e60c3e43..a702f3a5c2 100644
--- a/web/api/formatters/json_wrapper.h
+++ b/web/api/formatters/json_wrapper.h
@@ -15,4 +15,7 @@ void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb);
void rrdr_json_wrapper_begin2(RRDR *r, BUFFER *wb);
void rrdr_json_wrapper_end2(RRDR *r, BUFFER *wb);
+struct query_versions;
+void version_hashes_api_v2(BUFFER *wb, struct query_versions *versions);
+
#endif //NETDATA_API_FORMATTER_JSON_WRAPPER_H
diff --git a/web/api/formatters/rrd2json.c b/web/api/formatters/rrd2json.c
index e04e6a2e95..af1cfe93e2 100644
--- a/web/api/formatters/rrd2json.c
+++ b/web/api/formatters/rrd2json.c
@@ -11,10 +11,6 @@ inline bool query_target_has_percentage_units(struct query_target *qt) {
return false;
}
-bool query_target_aggregatable(struct query_target *qt) {
- return (qt->request.options & RRDR_OPTION_RETURN_RAW);
-}
-
void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
rrdset2json(st, wb, NULL, NULL, 0);
}
diff --git a/web/api/formatters/rrd2json.h b/web/api/formatters/rrd2json.h
index e452848c8f..85c5446ee3 100644
--- a/web/api/formatters/rrd2json.h
+++ b/web/api/formatters/rrd2json.h
@@ -63,7 +63,7 @@ void rrdr_json_group_by_labels(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTION
struct query_target;
bool query_target_has_percentage_units(struct query_target *qt);
-bool query_target_aggregatable(struct query_target *qt);
+#define query_target_aggregatable(qt) (qt->request.options & RRDR_OPTION_RETURN_RAW)
int rrdset2value_api_v1(
RRDSET *st
@@ -91,9 +91,13 @@ int rrdset2value_api_v1(
);
static inline bool rrdr_dimension_should_be_exposed(RRDR_DIMENSION_FLAGS rrdr_dim_flags, RRDR_OPTIONS options) {
+ if(unlikely(options & RRDR_OPTION_RETURN_RAW))
+ return true;
+
if(unlikely(rrdr_dim_flags & RRDR_DIMENSION_HIDDEN)) return false;
if(unlikely(!(rrdr_dim_flags & RRDR_DIMENSION_QUERIED))) return false;
if(unlikely((options & RRDR_OPTION_NONZERO) && !(rrdr_dim_flags & RRDR_DIMENSION_NONZERO))) return false;
+
return true;
}
diff --git a/web/api/formatters/value/value.c b/web/api/formatters/value/value.c
index 1db2a516ab..e6a663a431 100644
--- a/web/api/formatters/value/value.c
+++ b/web/api/formatters/value/value.c
@@ -13,24 +13,8 @@ inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all
NETDATA_DOUBLE sum = 0, min = 0, max = 0, v;
int all_null = 1, init = 1;
- NETDATA_DOUBLE total = 1;
NETDATA_DOUBLE total_anomaly_rate = 0;
- if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
- total = 0;
- for (c = 0; c < r->d ; c++) {
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
- NETDATA_DOUBLE n = cn[c];
-
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- total += n;
- }
- // prevent a division by zero
- if(total == 0) total = 1;
- }
-
// for each dimension
for (c = 0; c < r->d ; c++) {
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
@@ -38,21 +22,6 @@ inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all
NETDATA_DOUBLE n = cn[c];
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
- n = -n;
-
- if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
- n = n * 100 / total;
-
- if(unlikely(c == 0)) {
- r->view.min = r->view.max = n;
- }
- else {
- if (n < r->view.min) r->view.min = n;
- if (n > r->view.max) r->view.max = n;
- }
- }
-
if(unlikely(init)) {
if(n > 0) {
min = 0;
@@ -102,7 +71,7 @@ inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all
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 group_method, const char *group_options,
+ 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 = {
@@ -115,10 +84,10 @@ QUERY_VALUE rrdmetric2value(RRDHOST *host,
.before = before,
.points = 1,
.options = options,
- .time_group_method = group_method,
- .time_group_options = group_options,
+ .time_group_method = time_group_method,
+ .time_group_options = time_group_options,
.tier = tier,
- .timeout = timeout,
+ .timeout_ms = timeout,
.query_source = query_source,
.priority = priority,
};
@@ -132,6 +101,13 @@ QUERY_VALUE rrdmetric2value(RRDHOST *host,
qv = (QUERY_VALUE) {
.value = NAN,
.anomaly_rate = NAN,
+ .sp = {
+ .count = 0,
+ .min = NAN,
+ .max = NAN,
+ .sum = NAN,
+ .anomaly_count = 0,
+ }
};
}
else {
@@ -140,8 +116,14 @@ QUERY_VALUE rrdmetric2value(RRDHOST *host,
.before = r->view.before,
.points_read = r->stats.db_points_read,
.result_points = r->stats.result_points_generated,
+ .sp = {
+ .count = 0,
+ }
};
+ for(size_t d = 0; d < r->d ;d++)
+ storage_point_merge_to(qv.sp, r->drs[d]);
+
for(size_t t = 0; t < storage_tiers ;t++)
qv.storage_points_per_tier[t] = r->internal.qt->db.tiers[t].points;
diff --git a/web/api/formatters/value/value.h b/web/api/formatters/value/value.h
index a9b18e429a..7ff613cc03 100644
--- a/web/api/formatters/value/value.h
+++ b/web/api/formatters/value/value.h
@@ -13,6 +13,7 @@ typedef struct storage_value {
size_t points_read;
size_t storage_points_per_tier[RRD_STORAGE_TIERS];
size_t result_points;
+ STORAGE_POINT sp;
} QUERY_VALUE;
struct rrdmetric_acquired;
@@ -22,7 +23,7 @@ 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 group_method, const char *group_options,
+ 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
);
diff --git a/web/api/netdata-swagger.yaml b/web/api/netdata-swagger.yaml
index a52a52ef49..81db04f87a 100644
--- a/web/api/netdata-swagger.yaml
+++ b/web/api/netdata-swagger.yaml
@@ -388,6 +388,7 @@ paths:
in: query
description: |
The aggregation function to apply when grouping metrics together.
+ When option `raw` is given, `average` and `avg` behave like `sum` and the caller is expected to calculate the average.
required: false
schema:
type: string
@@ -2414,6 +2415,10 @@ components:
Hashes that allow the caller to detect important database changes of Netdata agents.
type: object
properties:
+ nodes_hard_hash:
+ description: |
+ An auto-increment value that reflects the number of changes to the number of nodes maintained by the server. Everytime a node is added or removed, this number gets incremented.
+ type: integer
contexts_hard_hash:
description: |
An auto-increment value that reflects the number of changes to the number of contexts maintained by the server. Everytime a context is added or removed, this number gets incremented.
@@ -2422,6 +2427,14 @@ components:
description: |
An auto-increment value that reflects the number of changes to the queue that sends contexts updates to Netdata Cloud. Everytime the contents of a context are updated, this number gets incremented.
type: integer
+ alerts_hard_hash:
+ description: |
+ An auto-increment value that reflects the number of changes to the number of alerts. Everytime an alert is added or removed, this number gets incremented.
+ type: integer
+ alerts_soft_hash:
+ description: |
+ An auto-increment value that reflects the number of alerts transitions. Everytime an alert transitions to a new state, this number gets incremented.
+ type: integer
summary:
description: |
Summarized information about nodes, contexts, instances, labels, alerts, and dimensions. The items returned are determined by the scope of the query only, however the statistical data in them are influenced by the filters of the query. Using this information the dashboard allows users to slice and dice the data by filtering and grouping.
@@ -2747,6 +2760,18 @@ components:
type: array
items:
type: integer
+ view_minimum_values:
+ description: |
+ An array of the minimum value of each dimension across the entire query.
+ type: array
+ items:
+ type: number
+ view_maximum_values:
+ description: |
+ An array of the maximum value of each dimension across the entire query.
+ type: array
+ items:
+ type: number
view_average_values:
description: |
An array of the average value of each dimension across the entire query.
@@ -2837,6 +2862,12 @@ components:
Statistical values
type: object
properties:
+ min:
+ description: The minimum value of all metrics aggregated
+ type: number
+ max:
+ description: The maximum value of all metrics aggregated
+ type: number
avg:
description: The average value of all metrics aggregated
type: number
@@ -2851,6 +2882,12 @@ components:
Statistical values when `raw` option is given.
type: object
properties:
+ min:
+ description: The minimum value of all metrics aggregated
+ type: number
+ max:
+ description: The maximum value of all metrics aggregated
+ type: number
sum:
description: The sum value of all metrics aggregated
type: number
diff --git a/web/api/queries/query.c b/web/api/queries/query.c
index 779d787cd0..41944601cd 100644
--- a/web/api/queries/query.c
+++ b/web/api/queries/query.c
@@ -775,16 +775,13 @@ static inline NETDATA_DOUBLE *UNUSED_FUNCTION(rrdr_line_values)(RRDR *r, long rr
static inline long rrdr_line_init(RRDR *r, time_t t, long rrdr_line) {
rrdr_line++;
- internal_error(rrdr_line >= (long)r->n,
+ internal_fatal(rrdr_line >= (long)r->n,
"QUERY: requested to step above RRDR size for query '%s'",
r->internal.qt->id);
- internal_error(r->t[rrdr_line] != 0 && r->t[rrdr_line] != t,
- "QUERY: overwriting the timestamp of RRDR line %zu from %zu to %zu, of query '%s'",
- (size_t)rrdr_line, (size_t)r->t[rrdr_line], (size_t)t, r->internal.qt->id);
-
- // save the time
- r->t[rrdr_line] = t;
+ internal_fatal(r->t[rrdr_line] != t,