X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Frrd2json.c;h=568d04e8d9275e20291d2532d77c96973d88cdde;hb=048f7f7e4ad518adad428302da70fdc5dedde273;hp=bbf48a2965c44e06bb0fa34a779a5c59439fa2c1;hpb=c50ec4efef94710302a2da98b78d8a2bfc567c35;p=netdata.git diff --git a/src/rrd2json.c b/src/rrd2json.c index bbf48a29..568d04e8 100644 --- a/src/rrd2json.c +++ b/src/rrd2json.c @@ -1,9 +1,6 @@ #include "common.h" -#define HOSTNAME_MAX 1024 -char *hostname = "unknown"; - -void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) +void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used) { pthread_rwlock_rdlock(&st->rwlock); @@ -44,7 +41,7 @@ void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) unsigned long memory = st->memsize; - int c = 0; + size_t dimensions = 0; RRDDIM *rd; for(rd = st->dimensions; rd ; rd = rd->next) { if(rd->flags & RRDDIM_FLAG_HIDDEN) continue; @@ -54,25 +51,36 @@ void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) buffer_sprintf(wb, "%s" "\t\t\t\t\"%s\": { \"name\": \"%s\" }" - , c?",\n":"" + , dimensions?",\n":"" , rd->id , rd->name ); - c++; + dimensions++; } + if(dimensions_count) *dimensions_count += dimensions; + if(memory_used) *memory_used += memory; + + buffer_strcat(wb, "\n\t\t\t},\n\t\t\t\"green\": "); + buffer_rrd_value(wb, st->green); + buffer_strcat(wb, ",\n\t\t\t\"red\": "); + buffer_rrd_value(wb, st->red); + buffer_sprintf(wb, - "\n\t\t\t}\n" - "\t\t}" + "\n\t\t}" ); pthread_rwlock_unlock(&st->rwlock); } +void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) { + rrd_stats_api_v1_chart_with_data(st, wb, NULL, NULL); +} + void rrd_stats_api_v1_charts(BUFFER *wb) { - long c; + size_t c, dimensions = 0, memory = 0, alarms = 0; RRDSET *st; buffer_sprintf(wb, "{\n" @@ -80,7 +88,7 @@ void rrd_stats_api_v1_charts(BUFFER *wb) ",\n\t\"update_every\": %d" ",\n\t\"history\": %d" ",\n\t\"charts\": {" - , hostname + , localhost.hostname , rrd_update_every , rrd_default_history_entries ); @@ -92,19 +100,202 @@ void rrd_stats_api_v1_charts(BUFFER *wb) buffer_strcat(wb, "\n\t\t\""); buffer_strcat(wb, st->id); buffer_strcat(wb, "\": "); - rrd_stats_api_v1_chart(st, wb); + rrd_stats_api_v1_chart_with_data(st, wb, &dimensions, &memory); c++; } } + + RRDCALC *rc; + for(rc = localhost.alarms; rc ; rc = rc->next) { + if(rc->rrdset) + alarms++; + } + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock); + + buffer_sprintf(wb, "\n\t}" + ",\n\t\"charts_count\": %zu" + ",\n\t\"dimensions_count\": %zu" + ",\n\t\"alarms_count\": %zu" + ",\n\t\"rrd_memory_bytes\": %zu" + "\n}\n" + , c + , dimensions + , alarms + , memory + ); +} + +// ---------------------------------------------------------------------------- +// PROMETHEUS +// /api/v1/allmetrics?format=prometheus + +static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable) { + size_t n; + + for(n = 0; *s && n < usable ; d++, s++, n++) { + register char c = *s; + + if(unlikely(!isalnum(c))) *d = '_'; + else *d = c; + } + *d = '\0'; + + return n; +} + +#define PROMETHEUS_ELEMENT_MAX 256 + +void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb) +{ + pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock); + + char host[PROMETHEUS_ELEMENT_MAX + 1]; + prometheus_name_copy(host, config_get("global", "hostname", "localhost"), PROMETHEUS_ELEMENT_MAX); + + // for each chart + RRDSET *st; + for(st = localhost.rrdset_root; st ; st = st->next) { + char chart[PROMETHEUS_ELEMENT_MAX + 1]; + prometheus_name_copy(chart, st->id, PROMETHEUS_ELEMENT_MAX); + + buffer_strcat(wb, "\n"); + if(st->enabled && st->dimensions) { + pthread_rwlock_rdlock(&st->rwlock); + + // for each dimension + RRDDIM *rd; + for(rd = st->dimensions; rd ; rd = rd->next) { + if(rd->counter) { + char dimension[PROMETHEUS_ELEMENT_MAX + 1]; + prometheus_name_copy(dimension, rd->id, PROMETHEUS_ELEMENT_MAX); + + // buffer_sprintf(wb, "# HELP %s.%s %s\n", st->id, rd->id, st->units); + + switch(rd->algorithm) { + case RRDDIM_INCREMENTAL: + case RRDDIM_PCENT_OVER_DIFF_TOTAL: + buffer_sprintf(wb, "# TYPE %s_%s counter\n", chart, dimension); + break; + + default: + buffer_sprintf(wb, "# TYPE %s_%s gauge\n", chart, dimension); + break; + } + + // calculated_number n = (calculated_number)rd->last_collected_value * (calculated_number)(abs(rd->multiplier)) / (calculated_number)(abs(rd->divisor)); + // buffer_sprintf(wb, "%s.%s " CALCULATED_NUMBER_FORMAT " %llu\n", st->id, rd->id, n, + // (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000))); + + buffer_sprintf(wb, "%s_%s{instance=\"%s\"} " COLLECTED_NUMBER_FORMAT " %llu\n", + chart, dimension, host, rd->last_collected_value, + (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000))); + + } + } + + pthread_rwlock_unlock(&st->rwlock); + } + } + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock); +} + +// ---------------------------------------------------------------------------- +// BASH +// /api/v1/allmetrics?format=bash - buffer_strcat(wb, "\n\t}\n}\n"); +static inline size_t shell_name_copy(char *d, const char *s, size_t usable) { + size_t n; + + for(n = 0; *s && n < usable ; d++, s++, n++) { + register char c = *s; + + if(unlikely(!isalnum(c))) *d = '_'; + else *d = (char)toupper(c); + } + *d = '\0'; + + return n; } +#define SHELL_ELEMENT_MAX 100 + +void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb) +{ + pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock); + + char host[SHELL_ELEMENT_MAX + 1]; + shell_name_copy(host, config_get("global", "hostname", "localhost"), SHELL_ELEMENT_MAX); + + // for each chart + RRDSET *st; + for(st = localhost.rrdset_root; st ; st = st->next) { + calculated_number total = 0.0; + char chart[SHELL_ELEMENT_MAX + 1]; + shell_name_copy(chart, st->id, SHELL_ELEMENT_MAX); + + buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name); + if(st->enabled && st->dimensions) { + pthread_rwlock_rdlock(&st->rwlock); + + // for each dimension + RRDDIM *rd; + for(rd = st->dimensions; rd ; rd = rd->next) { + if(rd->counter) { + char dimension[SHELL_ELEMENT_MAX + 1]; + shell_name_copy(dimension, rd->id, SHELL_ELEMENT_MAX); + + calculated_number n = rd->last_stored_value; + + if(isnan(n) || isinf(n)) + buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, st->units); + else { + if(rd->multiplier < 0 || rd->divisor < 0) n = -n; + n = roundl(n); + if(!(rd->flags & RRDDIM_FLAG_HIDDEN)) total += n; + buffer_sprintf(wb, "NETDATA_%s_%s=\"%0.0Lf\" # %s\n", chart, dimension, n, st->units); + } + } + } + + total = roundl(total); + buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"%0.0Lf\" # %s\n", chart, total, st->units); + pthread_rwlock_unlock(&st->rwlock); + } + } + + buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n"); + + RRDCALC *rc; + for(rc = localhost.alarms; rc ;rc = rc->next) { + if(!rc->rrdset) continue; + + char chart[SHELL_ELEMENT_MAX + 1]; + shell_name_copy(chart, rc->rrdset->id, SHELL_ELEMENT_MAX); + + char alarm[SHELL_ELEMENT_MAX + 1]; + shell_name_copy(alarm, rc->name, SHELL_ELEMENT_MAX); + + calculated_number n = rc->value; + + if(isnan(n) || isinf(n)) + buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rc->units); + else { + n = roundl(n); + buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"%0.0Lf\" # %s\n", chart, alarm, n, rc->units); + } + + buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status)); + } + + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock); +} + +// ---------------------------------------------------------------------------- unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb) { - time_t now = time(NULL); + time_t now = now_realtime_sec(); pthread_rwlock_rdlock(&st->rwlock); @@ -242,7 +433,7 @@ void rrd_stats_all_json(BUFFER *wb) "\t\"history\": %d,\n" "\t\"memory\": %lu\n" "}\n" - , hostname + , localhost.hostname , rrd_update_every , rrd_default_history_entries , memory @@ -350,7 +541,7 @@ static void rrdr_dump(RRDR *r) } */ -void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims) +void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) { char b[strlen(dims) + 1]; char *o = b, *tok; @@ -376,7 +567,8 @@ void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims) // since the user needs this dimension // make it appear as NONZERO, to return it // even if the dimension has only zeros - r->od[c] |= RRDR_NONZERO; + // unless option non_zero is set + if (!(options & RRDR_OPTION_NONZERO)) r->od[c] |= RRDR_NONZERO; } } } @@ -433,17 +625,21 @@ void rrdr_buffer_print_format(BUFFER *wb, uint32_t format) uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims) { + (void)dims; + if(options & RRDR_OPTION_NONZERO) { long i; - if(dims && *dims) { + // commented due to #1514 + + //if(dims && *dims) { // the caller wants specific dimensions // disable NONZERO option // to make sure we don't accidentally prevent // the specific dimensions from being returned - i = 0; - } - else { + // i = 0; + //} + //else { // find how many dimensions are not zero long c; RRDDIM *rd; @@ -452,7 +648,7 @@ uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims) if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue; i++; } - } + //} // if with nonzero we get i = 0 (no dimensions will be returned) // disable nonzero to show all dimensions @@ -1035,12 +1231,12 @@ inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, in } if(unlikely(all_null)) { - if(likely(*all_values_are_null)) + if(likely(all_values_are_null)) *all_values_are_null = 1; return 0; } else { - if(likely(*all_values_are_null)) + if(likely(all_values_are_null)) *all_values_are_null = 0; } @@ -1157,7 +1353,7 @@ inline static void rrdr_free(RRDR *r) freez(r); } -inline void rrdr_done(RRDR *r) +static inline void rrdr_done(RRDR *r) { r->rows = r->c + 1; r->c = 0; @@ -1208,19 +1404,32 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g time_t last_entry_t = rrdset_last_entry_t(st); if(before == 0 && after == 0) { + // dump the all the data before = last_entry_t; after = first_entry_t; absolute_period_requested = 0; } - // allow relative for before and after - if(((before < 0)?-before:before) <= (st->update_every * st->entries)) { - before = last_entry_t + before; + // allow relative for before (smaller than API_RELATIVE_TIME_MAX) + if(((before < 0)?-before:before) <= API_RELATIVE_TIME_MAX) { + if(abs(before) % st->update_every) { + // make sure it is multiple of st->update_every + if(before < 0) before = before - st->update_every - before % st->update_every; + else before = before + st->update_every - before % st->update_every; + } + if(before > 0) before = first_entry_t + before; + else before = last_entry_t + before; absolute_period_requested = 0; } - if(((after < 0)?-after:after) <= (st->update_every * st->entries)) { + // allow relative for after (smaller than API_RELATIVE_TIME_MAX) + if(((after < 0)?-after:after) <= API_RELATIVE_TIME_MAX) { if(after == 0) after = -st->update_every; + if(abs(after) % st->update_every) { + // make sure it is multiple of st->update_every + if(after < 0) after = after - st->update_every - after % st->update_every; + else after = after + st->update_every - after % st->update_every; + } after = before + after; absolute_period_requested = 0; } @@ -1366,7 +1575,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g long c; for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) { last_values[c] = 0; - group_values[c] = 0; + group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0; group_counts[c] = 0; group_options[c] = 0; found_non_zero[c] = 0; @@ -1445,14 +1654,22 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g group_options[c] |= RRDR_RESET; switch(group_method) { + case GROUP_MIN: + if(unlikely(isnan(group_values[c])) || + fabsl(value) < fabsl(group_values[c])) + group_values[c] = value; + break; + case GROUP_MAX: - if(unlikely(fabsl(value) > fabsl(group_values[c]))) + if(unlikely(isnan(group_values[c])) || + fabsl(value) > fabsl(group_values[c])) group_values[c] = value; break; default: case GROUP_SUM: case GROUP_AVERAGE: + case GROUP_UNDEFINED: group_values[c] += value; break; @@ -1487,23 +1704,39 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g if(unlikely(group_counts[c] == 0)) { cn[c] = 0.0; co[c] |= RRDR_EMPTY; - } - else if(unlikely(group_method == GROUP_AVERAGE)) { - // GROUP_AVERAGE - cn[c] = group_values[c] / group_counts[c]; + group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0; } else { - // GROUP_SUM - // GROUP_MAX - // GROUP_INCREMENTAL_SUM - cn[c] = group_values[c]; - } + switch(group_method) { + case GROUP_MIN: + case GROUP_MAX: + if(unlikely(isnan(group_values[c]))) + cn[c] = 0; + else { + cn[c] = group_values[c]; + group_values[c] = NAN; + } + break; + + case GROUP_SUM: + case GROUP_INCREMENTAL_SUM: + cn[c] = group_values[c]; + group_values[c] = 0; + break; + + default: + case GROUP_AVERAGE: + case GROUP_UNDEFINED: + cn[c] = group_values[c] / group_counts[c]; + group_values[c] = 0; + break; + } - if(cn[c] < r->min) r->min = cn[c]; - if(cn[c] > r->max) r->max = cn[c]; + if(cn[c] < r->min) r->min = cn[c]; + if(cn[c] > r->max) r->max = cn[c]; + } - // reset them for the next loop - group_values[c] = 0; + // reset for the next loop group_counts[c] = 0; group_options[c] = 0; } @@ -1520,7 +1753,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g return r; } -int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, BUFFER *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp, int *value_is_null) +int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *db_after, time_t *db_before, int *value_is_null) { RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED)); if(!r) { @@ -1530,22 +1763,26 @@ int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, BUFFER *dimensions, if(rrdr_rows(r) == 0) { rrdr_free(r); + + if(db_after) *db_after = 0; + if(db_before) *db_before = 0; if(value_is_null) *value_is_null = 1; + return 400; } if(r->result_options & RRDR_RESULT_OPTION_RELATIVE) - wb->options |= WB_CONTENT_NO_CACHEABLE; + buffer_no_cacheable(wb); else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE) - wb->options |= WB_CONTENT_CACHEABLE; + buffer_cacheable(wb); - options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL); + options = rrdr_check_options(r, options, dimensions); if(dimensions) - rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions)); + rrdr_disable_not_selected_dimensions(r, options, dimensions); - if(latest_timestamp) - *latest_timestamp = r->before; + if(db_after) *db_after = r->after; + if(db_before) *db_before = r->before; long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0; *n = rrdr2value(r, i, options, value_is_null); @@ -1563,14 +1800,14 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long } if(r->result_options & RRDR_RESULT_OPTION_RELATIVE) - wb->options |= WB_CONTENT_NO_CACHEABLE; + buffer_no_cacheable(wb); else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE) - wb->options |= WB_CONTENT_CACHEABLE; + buffer_cacheable(wb); options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL); if(dimensions) - rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions)); + rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions)); if(latest_timestamp && rrdr_rows(r) > 0) *latest_timestamp = r->before;