diff options
Diffstat (limited to '')
-rw-r--r-- | web/api/exporters/shell/README.md | 8 | ||||
-rw-r--r-- | web/api/formatters/json/json.c | 10 | ||||
-rw-r--r-- | web/api/formatters/json/json.h | 2 | ||||
-rw-r--r-- | web/api/formatters/json_wrapper.c | 28 | ||||
-rw-r--r-- | web/api/formatters/json_wrapper.h | 2 | ||||
-rw-r--r-- | web/api/formatters/rrd2json.c | 89 | ||||
-rw-r--r-- | web/api/formatters/value/value.c | 3 | ||||
-rw-r--r-- | web/api/queries/query.c | 35 | ||||
-rw-r--r-- | web/api/queries/rrdr.c | 7 | ||||
-rw-r--r-- | web/api/queries/rrdr.h | 1 | ||||
-rw-r--r-- | web/api/web_api_v1.c | 26 | ||||
-rw-r--r-- | web/gui/dashboard_info.js | 81 | ||||
-rw-r--r-- | web/gui/main.js | 14 | ||||
-rw-r--r-- | web/server/web_client.c | 27 | ||||
-rw-r--r-- | web/server/web_client.h | 1 |
15 files changed, 228 insertions, 106 deletions
diff --git a/web/api/exporters/shell/README.md b/web/api/exporters/shell/README.md index b919045f2..9d44a3707 100644 --- a/web/api/exporters/shell/README.md +++ b/web/api/exporters/shell/README.md @@ -38,14 +38,12 @@ echo ${NETDATA_SYSTEM_CPU_VISIBLETOTAL} # what about alarms? set | grep "^NETDATA_ALARM_SYSTEM_SWAP_" -NETDATA_ALARM_SYSTEM_SWAP_RAM_IN_SWAP_STATUS=CRITICAL -NETDATA_ALARM_SYSTEM_SWAP_RAM_IN_SWAP_VALUE=53 NETDATA_ALARM_SYSTEM_SWAP_USED_SWAP_STATUS=CLEAR NETDATA_ALARM_SYSTEM_SWAP_USED_SWAP_VALUE=51 -# let's get the current status of the alarm 'ram in swap' -echo ${NETDATA_ALARM_SYSTEM_SWAP_RAM_IN_SWAP_STATUS} -CRITICAL +# let's get the current status of the alarm 'used swap' +echo ${NETDATA_ALARM_SYSTEM_SWAP_USED_SWAP_STATUS} +CLEAR # is it fast? time curl -s 'http://localhost:19999/api/v1/allmetrics' >/dev/null diff --git a/web/api/formatters/json/json.c b/web/api/formatters/json/json.c index f28eb5738..bf311e22c 100644 --- a/web/api/formatters/json/json.c +++ b/web/api/formatters/json/json.c @@ -5,8 +5,14 @@ #define JSON_DATES_JS 1 #define JSON_DATES_TIMESTAMP 2 -void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, RRDDIM *temp_rd) { - rrdset_check_rdlock(r->st); +void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, struct context_param *context_param_list) +{ + RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL; + + int should_lock = (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)); + + if (should_lock) + rrdset_check_rdlock(r->st); //info("RRD2JSON(): %s: BEGIN", r->st->id); int row_annotations = 0, dates, dates_with_new = 0; diff --git a/web/api/formatters/json/json.h b/web/api/formatters/json/json.h index 6d73a3ffe..5c4e11371 100644 --- a/web/api/formatters/json/json.h +++ b/web/api/formatters/json/json.h @@ -5,6 +5,6 @@ #include "../rrd2json.h" -extern void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, RRDDIM *temp_rd); +extern void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, struct context_param *context_param_list); #endif //NETDATA_API_FORMATTER_JSON_H diff --git a/web/api/formatters/json_wrapper.c b/web/api/formatters/json_wrapper.c index cf4f1099a..1d9c2472a 100644 --- a/web/api/formatters/json_wrapper.c +++ b/web/api/formatters/json_wrapper.c @@ -2,8 +2,16 @@ #include "json_wrapper.h" -void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd, char *chart_label_key) { - rrdset_check_rdlock(r->st); +void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, + struct context_param *context_param_list, char *chart_label_key) +{ + + RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL; + int should_lock = (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)); + uint8_t context_mode = (!context_param_list || (context_param_list->flags & CONTEXT_FLAGS_CONTEXT)); + + if (should_lock) + rrdset_check_rdlock(r->st); long rows = rrdr_rows(r); long c, i; @@ -22,7 +30,8 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS sq[0] = '"'; } - rrdset_rdlock(r->st); + if (should_lock) + rrdset_rdlock(r->st); buffer_sprintf(wb, "{\n" " %sapi%s: 1,\n" " %sid%s: %s%s%s,\n" @@ -35,16 +44,17 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS " %safter%s: %u,\n" " %sdimension_names%s: [" , kq, kq - , kq, kq, sq, temp_rd?r->st->context:r->st->id, sq - , kq, kq, sq, temp_rd?r->st->context:r->st->name, sq + , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->id, sq + , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->name, sq , kq, kq, r->update_every , kq, kq, r->st->update_every - , kq, kq, (uint32_t)rrdset_first_entry_t_nolock(r->st) - , kq, kq, (uint32_t)rrdset_last_entry_t_nolock(r->st) + , kq, kq, (uint32_t) (context_param_list ? context_param_list->first_entry_t : rrdset_first_entry_t_nolock(r->st)) + , kq, kq, (uint32_t) (context_param_list ? context_param_list->last_entry_t : rrdset_last_entry_t_nolock(r->st)) , kq, kq, (uint32_t)r->before , kq, kq, (uint32_t)r->after , kq, kq); - rrdset_unlock(r->st); + if (should_lock) + rrdset_unlock(r->st); for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue; @@ -89,7 +99,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS buffer_strcat(wb, "],\n"); // Composite charts - if (temp_rd) { + if (context_mode && temp_rd) { buffer_sprintf( wb, " %schart_ids%s: [", diff --git a/web/api/formatters/json_wrapper.h b/web/api/formatters/json_wrapper.h index d48d5d1ae..14662db74 100644 --- a/web/api/formatters/json_wrapper.h +++ b/web/api/formatters/json_wrapper.h @@ -5,7 +5,7 @@ #include "rrd2json.h" -extern void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd, char *chart_key); +extern void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, struct context_param *context_param_list, char *chart_key); extern void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value); #endif //NETDATA_API_FORMATTER_JSON_WRAPPER_H diff --git a/web/api/formatters/rrd2json.c b/web/api/formatters/rrd2json.c index d8e248066..5b12c89ba 100644 --- a/web/api/formatters/rrd2json.c +++ b/web/api/formatters/rrd2json.c @@ -2,7 +2,28 @@ #include "web/api/web_api_v1.h" -static inline void free_temp_rrddim(RRDDIM *temp_rd) +static inline void free_single_rrdrim(RRDDIM *temp_rd, int archive_mode) +{ + if (unlikely(!temp_rd)) + return; + + freez((char *)temp_rd->id); + freez((char *)temp_rd->name); + + if (unlikely(archive_mode)) { + temp_rd->rrdset->counter--; + if (!temp_rd->rrdset->counter) { + freez((char *)temp_rd->rrdset->name); + freez(temp_rd->rrdset->context); + freez(temp_rd->rrdset); + } + } + freez(temp_rd->state->metric_uuid); + freez(temp_rd->state); + freez(temp_rd); +} + +static inline void free_rrddim_list(RRDDIM *temp_rd, int archive_mode) { if (unlikely(!temp_rd)) return; @@ -10,14 +31,7 @@ static inline void free_temp_rrddim(RRDDIM *temp_rd) RRDDIM *t; while (temp_rd) { t = temp_rd->next; - freez((char *)temp_rd->id); - freez((char *)temp_rd->name); -#ifdef ENABLE_DBENGINE - if (temp_rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) - freez(temp_rd->state->metric_uuid); -#endif - freez(temp_rd->state); - freez(temp_rd); + free_single_rrdrim(temp_rd, archive_mode); temp_rd = t; } } @@ -27,7 +41,7 @@ void free_context_param_list(struct context_param **param_list) if (unlikely(!param_list || !*param_list)) return; - free_temp_rrddim(((*param_list)->rd)); + free_rrddim_list(((*param_list)->rd), (*param_list)->flags & CONTEXT_FLAGS_ARCHIVE); freez((*param_list)); *param_list = NULL; } @@ -36,21 +50,17 @@ void rebuild_context_param_list(struct context_param *context_param_list, time_t { RRDDIM *temp_rd = context_param_list->rd; RRDDIM *new_rd_list = NULL, *t; + int is_archived = (context_param_list->flags & CONTEXT_FLAGS_ARCHIVE); while (temp_rd) { t = temp_rd->next; - if (rrdset_last_entry_t(temp_rd->rrdset) >= after_requested) { + RRDSET *st = temp_rd->rrdset; + time_t last_entry_t = is_archived ? st->last_entry_t : rrdset_last_entry_t(st); + + if (last_entry_t >= after_requested) { temp_rd->next = new_rd_list; new_rd_list = temp_rd; - } else { - freez((char *)temp_rd->id); - freez((char *)temp_rd->name); -#ifdef ENABLE_DBENGINE - if (temp_rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) - freez(temp_rd->state->metric_uuid); -#endif - freez(temp_rd->state); - freez(temp_rd); - } + } else + free_single_rrdrim(temp_rd, is_archived); temp_rd = t; } context_param_list->rd = new_rd_list; @@ -65,6 +75,7 @@ void build_context_param_list(struct context_param **param_list, RRDSET *st) *param_list = mallocz(sizeof(struct context_param)); (*param_list)->first_entry_t = LONG_MAX; (*param_list)->last_entry_t = 0; + (*param_list)->flags = CONTEXT_FLAGS_CONTEXT; (*param_list)->rd = NULL; } @@ -214,9 +225,9 @@ int rrdset2anything_api_v1( , struct context_param *context_param_list , char *chart_label_key ) { - time_t last_accessed_time = now_realtime_sec(); - st->last_accessed_time = last_accessed_time; + if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) + st->last_accessed_time = now_realtime_sec(); RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL, context_param_list); if(!r) { @@ -238,7 +249,7 @@ int rrdset2anything_api_v1( case DATASOURCE_SSV: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 1, context_param_list, chart_label_key); rrdr2ssv(r, wb, options, "", " ", ""); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -251,7 +262,7 @@ int rrdset2anything_api_v1( case DATASOURCE_SSV_COMMA: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 1, context_param_list, chart_label_key); rrdr2ssv(r, wb, options, "", ",", ""); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -264,7 +275,7 @@ int rrdset2anything_api_v1( case DATASOURCE_JS_ARRAY: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 0, context_param_list, chart_label_key); rrdr2ssv(r, wb, options, "[", ",", "]"); rrdr_json_wrapper_end(r, wb, format, options, 0); } @@ -277,7 +288,7 @@ int rrdset2anything_api_v1( case DATASOURCE_CSV: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 1, context_param_list, chart_label_key); rrdr2csv(r, wb, format, options, "", ",", "\\n", "", temp_rd); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -290,7 +301,7 @@ int rrdset2anything_api_v1( case DATASOURCE_CSV_MARKDOWN: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 1, context_param_list, chart_label_key); rrdr2csv(r, wb, format, options, "", "|", "\\n", "", temp_rd); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -303,7 +314,7 @@ int rrdset2anything_api_v1( case DATASOURCE_CSV_JSON_ARRAY: wb->contenttype = CT_APPLICATION_JSON; if(options & RRDR_OPTION_JSON_WRAP) { - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 0, context_param_list, chart_label_key); buffer_strcat(wb, "[\n"); rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd); buffer_strcat(wb, "\n]"); @@ -320,7 +331,7 @@ int rrdset2anything_api_v1( case DATASOURCE_TSV: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 1, context_param_list, chart_label_key); rrdr2csv(r, wb, format, options, "", "\t", "\\n", "", temp_rd); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -333,7 +344,7 @@ int rrdset2anything_api_v1( case DATASOURCE_HTML: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 1, context_param_list, chart_label_key); buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n"); rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "", temp_rd); buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n"); @@ -351,9 +362,9 @@ int rrdset2anything_api_v1( wb->contenttype = CT_APPLICATION_X_JAVASCRIPT; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 0, context_param_list, chart_label_key); - rrdr2json(r, wb, options, 1, temp_rd); + rrdr2json(r, wb, options, 1, context_param_list); if(options & RRDR_OPTION_JSON_WRAP) rrdr_json_wrapper_end(r, wb, format, options, 0); @@ -363,9 +374,9 @@ int rrdset2anything_api_v1( wb->contenttype = CT_APPLICATION_JSON; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 0, context_param_list, chart_label_key); - rrdr2json(r, wb, options, 1, temp_rd); + rrdr2json(r, wb, options, 1, context_param_list); if(options & RRDR_OPTION_JSON_WRAP) rrdr_json_wrapper_end(r, wb, format, options, 0); @@ -374,9 +385,9 @@ int rrdset2anything_api_v1( case DATASOURCE_JSONP: wb->contenttype = CT_APPLICATION_X_JAVASCRIPT; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 0, context_param_list, chart_label_key); - rrdr2json(r, wb, options, 0, temp_rd); + rrdr2json(r, wb, options, 0, context_param_list); if(options & RRDR_OPTION_JSON_WRAP) rrdr_json_wrapper_end(r, wb, format, options, 0); @@ -387,9 +398,9 @@ int rrdset2anything_api_v1( wb->contenttype = CT_APPLICATION_JSON; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); + rrdr_json_wrapper_begin(r, wb, format, options, 0, context_param_list, chart_label_key); - rrdr2json(r, wb, options, 0, temp_rd); + rrdr2json(r, wb, options, 0, context_param_list); if(options & RRDR_OPTION_JSON_WRAP) rrdr_json_wrapper_end(r, wb, format, options, 0); diff --git a/web/api/formatters/value/value.c b/web/api/formatters/value/value.c index aea6c162b..a69af6165 100644 --- a/web/api/formatters/value/value.c +++ b/web/api/formatters/value/value.c @@ -4,7 +4,8 @@ inline calculated_number rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all_values_are_null) { - rrdset_check_rdlock(r->st); + if (r->st_needs_lock) + rrdset_check_rdlock(r->st); long c; RRDDIM *d; diff --git a/web/api/queries/query.c b/web/api/queries/query.c index 663e4bd14..2a27a94fc 100644 --- a/web/api/queries/query.c +++ b/web/api/queries/query.c @@ -281,8 +281,14 @@ RRDR_GROUPING web_client_api_request_v1_data_group(const char *name, RRDR_GROUPI // ---------------------------------------------------------------------------- -static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options, const char *dims, RRDDIM *temp_rd) { - rrdset_check_rdlock(r->st); +static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options, const char *dims, + struct context_param *context_param_list) +{ + RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL; + int should_lock = (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)); + + if (should_lock) + rrdset_check_rdlock(r->st); if(unlikely(!dims || !*dims || (dims[0] == '*' && dims[1] == '\0'))) return; @@ -758,8 +764,8 @@ static int rrdr_convert_before_after_to_absolute( } // allow relative for before (smaller than API_RELATIVE_TIME_MAX) - if(abs(before_requested) <= API_RELATIVE_TIME_MAX) { - if(abs(before_requested) % update_every) { + if(ABS(before_requested) <= API_RELATIVE_TIME_MAX) { + if(ABS(before_requested) % update_every) { // make sure it is multiple of st->update_every if(before_requested < 0) before_requested = before_requested - update_every - before_requested % update_every; @@ -772,9 +778,9 @@ static int rrdr_convert_before_after_to_absolute( } // allow relative for after (smaller than API_RELATIVE_TIME_MAX) - if(abs(after_requested) <= API_RELATIVE_TIME_MAX) { + if(ABS(after_requested) <= API_RELATIVE_TIME_MAX) { if(after_requested == 0) after_requested = -update_every; - if(abs(after_requested) % update_every) { + if(ABS(after_requested) % update_every) { // make sure it is multiple of st->update_every if(after_requested < 0) after_requested = after_requested - update_every - after_requested % update_every; else after_requested = after_requested + update_every - after_requested % update_every; @@ -1060,10 +1066,11 @@ static RRDR *rrd2rrdr_fixedstep( // ------------------------------------------------------------------------- // disable the not-wanted dimensions - rrdset_check_rdlock(st); + if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) + rrdset_check_rdlock(st); if(dimensions) - rrdr_disable_not_selected_dimensions(r, options, dimensions, temp_rd); + rrdr_disable_not_selected_dimensions(r, options, dimensions, context_param_list); // ------------------------------------------------------------------------- @@ -1435,11 +1442,11 @@ static RRDR *rrd2rrdr_variablestep( // ------------------------------------------------------------------------- // disable the not-wanted dimensions - - rrdset_check_rdlock(st); + if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) + rrdset_check_rdlock(st); if(dimensions) - rrdr_disable_not_selected_dimensions(r, options, dimensions, temp_rd); + rrdr_disable_not_selected_dimensions(r, options, dimensions, context_param_list); // ------------------------------------------------------------------------- @@ -1591,8 +1598,12 @@ RRDR *rrd2rrdr( if (first_entry_t > after_requested) first_entry_t = after_requested; - if (context_param_list) + if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) { rebuild_context_param_list(context_param_list, after_requested); + st = context_param_list->rd ? context_param_list->rd->rrdset : NULL; + if (unlikely(!st)) + return NULL; + } #ifdef ENABLE_DBENGINE if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) { diff --git a/web/api/queries/rrdr.c b/web/api/queries/rrdr.c index ef237fa02..b64868222 100644 --- a/web/api/queries/rrdr.c +++ b/web/api/queries/rrdr.c @@ -100,7 +100,7 @@ inline void rrdr_free(RRDR *r) RRDR *rrdr_create(struct rrdset *st, long n, struct context_param *context_param_list) { - if(unlikely(!st)) { + if (unlikely(!st)) { error("NULL value given!"); return NULL; } @@ -108,7 +108,10 @@ RRDR *rrdr_create(struct rrdset *st, long n, struct context_param *context_param RRDR *r = callocz(1, sizeof(RRDR)); r->st = st; - rrdr_lock_rrdset(r); + if (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE)) { + rrdr_lock_rrdset(r); + r->st_needs_lock = 1; + } RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL; RRDDIM *rd; diff --git a/web/api/queries/rrdr.h b/web/api/queries/rrdr.h index 4d349c305..d95c10857 100644 --- a/web/api/queries/rrdr.h +++ b/web/api/queries/rrdr.h @@ -73,6 +73,7 @@ typedef struct rrdresult { time_t after; int has_st_lock; // if st is read locked by us + uint8_t st_needs_lock; // if ST should be locked // internal rrd2rrdr() members below this point struct { diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 73ac15d30..1d8217bbd 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -276,6 +276,7 @@ inline int web_client_api_request_v1_alarm_count(RRDHOST *host, struct web_clien inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) { uint32_t after = 0; + char *chart = NULL; while(url) { char *value = mystrsep(&url, "&"); @@ -285,12 +286,13 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client if(!name || !*name) continue; if(!value || !*value) continue; - if(!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0); + if (!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0); + else if (!strcmp(name, "chart")) chart = value; } buffer_flush(w->response.data); w->response.data->contenttype = CT_APPLICATION_JSON; - health_alarm_log2json(host, w->response.data, after); + health_alarm_log2json(host, w->response.data, after, chart); return HTTP_RESP_OK; } @@ -511,6 +513,10 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c rrdhost_unlock(host); if (likely(context_param_list && context_param_list->rd)) // Just set the first one st = context_param_list->rd->rrdset; + else { + if (!chart_label_key) + sql_build_context_param_list(&context_param_list, host, context, NULL); + } } else { st = rrdset_find(host, chart); @@ -518,6 +524,17 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c st = rrdset_find_byname(host, chart); if (likely(st)) st->last_accessed_time = now_realtime_sec(); + else + sql_build_context_param_list(&context_param_list, host, NULL, chart); + } + + if (!st) { + if (likely(context_param_list && context_param_list->rd && context_param_list->rd->rrdset)) + st = context_param_list->rd->rrdset; + else { + free_context_param_list(&context_param_list); + context_param_list = NULL; + } } if (!st && !context_param_list) { @@ -961,6 +978,11 @@ 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"); +#ifdef ACLK_NG + buffer_strcat(wb, "\t\"aclk-implementation\": \"Next Generation\",\n"); +#else + buffer_strcat(wb, "\t\"aclk-implementation\": \"legacy\",\n"); +#endif #else buffer_strcat(wb, "\t\"cloud-available\": false,\n"); #endif diff --git a/web/gui/dashboard_info.js b/web/gui/dashboard_info.js index df15a6372..d5d7c693c 100644 --- a/web/gui/dashboard_info.js +++ b/web/gui/dashboard_info.js @@ -582,11 +582,19 @@ netdataDashboard.menu = { icon: '<i class="fas fa-bell"></i>', info: 'Charts showing alarm status over time. More details <a href="https://github.com/netdata/netdata/blob/master/collectors/python.d.plugin/alarms/README.md" target="_blank">here</a>.' }, + 'statsd': { title: 'StatsD', icon: '<i class="fas fa-chart-line"></i>', info:'StatsD is an industry-standard technology stack for monitoring applications and instrumenting any piece of software to deliver custom metrics. Netdata allows the user to organize the metrics in different charts and visualize any application metric easily. Read more on <a href="https://learn.netdata.cloud/docs/agent/collectors/statsd.plugin">Netdata Learn</a>.' - } + }, + + 'supervisord': { + title: 'Supervisord', + icon: '<i class="fas fa-tasks"></i>', + info: 'Detailed statistics for each group of processes controlled by <b><a href="http://supervisord.org/">Supervisor</a></b>. ' + + 'Netdata collects these metrics using <a href="http://supervisord.org/api.html#supervisor.rpcinterface.SupervisorNamespaceRPCInterface.getAllProcessInfo" target="_blank"><code>getAllProcessInfo</code></a> method.' + }, }; @@ -1010,6 +1018,38 @@ netdataDashboard.context = { info: 'Transparent HugePages (THP) is backing virtual memory with huge pages, supporting automatic promotion and demotion of page sizes. It works for all applications for anonymous memory mappings and tmpfs/shmem.' }, + 'mem.cachestat_ratio': { + info: 'When the processor needs to read or write a location in main memory, it checks for a corresponding entry in the page cache. If the entry is there, a page cache hit has occurred and the read is from the cache. If the entry is not there, a page cache miss has occurred and the kernel allocates a new entry and copies in data from the disk. Netdata calculates the percentage of accessed files that are cached on memory. <a href="https://github.com/iovisor/bcc/blob/master/tools/cachestat.py#L126-L138" target="_blank">The ratio</a> is calculated counting the accessed cached pages (without counting dirty pages and pages added because of read misses) divided by total access without dirty pages. The algorithm will not plot data when ratio is zero and our dashboard will interpolate the plot. ' + }, + + 'mem.cachestat_dirties': { + info: 'Number of <a href="https://en.wikipedia.org/wiki/Page_cache#Memory_conservation" target="_blank">dirty(modified) pages</a> cache. Pages in the page cache modified after being brought in are called dirty pages. Since non-dirty pages in the page cache have identical copies in <a href="https://en.wikipedia.org/wiki/Secondary_storage" target="_blank">secondary storage</a> (e.g. hard disk drive or solid-state drive), discarding and reusing their space is much quicker than paging out application memory, and is often preferred over flushing the dirty pages into secondary storage and reusing their space.' + }, + + 'mem.cachestat_hits': { + info: 'When the processor needs to read or write a location in main memory, it checks for a corresponding entry in the page cache. If the entry is there, a page cache hit has occurred and the read is from the cache. Hits show pages accessed that were not modified (we are excluding dirty pages), this counting also excludes the recent pages inserted for read.' + }, + + 'mem.cachestat_misses': { + info: 'When the processor needs to read or write a location in main memory, it checks for a corresponding entry in the page cache. If the entry is not there, a page cache miss has occurred and the cache allocates a new entry and copies in data for the main memory. Misses count page insertions to the memory not related to writing.' + }, + + 'mem.sync': { + info: 'System calls for <a href="https://man7.org/linux/man-pages/man2/sync.2.html" target="_blank">sync() and syncfs()</a> which flush the file system buffers to storage devices. Performance perturbations might be caused by these calls. The <code>sync()</code> calls are based on the eBPF <a href="https://github.com/iovisor/bcc/blob/master/tools/syncsnoop.py" target="_blank">syncsnoop</a> from BCC tools.' + }, + + 'mem.file_sync': { + info: 'System calls for <a href="https://man7.org/linux/man-pages/man2/fsync.2.html" target="_blank">fsync() and fdatasync()</a> transfer all modified page caches for the files on disk devices. These calls block until the device reports that the transfer has been completed.' + }, + + 'mem.memory_map': { + info: 'System calls for <a href="https://man7.org/linux/man-pages/man2/msync.2.html" target="_blank">msync()</a> which flushes changes made to the in-core copy of a file that was mapped.' + }, + + 'mem.file_segment': { + info: 'System calls for <a href="https://man7.org/linux/man-pages/man2/sync_file_range.2.html" target="_blank">sync_file_range()</a> permits fine control when synchronizing the open file referred to by the file descriptor fd with disk. This system call is extremely dangerous and should not be used in portable programs.' + }, + // ------------------------------------------------------------------------ // network interfaces @@ -1017,6 +1057,18 @@ netdataDashboard.context = { info: 'Packets that have been dropped at the network interface level. These are the same counters reported by <code>ifconfig</code> as <code>RX dropped</code> (inbound) and <code>TX dropped</code> (outbound). <b>inbound</b> packets can be dropped at the network interface level due to <a href="#menu_system_submenu_softnet_stat">softnet backlog</a> overflow, bad / unintented VLAN tags, unknown or unregistered protocols, IPv6 frames when the server is not configured for IPv6. Check <a href="https://www.novell.com/support/kb/doc.php?id=7007165" target="_blank">this document</a> for more information.' }, + 'net.duplex': { + info: 'State map: 0 - unknown, 1 - half duplex, 2 - full duplex' + }, + + 'net.operstate': { + info: 'State map: 0 - unknown, 1 - notpresent, 2 - down, 3 - lowerlayerdown, 4 - testing, 5 - dormant, 6 - up' + }, + + 'net.carrier': { + info: 'State map: 0 - down, 1 - up' + }, + // ------------------------------------------------------------------------ // IP @@ -1119,12 +1171,12 @@ netdataDashboard.context = { }, 'apps.file_closed': { - info: 'Calls to the internal function <a href="https://elixir.bootlin.com/linux/latest/source/fs/file.c#L665" target="_blank">__close_fd</a>, which is called from' + + info: 'Calls to the internal function <a href="https://elixir.bootlin.com/linux/v5.10/source/fs/file.c#L665" target="_blank">__close_fd</a> or <a href="https://elixir.bootlin.com/linux/v5.11/source/fs/file.c#L617" target="_blank">close_fd</a> according to your kernel version, which is called from' + ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. ' }, 'apps.file_close_error': { - info: 'Failed calls to the internal function <a href="https://elixir.bootlin.com/linux/latest/source/fs/file.c#L665" target="_blank">__close_fd</a>.' + info: 'Failed calls to the internal function <a href="https://elixir.bootlin.com/linux/v5.10/source/fs/file.c#L665" target="_blank">__close_fd</a> or <a href="https://elixir.bootlin.com/linux/v5.11/source/fs/file.c#L617" target="_blank">close_fd</a> according to your kernel version.' }, 'apps.file_deleted': { @@ -1342,6 +1394,11 @@ netdataDashboard.context = { info: 'Disk Utilization measures the amount of time the disk was busy with something. This is not related to its performance. 100% means that the system always had an outstanding operation on the disk. Keep in mind that depending on the underlying technology of the disk, 100% here may or may not be an indication of congestion.' }, + 'disk.busy': { + colors: '#FF5588', + info: 'Disk Busy Time measures the amount of time the disk was busy with something.' + }, + 'disk.backlog': { colors: '#0099CC', info: 'Backlog is an indication of the duration of pending disk operations. On every I/O event the system is multiplying the time spent doing I/O since the last update of this field with the number of pending operations. While not accurate, this metric can provide an indication of the expected completion time of the operations in progress.' @@ -2306,7 +2363,7 @@ netdataDashboard.context = { }, 'web_log.squid_transport_errors': { - info: 'These tags are optional and describe some error conditions which occured during response delivery (if any). ' + + info: 'These tags are optional and describe some error conditions which occurred during response delivery (if any). ' + '<code>ABORTED</code> when the response was not completed due to the connection being aborted (usually by the client). ' + '<code>TIMEOUT</code>, when the response was not completed due to a connection timeout.' }, @@ -3063,7 +3120,7 @@ netdataDashboard.context = { }, 'squidlog.cache_code_error_tag_requests': { - info: 'These tags are optional and describe some error conditions which occured during response delivery.<br>' + + info: 'These tags are optional and describe some error conditions which occurred during response delivery.<br>' + '<ul>' + ' <li><code>ABORTED</code> the response was not completed due to the connection being aborted (usually by the client).</li>' + ' <li><code>TIMEOUT</code> the response was not completed due to a connection timeout.</li>' + @@ -3304,7 +3361,7 @@ netdataDashboard.context = { info: 'Calls for internal functions on Linux kernel. The open dimension is attached to the kernel internal function <code>do_sys_open</code> ( For kernels newer than <code>5.5.19</code> we add a kprobe to <code>do_sys_openat2</code>. ), which is the common function called from'+ ' <a href="https://www.man7.org/linux/man-pages/man2/open.2.html" target="_blank">open(2)</a> ' + ' and <a href="https://www.man7.org/linux/man-pages/man2/openat.2.html" target="_blank">openat(2)</a>. ' + - ' The close dimension is attached to the function <code>__close_fd</code>, which is called from system call' + + ' The close dimension is attached to the function <code>__close_fd</code> or <code>close_fd</code> according to your kernel version, which is called from system call' + ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. ' }, @@ -3313,7 +3370,7 @@ netdataDashboard.context = { info: 'Failed calls to the kernel internal function <code>do_sys_open</code> ( For kernels newer than <code>5.5.19</code> we add a kprobe to <code>do_sys_openat2</code>. ), which is the common function called from'+ ' <a href="https://www.man7.org/linux/man-pages/man2/open.2.html" target="_blank">open(2)</a> ' + ' and <a href="https://www.man7.org/linux/man-pages/man2/openat.2.html" target="_blank">openat(2)</a>. ' + - ' The close dimension is attached to the function <code>__close_fd</code>, which is called from system call' + + ' The close dimension is attached to the function <code>__close_fd</code> or <code>close_fd</code> according to your kernel version, which is called from system call' + ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. ' }, @@ -3707,6 +3764,7 @@ netdataDashboard.context = { + ' data-chart-library="easypiechart"' + ' data-title="Fan Speed"' + ' data-units="percentage"' + + ' data-easypiechart-max-value="100"' + ' data-gauge-adjust="width"' + ' data-width="12%"' + ' data-before="0"' @@ -3778,4 +3836,13 @@ netdataDashboard.context = { } ] }, + + // ------------------------------------------------------------------------ + // Supervisor + + 'supervisord.process_state_code': { + info: '<a href="http://supervisord.org/subprocess.html#process-states" target="_blank">Process states map</a>: ' + + '<code>0</code> - stopped, <code>10</code> - starting, <code>20</code> - running, <code>30</code> - backoff,' + + '<code>40</code> - stopping, <code>100</code> - exited, <code>200</code> - fatal, <code>1000</code> - unknown.' + }, }; diff --git a/web/gui/main.js b/web/gui/main.js index 5bf11e5f7..dc9a5f7f0 100644 --- a/web/gui/main.js +++ b/web/gui/main.js @@ -668,13 +668,13 @@ function renderMachines(machinesArray) { if (machines) { html += ( `<div class="info-item"> - <a href="https://github.com/netdata/netdata/tree/master/registry#netdata-registry" target="_blank">Your nodes list is empty</a> + <a href="https://github.com/netdata/netdata/tree/master/registry#registry" target="_blank">Your nodes list is empty</a> </div>` ) } else { html += ( `<div class="info-item"> - <a href="https://github.com/netdata/netdata/tree/master/registry#netdata-registry" target="_blank">Failed to contact the registry</a> + <a href="https://github.com/netdata/netdata/tree/master/registry#registry" target="_blank">Failed to contact the registry</a> </div>` ) } @@ -812,7 +812,7 @@ function renderMyNetdataMenu(machinesArray) { </div> <div class="agent-item"> <i class="fas fa-question-circle""></i> - <a href="https://github.com/netdata/netdata/tree/master/registry#netdata-registry" target="_blank">What is this?</a> + <a href="https://github.com/netdata/netdata/tree/master/registry#registry" target="_blank">What is this?</a> <div></div> </div>` ) @@ -1815,8 +1815,8 @@ function renderPage(menus, data) { const isMemoryModeDbEngine = data.memory_mode === "dbengine"; - sidebar += '<li class="" style="padding-top:15px;"><a href="https://docs.netdata.cloud/collectors/quickstart/" target="_blank"><i class="fas fa-plus"></i> Add more charts</a></li>'; - sidebar += '<li class=""><a href="https://docs.netdata.cloud/health/quickstart/" target="_blank"><i class="fas fa-plus"></i> Add more alarms</a></li>'; + sidebar += '<li class="" style="padding-top:15px;"><a href="https://learn.netdata.cloud/docs/agent/collectors/quickstart/" target="_blank"><i class="fas fa-plus"></i> Add more charts</a></li>'; + sidebar += '<li class=""><a href="https://learn.netdata.cloud/docs/agent/health/quickstart/" target="_blank"><i class="fas fa-plus"></i> Add more alarms</a></li>'; sidebar += '<li class="" style="margin:20px;color:#666;"><small>Every ' + ((data.update_every === 1) ? 'second' : data.update_every.toString() + ' seconds') + ', ' + 'Netdata collects <strong>' + data.dimensions_count.toLocaleString() + '</strong> metrics on ' + @@ -1828,7 +1828,7 @@ function renderPage(menus, data) { if (!isMemoryModeDbEngine) { sidebar += '<br /> <br />Get more history by ' + - '<a href="https://docs.netdata.cloud/docs/configuration-guide/#increase-the-metrics-retention-period" target=_blank>configuring Netdata\'s <strong>history</strong></a> or using the <a href="https://docs.netdata.cloud/database/engine/" target=_blank>DB engine.</a>'; + '<a href="https://learn.netdata.cloud/guides/longer-metrics-storage#using-the-round-robin-database" target=_blank>configuring Netdata\'s <strong>history</strong></a> or using the <a href="https://learn.netdata.cloud/docs/agent/database/engine/" target=_blank>DB engine.</a>'; } sidebar += '<br/> <br/><strong>netdata</strong><br/>' + data.version.toString() + '</small></li>'; @@ -3052,7 +3052,7 @@ function notifyForUpdate(force) { versionLog('<p><big>You already have the latest netdata!</big></p><p>No update yet?<br/>We probably need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/netdata/netdata" target="_blank">give netdata a <b><i class="fas fa-star"></i></b> at its github page</a>.</p>'); } else { save = true; - var compare = 'https://docs.netdata.cloud/changelog/'; + var compare = 'https://learn.netdata.cloud/docs/agent/changelog/'; versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest version: <b><code>' + sha2 + '</code></b></p><p><a href="' + compare + '" target="_blank">Click here for the changes log</a> and<br/><a href="https://github.com/netdata/netdata/tree/master/packaging/installer/UPDATE.md" target="_blank">click here for directions on updating</a> your netdata installation.</p><p>We suggest to review the changes log for new features you may be interested, or important bug fixes you may need.<br/>Keeping your netdata updated is generally a good idea.</p>'); document.getElementById('update_badge').innerHTML = '!'; diff --git a/web/server/web_client.c b/web/server/web_client.c index f0856fb17..5e3de38d5 100644 --- a/web/server/web_client.c +++ b/web/server/web_client.c @@ -55,7 +55,7 @@ static inline int web_client_uncrock_socket(struct web_client *w) { return 0; } -static inline char *strip_control_characters(char *url) { +char *strip_control_characters(char *url) { char *s = url; if(!s) return ""; @@ -1374,34 +1374,25 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch uint32_t hash = simple_hash(tok); host = rrdhost_find_by_hostname(tok, hash); - if(!host) host = rrdhost_find_by_guid(tok, hash); - -#ifdef ENABLE_DBENGINE - int release_host = 0; + if (!host) + host = rrdhost_find_by_guid(tok, hash); if (!host) { host = sql_create_host_by_uuid(tok); if (likely(host)) { - rrdhost_flag_set(host, RRDHOST_FLAG_ARCHIVED); - release_host = 1; - } - } - if(host) { - int rc = web_client_process_url(host, w, url); - if (release_host) { + int rc = web_client_process_url(host, w, url); freez(host->hostname); - freez((char *) host->os); - freez((char *) host->tags); - freez((char *) host->timezone); + freez((char *)host->os); + freez((char *)host->tags); + freez((char *)host->timezone); freez(host->program_name); freez(host->program_version); freez(host->registry_hostname); + freez(host->system_info); freez(host); + return rc; } - return rc; } -#else if (host) return web_client_process_url(host, w, url); -#endif } buffer_flush(w->response.data); diff --git a/web/server/web_client.h b/web/server/web_client.h index 48bf1ac86..4580b9749 100644 --- a/web/server/web_client.h +++ b/web/server/web_client.h @@ -211,6 +211,7 @@ extern void buffer_data_options2string(BUFFER *wb, uint32_t options); extern int mysendfile(struct web_client *w, char *filename); extern void web_client_build_http_header(struct web_client *w); +extern char *strip_control_characters(char *url); #include "daemon/common.h" |