diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-08-12 07:26:17 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-08-12 07:26:17 +0000 |
commit | 7877a98bd9c00db5e81dd2f8c734cba2bab20be7 (patch) | |
tree | d18b767250f7c7ced9b8abe2ece784ac1fe24d3e /web/api/web_api_v1.c | |
parent | Releasing debian version 1.35.1-2. (diff) | |
download | netdata-7877a98bd9c00db5e81dd2f8c734cba2bab20be7.tar.xz netdata-7877a98bd9c00db5e81dd2f8c734cba2bab20be7.zip |
Merging upstream version 1.36.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/api/web_api_v1.c')
-rw-r--r-- | web/api/web_api_v1.c | 468 |
1 files changed, 384 insertions, 84 deletions
diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index cb73f7c02..8bfc617fd 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 }, }; |