summaryrefslogtreecommitdiffstats
path: root/src/rrd2json.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rrd2json.c')
-rw-r--r--src/rrd2json.c243
1 files changed, 225 insertions, 18 deletions
diff --git a/src/rrd2json.c b/src/rrd2json.c
index 474b5915d..067475006 100644
--- a/src/rrd2json.c
+++ b/src/rrd2json.c
@@ -1,6 +1,6 @@
#include "common.h"
-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);
@@ -41,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;
@@ -51,14 +51,17 @@ 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\": ");
@@ -71,9 +74,13 @@ void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb)
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"
@@ -93,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_strcat(wb, "\n\t}\n}\n");
+ 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
+
+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);
@@ -434,17 +624,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;
@@ -453,7 +647,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
@@ -1158,7 +1352,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;
@@ -1209,19 +1403,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 (smaller than 3 years)
- if(((before < 0)?-before:before) <= (3 * 365 * 86400)) {
- 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) <= (3 * 365 * 86400)) {
+ // 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;
}