summaryrefslogtreecommitdiffstats
path: root/web/api/web_api_v1.c
diff options
context:
space:
mode:
Diffstat (limited to 'web/api/web_api_v1.c')
-rw-r--r--web/api/web_api_v1.c468
1 files changed, 384 insertions, 84 deletions
diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c
index cb73f7c0..8bfc617f 100644
--- a/web/api/web_api_v1.c
+++ b/web/api/web_api_v1.c
@@ -3,42 +3,45 @@
#include "web_api_v1.h"
char *api_secret;
-extern int aclk_use_new_cloud_arch;
static struct {
const char *name;
uint32_t hash;
RRDR_OPTIONS value;
} api_v1_data_options[] = {
- { "nonzero" , 0 , RRDR_OPTION_NONZERO}
- , {"flip" , 0 , RRDR_OPTION_REVERSED}
- , {"reversed" , 0 , RRDR_OPTION_REVERSED}
- , {"reverse" , 0 , RRDR_OPTION_REVERSED}
- , {"jsonwrap" , 0 , RRDR_OPTION_JSON_WRAP}
- , {"min2max" , 0 , RRDR_OPTION_MIN2MAX}
- , {"ms" , 0 , RRDR_OPTION_MILLISECONDS}
- , {"milliseconds" , 0 , RRDR_OPTION_MILLISECONDS}
- , {"abs" , 0 , RRDR_OPTION_ABSOLUTE}
- , {"absolute" , 0 , RRDR_OPTION_ABSOLUTE}
- , {"absolute_sum" , 0 , RRDR_OPTION_ABSOLUTE}
- , {"absolute-sum" , 0 , RRDR_OPTION_ABSOLUTE}
- , {"display_absolute", 0 , RRDR_OPTION_DISPLAY_ABS}
- , {"display-absolute", 0 , RRDR_OPTION_DISPLAY_ABS}
- , {"seconds" , 0 , RRDR_OPTION_SECONDS}
- , {"null2zero" , 0 , RRDR_OPTION_NULL2ZERO}
- , {"objectrows" , 0 , RRDR_OPTION_OBJECTSROWS}
- , {"google_json" , 0 , RRDR_OPTION_GOOGLE_JSON}
- , {"google-json" , 0 , RRDR_OPTION_GOOGLE_JSON}
- , {"percentage" , 0 , RRDR_OPTION_PERCENTAGE}
- , {"unaligned" , 0 , RRDR_OPTION_NOT_ALIGNED}
- , {"match_ids" , 0 , RRDR_OPTION_MATCH_IDS}
- , {"match-ids" , 0 , RRDR_OPTION_MATCH_IDS}
- , {"match_names" , 0 , RRDR_OPTION_MATCH_NAMES}
- , {"match-names" , 0 , RRDR_OPTION_MATCH_NAMES}
- , {"showcustomvars" , 0 , RRDR_OPTION_CUSTOM_VARS}
- , {"allow_past" , 0 , RRDR_OPTION_ALLOW_PAST}
- , {"anomaly-bit" , 0 , RRDR_OPTION_ANOMALY_BIT}
- , { NULL, 0, 0}
+ { "nonzero" , 0 , RRDR_OPTION_NONZERO}
+ , {"flip" , 0 , RRDR_OPTION_REVERSED}
+ , {"reversed" , 0 , RRDR_OPTION_REVERSED}
+ , {"reverse" , 0 , RRDR_OPTION_REVERSED}
+ , {"jsonwrap" , 0 , RRDR_OPTION_JSON_WRAP}
+ , {"min2max" , 0 , RRDR_OPTION_MIN2MAX}
+ , {"ms" , 0 , RRDR_OPTION_MILLISECONDS}
+ , {"milliseconds" , 0 , RRDR_OPTION_MILLISECONDS}
+ , {"abs" , 0 , RRDR_OPTION_ABSOLUTE}
+ , {"absolute" , 0 , RRDR_OPTION_ABSOLUTE}
+ , {"absolute_sum" , 0 , RRDR_OPTION_ABSOLUTE}
+ , {"absolute-sum" , 0 , RRDR_OPTION_ABSOLUTE}
+ , {"display_absolute" , 0 , RRDR_OPTION_DISPLAY_ABS}
+ , {"display-absolute" , 0 , RRDR_OPTION_DISPLAY_ABS}
+ , {"seconds" , 0 , RRDR_OPTION_SECONDS}
+ , {"null2zero" , 0 , RRDR_OPTION_NULL2ZERO}
+ , {"objectrows" , 0 , RRDR_OPTION_OBJECTSROWS}
+ , {"google_json" , 0 , RRDR_OPTION_GOOGLE_JSON}
+ , {"google-json" , 0 , RRDR_OPTION_GOOGLE_JSON}
+ , {"percentage" , 0 , RRDR_OPTION_PERCENTAGE}
+ , {"unaligned" , 0 , RRDR_OPTION_NOT_ALIGNED}
+ , {"match_ids" , 0 , RRDR_OPTION_MATCH_IDS}
+ , {"match-ids" , 0 , RRDR_OPTION_MATCH_IDS}
+ , {"match_names" , 0 , RRDR_OPTION_MATCH_NAMES}
+ , {"match-names" , 0 , RRDR_OPTION_MATCH_NAMES}
+ , {"showcustomvars" , 0 , RRDR_OPTION_CUSTOM_VARS}
+ , {"anomaly-bit" , 0 , RRDR_OPTION_ANOMALY_BIT}
+ , {"selected-tier" , 0 , RRDR_OPTION_SELECTED_TIER}
+ , {"raw" , 0 , RRDR_OPTION_RETURN_RAW}
+ , {"jw-anomaly-rates" , 0 , RRDR_OPTION_RETURN_JWAR}
+ , {"natural-points" , 0 , RRDR_OPTION_NATURAL_POINTS}
+ , {"virtual-points" , 0 , RRDR_OPTION_VIRTUAL_POINTS}
+ , {NULL , 0 , 0}
};
static struct {
@@ -162,8 +165,8 @@ void web_client_api_v1_management_init(void) {
api_secret = get_mgmt_api_key();
}
-inline uint32_t web_client_api_request_v1_data_options(char *o) {
- uint32_t ret = 0x00000000;
+inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) {
+ RRDR_OPTIONS ret = 0x00000000;
char *tok;
while(o && *o && (tok = mystrsep(&o, ", |"))) {
@@ -182,6 +185,19 @@ inline uint32_t web_client_api_request_v1_data_options(char *o) {
return ret;
}
+void web_client_api_request_v1_data_options_to_string(BUFFER *wb, RRDR_OPTIONS options) {
+ RRDR_OPTIONS used = 0; // to prevent adding duplicates
+ int added = 0;
+ for(int i = 0; api_v1_data_options[i].name ; i++) {
+ if (unlikely((api_v1_data_options[i].value & options) && !(api_v1_data_options[i].value & used))) {
+ if(added) buffer_strcat(wb, ",");
+ buffer_strcat(wb, api_v1_data_options[i].name);
+ used |= api_v1_data_options[i].value;
+ added++;
+ }
+ }
+}
+
inline uint32_t web_client_api_request_v1_data_format(char *name) {
uint32_t hash = simple_hash(name);
int i;
@@ -358,6 +374,157 @@ inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_c
return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
}
+static RRDCONTEXT_TO_JSON_OPTIONS rrdcontext_to_json_parse_options(char *o) {
+ RRDCONTEXT_TO_JSON_OPTIONS options = RRDCONTEXT_OPTION_NONE;
+ char *tok;
+
+ while(o && *o && (tok = mystrsep(&o, ", |"))) {
+ if(!*tok) continue;
+
+ if(!strcmp(tok, "full") || !strcmp(tok, "all"))
+ options |= RRDCONTEXT_OPTIONS_ALL;
+ else if(!strcmp(tok, "charts") || !strcmp(tok, "instances"))
+ options |= RRDCONTEXT_OPTION_SHOW_INSTANCES;
+ else if(!strcmp(tok, "dimensions") || !strcmp(tok, "metrics"))
+ options |= RRDCONTEXT_OPTION_SHOW_METRICS;
+ else if(!strcmp(tok, "queue"))
+ options |= RRDCONTEXT_OPTION_SHOW_QUEUED;
+ else if(!strcmp(tok, "flags"))
+ options |= RRDCONTEXT_OPTION_SHOW_FLAGS;
+ else if(!strcmp(tok, "uuids"))
+ options |= RRDCONTEXT_OPTION_SHOW_UUIDS;
+ else if(!strcmp(tok, "deleted"))
+ options |= RRDCONTEXT_OPTION_SHOW_DELETED;
+ else if(!strcmp(tok, "labels"))
+ options |= RRDCONTEXT_OPTION_SHOW_LABELS;
+ else if(!strcmp(tok, "deepscan"))
+ options |= RRDCONTEXT_OPTION_DEEPSCAN;
+ else if(!strcmp(tok, "hidden"))
+ options |= RRDCONTEXT_OPTION_SHOW_HIDDEN;
+ }
+
+ return options;
+}
+
+static int web_client_api_request_v1_context(RRDHOST *host, struct web_client *w, char *url) {
+ char *context = NULL;
+ RRDCONTEXT_TO_JSON_OPTIONS options = RRDCONTEXT_OPTION_NONE;
+ time_t after = 0, before = 0;
+ const char *chart_label_key = NULL, *chart_labels_filter = NULL;
+ BUFFER *dimensions = NULL;
+
+ buffer_flush(w->response.data);
+
+ while(url) {
+ char *value = mystrsep(&url, "&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "context") || !strcmp(name, "ctx")) context = value;
+ else if(!strcmp(name, "after")) after = str2l(value);
+ else if(!strcmp(name, "before")) before = str2l(value);
+ else if(!strcmp(name, "options")) options = rrdcontext_to_json_parse_options(value);
+ else if(!strcmp(name, "chart_label_key")) chart_label_key = value;
+ else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value;
+ else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+ if(!dimensions) dimensions = buffer_create(100);
+ buffer_strcat(dimensions, "|");
+ buffer_strcat(dimensions, value);
+ }
+ }
+
+ if(!context || !*context) {
+ buffer_sprintf(w->response.data, "No context is given at the request.");
+ return HTTP_RESP_BAD_REQUEST;
+ }
+
+ SIMPLE_PATTERN *chart_label_key_pattern = NULL;
+ SIMPLE_PATTERN *chart_labels_filter_pattern = NULL;
+ SIMPLE_PATTERN *chart_dimensions_pattern = NULL;
+
+ if(chart_label_key)
+ chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
+ if(chart_labels_filter)
+ chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
+ if(dimensions) {
+ chart_dimensions_pattern = simple_pattern_create(buffer_tostring(dimensions), ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ buffer_free(dimensions);
+ }
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ int ret = rrdcontext_to_json(host, w->response.data, after, before, options, context, chart_label_key_pattern, chart_labels_filter_pattern, chart_dimensions_pattern);
+
+ simple_pattern_free(chart_label_key_pattern);
+ simple_pattern_free(chart_labels_filter_pattern);
+ simple_pattern_free(chart_dimensions_pattern);
+
+ return ret;
+}
+
+static int web_client_api_request_v1_contexts(RRDHOST *host, struct web_client *w, char *url) {
+ RRDCONTEXT_TO_JSON_OPTIONS options = RRDCONTEXT_OPTION_NONE;
+ time_t after = 0, before = 0;
+ const char *chart_label_key = NULL, *chart_labels_filter = NULL;
+ BUFFER *dimensions = NULL;
+
+ buffer_flush(w->response.data);
+
+ while(url) {
+ char *value = mystrsep(&url, "&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "after")) after = str2l(value);
+ else if(!strcmp(name, "before")) before = str2l(value);
+ else if(!strcmp(name, "options")) options = rrdcontext_to_json_parse_options(value);
+ else if(!strcmp(name, "chart_label_key")) chart_label_key = value;
+ else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value;
+ else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+ if(!dimensions) dimensions = buffer_create(100);
+ buffer_strcat(dimensions, "|");
+ buffer_strcat(dimensions, value);
+ }
+ }
+
+ SIMPLE_PATTERN *chart_label_key_pattern = NULL;
+ SIMPLE_PATTERN *chart_labels_filter_pattern = NULL;
+ SIMPLE_PATTERN *chart_dimensions_pattern = NULL;
+
+ if(chart_label_key)
+ chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
+ if(chart_labels_filter)
+ chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
+ if(dimensions) {
+ chart_dimensions_pattern = simple_pattern_create(buffer_tostring(dimensions), ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ buffer_free(dimensions);
+ }
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ int ret = rrdcontexts_to_json(host, w->response.data, after, before, options, chart_label_key_pattern, chart_labels_filter_pattern, chart_dimensions_pattern);
+
+ simple_pattern_free(chart_label_key_pattern);
+ simple_pattern_free(chart_labels_filter_pattern);
+ simple_pattern_free(chart_dimensions_pattern);
+
+ return ret;
+}
+
inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url) {
(void)url;
@@ -392,6 +559,7 @@ void fix_google_param(char *s) {
}
}
+
// returns the HTTP code
inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
@@ -420,7 +588,8 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
char *context = NULL;
char *chart_label_key = NULL;
char *chart_labels_filter = NULL;
-
+ char *group_options = NULL;
+ int tier = 0;
int group = RRDR_GROUPING_AVERAGE;
int show_dimensions = 0;
uint32_t format = DATASOURCE_JSON;
@@ -454,6 +623,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
else if(!strcmp(name, "points")) points_str = value;
else if(!strcmp(name, "timeout")) timeout_str = value;
else if(!strcmp(name, "gtime")) group_time_str = value;
+ else if(!strcmp(name, "group_options")) group_options = value;
else if(!strcmp(name, "group")) {
group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
}
@@ -503,6 +673,11 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
else if(!strcmp(name, "max_anomaly_rates")) {
max_anomaly_rates_str = value;
}
+ else if(!strcmp(name, "tier")) {
+ tier = str2i(value);
+ if(tier >= 0 && tier < storage_tiers)
+ options |= RRDR_OPTION_SELECTED_TIER;
+ }
}
// validate the google parameters given
@@ -528,18 +703,23 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
uint32_t context_hash = simple_hash(context);
+ SIMPLE_PATTERN *chart_label_key_pattern = NULL;
+ if(chart_label_key)
+ chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
+ SIMPLE_PATTERN *chart_labels_filter_pattern = NULL;
+ if(chart_labels_filter)
+ chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
rrdhost_rdlock(host);
- char *words[MAX_CHART_LABELS_FILTER];
- uint32_t hash_key_list[MAX_CHART_LABELS_FILTER];
- int word_count = 0;
rrdset_foreach_read(st1, host) {
if (st1->hash_context == context_hash && !strcmp(st1->context, context) &&
- (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key)) &&
- (!chart_labels_filter ||
- rrdset_matches_label_keys(st1, chart_labels_filter, words, hash_key_list, &word_count, MAX_CHART_LABELS_FILTER)))
+ (!chart_label_key_pattern || rrdlabels_match_simple_pattern_parsed(st1->state->chart_labels, chart_label_key_pattern, ':')) &&
+ (!chart_labels_filter_pattern || rrdlabels_match_simple_pattern_parsed(st1->state->chart_labels, chart_labels_filter_pattern, ':')))
build_context_param_list(owa, &context_param_list, st1);
}
rrdhost_unlock(host);
+
if (likely(context_param_list && context_param_list->rd)) // Just set the first one
st = context_param_list->rd->rrdset;
else {
@@ -656,7 +836,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
.wb = w->response.data};
ret = rrdset2anything_api_v1(owa, st, &query_params, dimensions, format,
- points, after, before, group, group_time, options, &last_timestamp_in_data);
+ points, after, before, group, group_options, group_time, options, &last_timestamp_in_data, tier);
free_context_param_list(owa, &context_param_list);
@@ -903,8 +1083,6 @@ static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
buffer_strcat(wb, "\t\"mirrored_hosts\": [\n");
rrd_rdlock();
rrdhost_foreach_read(host) {
- if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))
- continue;
if (count > 0)
buffer_strcat(wb, ",\n");
@@ -916,8 +1094,6 @@ static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
count = 0;
rrdhost_foreach_read(host)
{
- if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))
- continue;
if (count > 0)
buffer_strcat(wb, ",\n");
@@ -964,22 +1140,8 @@ inline void host_labels2json(RRDHOST *host, BUFFER *wb, size_t indentation) {
indentation--;
}
- int count = 0;
- rrdhost_rdlock(host);
- netdata_rwlock_rdlock(&host->labels.labels_rwlock);
- for (struct label *label = host->labels.head; label; label = label->next) {
- if(count > 0) buffer_strcat(wb, ",\n");
- buffer_strcat(wb, tabs);
-
- char value[CONFIG_MAX_VALUE * 2 + 1];
- sanitize_json_string(value, label->value, CONFIG_MAX_VALUE * 2);
- buffer_sprintf(wb, "\"%s\": \"%s\"", label->key, value);
-
- count++;
- }
+ rrdlabels_to_buffer(host->host_labels, wb, tabs, ":", "\"", ",\n", NULL, NULL, NULL, NULL);
buffer_strcat(wb, "\n");
- netdata_rwlock_unlock(&host->labels.labels_rwlock);
- rrdhost_unlock(host);
}
extern int aclk_connected;
@@ -1054,11 +1216,7 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
#ifdef ENABLE_ACLK
buffer_strcat(wb, "\t\"cloud-available\": true,\n");
buffer_strcat(wb, "\t\"aclk-ng-available\": true,\n");
-#ifdef ENABLE_NEW_CLOUD_PROTOCOL
buffer_strcat(wb, "\t\"aclk-ng-new-cloud-protocol\": true,\n");
-#else
- buffer_strcat(wb, "\t\"aclk-ng-new-cloud-protocol\": false,\n");
-#endif
buffer_strcat(wb, "\t\"aclk-legacy-available\": false,\n");
buffer_strcat(wb, "\t\"aclk-implementation\": \"Next Generation\",\n");
#else
@@ -1066,7 +1224,7 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
buffer_strcat(wb, "\t\"aclk-ng-available\": false,\n");
buffer_strcat(wb, "\t\"aclk-legacy-available\": false,\n");
#endif
- char *agent_id = is_agent_claimed();
+ char *agent_id = get_agent_claimid();
if (agent_id == NULL)
buffer_strcat(wb, "\t\"agent-claimed\": false,\n");
else {
@@ -1076,12 +1234,7 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
#ifdef ENABLE_ACLK
if (aclk_connected) {
buffer_strcat(wb, "\t\"aclk-available\": true,\n");
-#ifdef ENABLE_NEW_CLOUD_PROTOCOL
- if (aclk_use_new_cloud_arch)
- buffer_strcat(wb, "\t\"aclk-available-protocol\": \"New\",\n");
- else
-#endif
- buffer_strcat(wb, "\t\"aclk-available-protocol\": \"Legacy\",\n");
+ buffer_strcat(wb, "\t\"aclk-available-protocol\": \"New\",\n");
}
else
#endif
@@ -1323,12 +1476,18 @@ static int web_client_api_request_v1_aclk_state(RRDHOST *host, struct web_client
return HTTP_RESP_OK;
}
-int web_client_api_request_v1_metric_correlations(RRDHOST *host, struct web_client *w, char *url) {
+static int web_client_api_request_v1_weights_internal(RRDHOST *host, struct web_client *w, char *url, WEIGHTS_METHOD method, WEIGHTS_FORMAT format) {
if (!netdata_ready)
return HTTP_RESP_BACKEND_FETCH_FAILED;
- long long baseline_after = 0, baseline_before = 0, highlight_after = 0, highlight_before = 0, max_points = 0;
-
+ long long baseline_after = 0, baseline_before = 0, after = 0, before = 0, points = 0;
+ RRDR_OPTIONS options = RRDR_OPTION_NOT_ALIGNED | RRDR_OPTION_NONZERO | RRDR_OPTION_NULL2ZERO;
+ int options_count = 0;
+ RRDR_GROUPING group = RRDR_GROUPING_AVERAGE;
+ int timeout = 0;
+ int tier = 0;
+ const char *group_options = NULL, *contexts_str = NULL;
+
while (url) {
char *value = mystrsep(&url, "&");
if (!value || !*value)
@@ -1342,30 +1501,165 @@ int web_client_api_request_v1_metric_correlations(RRDHOST *host, struct web_clie
if (!strcmp(name, "baseline_after"))
baseline_after = (long long) strtoul(value, NULL, 0);
+
else if (!strcmp(name, "baseline_before"))
baseline_before = (long long) strtoul(value, NULL, 0);
- else if (!strcmp(name, "highlight_after"))
- highlight_after = (long long) strtoul(value, NULL, 0);
- else if (!strcmp(name, "highlight_before"))
- highlight_before = (long long) strtoul(value, NULL, 0);
- else if (!strcmp(name, "max_points"))
- max_points = (long long) strtoul(value, NULL, 0);
-
+
+ else if (!strcmp(name, "after") || !strcmp(name, "highlight_after"))
+ after = (long long) strtoul(value, NULL, 0);
+
+ else if (!strcmp(name, "before") || !strcmp(name, "highlight_before"))
+ before = (long long) strtoul(value, NULL, 0);
+
+ else if (!strcmp(name, "points") || !strcmp(name, "max_points"))
+ points = (long long) strtoul(value, NULL, 0);
+
+ else if (!strcmp(name, "timeout"))
+ timeout = (int) strtoul(value, NULL, 0);
+
+ else if(!strcmp(name, "group"))
+ group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
+
+ else if(!strcmp(name, "options")) {
+ if(!options_count) options = RRDR_OPTION_NOT_ALIGNED | RRDR_OPTION_NULL2ZERO;
+ options |= web_client_api_request_v1_data_options(value);
+ options_count++;
+ }
+
+ else if(!strcmp(name, "method"))
+ method = weights_string_to_method(value);
+
+ else if(!strcmp(name, "context") || !strcmp(name, "contexts"))
+ contexts_str = value;
+
+ else if(!strcmp(name, "tier")) {
+ tier = str2i(value);
+ if(tier >= 0 && tier < storage_tiers)
+ options |= RRDR_OPTION_SELECTED_TIER;
+ }
}
BUFFER *wb = w->response.data;
buffer_flush(wb);
wb->contenttype = CT_APPLICATION_JSON;
+
+ SIMPLE_PATTERN *contexts = (contexts_str) ? simple_pattern_create(contexts_str, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT) : NULL;
+
+ int ret = web_api_v1_weights(host, wb, method, format, group, group_options, baseline_after, baseline_before, after, before, points, options, contexts, tier, timeout);
+
+ simple_pattern_free(contexts);
+ return ret;
+}
+
+int web_client_api_request_v1_metric_correlations(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_request_v1_weights_internal(host, w, url, default_metric_correlations_method, WEIGHTS_FORMAT_CHARTS);
+}
+
+int web_client_api_request_v1_weights(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_request_v1_weights_internal(host, w, url, WEIGHTS_METHOD_ANOMALY_RATE, WEIGHTS_FORMAT_CONTEXTS);
+}
+
+#ifndef ENABLE_DBENGINE
+int web_client_api_request_v1_dbengine_stats(RRDHOST *host, struct web_client *w, char *url) {
+ return HTTP_RESP_NOT_FOUND;
+}
+#else
+static void web_client_api_v1_dbengine_stats_for_tier(BUFFER *wb, int tier) {
+ RRDENG_SIZE_STATS stats = rrdeng_size_statistics(multidb_ctx[tier]);
+
+ buffer_sprintf(wb,
+ "\n\t\t\"default_granularity_secs\":%zu"
+ ",\n\t\t\"sizeof_metric\":%zu"
+ ",\n\t\t\"sizeof_metric_in_index\":%zu"
+ ",\n\t\t\"sizeof_page\":%zu"
+ ",\n\t\t\"sizeof_page_in_index\":%zu"
+ ",\n\t\t\"sizeof_extent\":%zu"
+ ",\n\t\t\"sizeof_page_in_extent\":%zu"
+ ",\n\t\t\"sizeof_datafile\":%zu"
+ ",\n\t\t\"sizeof_page_in_cache\":%zu"
+ ",\n\t\t\"sizeof_point_data\":%zu"
+ ",\n\t\t\"sizeof_page_data\":%zu"
+ ",\n\t\t\"pages_per_extent\":%zu"
+ ",\n\t\t\"datafiles\":%zu"
+ ",\n\t\t\"extents\":%zu"
+ ",\n\t\t\"extents_pages\":%zu"
+ ",\n\t\t\"points\":%zu"
+ ",\n\t\t\"metrics\":%zu"
+ ",\n\t\t\"metrics_pages\":%zu"
+ ",\n\t\t\"extents_compressed_bytes\":%zu"
+ ",\n\t\t\"pages_uncompressed_bytes\":%zu"
+ ",\n\t\t\"pages_duration_secs\":%ld"
+ ",\n\t\t\"single_point_pages\":%zu"
+ ",\n\t\t\"first_t\":%llu"
+ ",\n\t\t\"last_t\":%llu"
+ ",\n\t\t\"database_retention_secs\":%ld"
+ ",\n\t\t\"average_compression_savings\":%0.2f"
+ ",\n\t\t\"average_point_duration_secs\":%0.2f"
+ ",\n\t\t\"average_metric_retention_secs\":%0.2f"
+ ",\n\t\t\"ephemeral_metrics_per_day_percent\":%0.2f"
+ ",\n\t\t\"average_page_size_bytes\":%0.2f"
+ ",\n\t\t\"estimated_concurrently_collected_metrics\":%zu"
+ ",\n\t\t\"currently_collected_metrics\":%zu"
+ ",\n\t\t\"max_concurrently_collected_metrics\":%zu"
+ ",\n\t\t\"disk_space\":%zu"
+ ",\n\t\t\"max_disk_space\":%zu"
+ , stats.default_granularity_secs
+ , stats.sizeof_metric
+ , stats.sizeof_metric_in_index
+ , stats.sizeof_page
+ , stats.sizeof_page_in_index
+ , stats.sizeof_extent
+ , stats.sizeof_page_in_extent
+ , stats.sizeof_datafile
+ , stats.sizeof_page_in_cache
+ , stats.sizeof_point_data
+ , stats.sizeof_page_data
+ , stats.pages_per_extent
+ , stats.datafiles
+ , stats.extents
+ , stats.extents_pages
+ , stats.points
+ , stats.metrics
+ , stats.metrics_pages
+ , stats.extents_compressed_bytes
+ , stats.pages_uncompressed_bytes
+ , stats.pages_duration_secs
+ , stats.single_point_pages
+ , stats.first_t
+ , stats.last_t
+ , stats.database_retention_secs
+ , stats.average_compression_savings
+ , stats.average_point_duration_secs
+ , stats.average_metric_retention_secs
+ , stats.ephemeral_metrics_per_day_percent
+ , stats.average_page_size_bytes
+ , stats.estimated_concurrently_collected_metrics
+ , stats.currently_collected_metrics
+ , stats.max_concurrently_collected_metrics
+ , stats.disk_space
+ , stats.max_disk_space
+ );
+}
+int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struct web_client *w, char *url __maybe_unused) {
+ if (!netdata_ready)
+ return HTTP_RESP_BACKEND_FETCH_FAILED;
+
+ BUFFER *wb = w->response.data;
+ buffer_flush(wb);
+ wb->contenttype = CT_APPLICATION_JSON;
buffer_no_cacheable(wb);
- if (!highlight_after || !highlight_before)
- buffer_strcat(wb, "{\"error\": \"Missing or invalid required highlight after and before parameters.\" }");
- else {
- metric_correlations(host, wb, baseline_after, baseline_before, highlight_after, highlight_before, max_points);
+ buffer_strcat(wb, "{");
+ for(int tier = 0; tier < storage_tiers ;tier++) {
+ buffer_sprintf(wb, "%s\n\t\"tier%d\": {", tier?",":"", tier);
+ web_client_api_v1_dbengine_stats_for_tier(wb, tier);
+ buffer_strcat(wb, "\n\t}");
}
+ buffer_strcat(wb, "\n}");
return HTTP_RESP_OK;
}
+#endif
static struct api_command {
const char *command;
@@ -1377,6 +1671,8 @@ static struct api_command {
{ "data", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_data },
{ "chart", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_chart },
{ "charts", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_charts },
+ { "context", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_context },
+ { "contexts", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_contexts },
{ "archivedcharts", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_archivedcharts },
// registry checks the ACL by itself, so we allow everything
@@ -1401,6 +1697,10 @@ static struct api_command {
{ "manage/health", 0, WEB_CLIENT_ACL_MGMT, web_client_api_request_v1_mgmt_health },
{ "aclk", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_aclk_state },
{ "metric_correlations", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_metric_correlations },
+ { "weights", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_weights },
+
+ { "dbengine_stats", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_dbengine_stats },
+
// terminator
{ NULL, 0, WEB_CLIENT_ACL_NONE, NULL },
};