3 void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used)
9 "\t\t\t\"id\": \"%s\",\n"
10 "\t\t\t\"name\": \"%s\",\n"
11 "\t\t\t\"type\": \"%s\",\n"
12 "\t\t\t\"family\": \"%s\",\n"
13 "\t\t\t\"context\": \"%s\",\n"
14 "\t\t\t\"title\": \"%s\",\n"
15 "\t\t\t\"priority\": %ld,\n"
16 "\t\t\t\"enabled\": %s,\n"
17 "\t\t\t\"units\": \"%s\",\n"
18 "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
19 "\t\t\t\"chart_type\": \"%s\",\n"
20 "\t\t\t\"duration\": %ld,\n"
21 "\t\t\t\"first_entry\": %ld,\n"
22 "\t\t\t\"last_entry\": %ld,\n"
23 "\t\t\t\"update_every\": %d,\n"
24 "\t\t\t\"dimensions\": {\n"
32 , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?"true":"false"
35 , rrdset_type_name(st->chart_type)
36 , st->entries * st->update_every
37 , rrdset_first_entry_t(st)
38 , rrdset_last_entry_t(st)
42 unsigned long memory = st->memsize;
44 size_t dimensions = 0;
46 rrddim_foreach_read(rd, st) {
47 if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) continue;
49 memory += rd->memsize;
53 "\t\t\t\t\"%s\": { \"name\": \"%s\" }"
62 if(dimensions_count) *dimensions_count += dimensions;
63 if(memory_used) *memory_used += memory;
65 buffer_strcat(wb, "\n\t\t\t},\n\t\t\t\"green\": ");
66 buffer_rrd_value(wb, st->green);
67 buffer_strcat(wb, ",\n\t\t\t\"red\": ");
68 buffer_rrd_value(wb, st->red);
77 void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
78 rrd_stats_api_v1_chart_with_data(st, wb, NULL, NULL);
81 void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb)
83 size_t c, dimensions = 0, memory = 0, alarms = 0;
86 time_t now = now_realtime_sec();
88 buffer_sprintf(wb, "{\n"
89 "\t\"hostname\": \"%s\""
90 ",\n\t\"version\": \"%s\""
92 ",\n\t\"update_every\": %d"
93 ",\n\t\"history\": %d"
98 , host->rrd_update_every
99 , host->rrd_history_entries
103 rrdhost_rdlock(host);
104 rrdset_foreach_read(st, host) {
105 if(rrdset_is_available_for_viewers(st)) {
106 if(c) buffer_strcat(wb, ",");
107 buffer_strcat(wb, "\n\t\t\"");
108 buffer_strcat(wb, st->id);
109 buffer_strcat(wb, "\": ");
110 rrd_stats_api_v1_chart_with_data(st, wb, &dimensions, &memory);
113 st->last_accessed_time = now;
118 for(rc = host->alarms; rc ; rc = rc->next) {
122 rrdhost_unlock(host);
124 buffer_sprintf(wb, "\n\t}"
125 ",\n\t\"charts_count\": %zu"
126 ",\n\t\"dimensions_count\": %zu"
127 ",\n\t\"alarms_count\": %zu"
128 ",\n\t\"rrd_memory_bytes\": %zu"
129 ",\n\t\"hosts_count\": %zu"
135 , rrd_hosts_available
138 if(unlikely(rrd_hosts_available > 1)) {
141 rrdhost_foreach_read(h) {
144 "\n\t\t\t\"hostname\": \"%s\""
146 , (h != localhost) ? "," : ""
155 "\n\t\t\t\"hostname\": \"%s\""
161 buffer_sprintf(wb, "\n\t]\n}\n");
164 // ----------------------------------------------------------------------------
166 // /api/v1/allmetrics?format=prometheus
168 static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable) {
171 for(n = 0; *s && n < usable ; d++, s++, n++) {
172 register char c = *s;
174 if(unlikely(!isalnum(c))) *d = '_';
182 #define PROMETHEUS_ELEMENT_MAX 256
184 void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb) {
185 rrdhost_rdlock(host);
187 char hostname[PROMETHEUS_ELEMENT_MAX + 1];
188 prometheus_name_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
192 rrdset_foreach_read(st, host) {
193 char chart[PROMETHEUS_ELEMENT_MAX + 1];
194 prometheus_name_copy(chart, st->id, PROMETHEUS_ELEMENT_MAX);
196 buffer_strcat(wb, "\n");
197 if(rrdset_is_available_for_viewers(st)) {
200 // for each dimension
202 rrddim_foreach_read(rd, st) {
203 if(rd->collections_counter) {
204 char dimension[PROMETHEUS_ELEMENT_MAX + 1];
205 prometheus_name_copy(dimension, rd->id, PROMETHEUS_ELEMENT_MAX);
207 // buffer_sprintf(wb, "# HELP %s.%s %s\n", st->id, rd->id, st->units);
209 switch(rd->algorithm) {
210 case RRD_ALGORITHM_INCREMENTAL:
211 case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
212 buffer_sprintf(wb, "# TYPE %s_%s counter\n", chart, dimension);
216 buffer_sprintf(wb, "# TYPE %s_%s gauge\n", chart, dimension);
220 // calculated_number n = (calculated_number)rd->last_collected_value * (calculated_number)(abs(rd->multiplier)) / (calculated_number)(abs(rd->divisor));
221 // buffer_sprintf(wb, "%s.%s " CALCULATED_NUMBER_FORMAT " %llu\n", st->id, rd->id, n, timeval_msec(&rd->last_collected_time));
223 buffer_sprintf(wb, "%s_%s{instance=\"%s\"} " COLLECTED_NUMBER_FORMAT " %llu\n",
224 chart, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time)
234 rrdhost_unlock(host);
237 // ----------------------------------------------------------------------------
239 // /api/v1/allmetrics?format=bash
241 static inline size_t shell_name_copy(char *d, const char *s, size_t usable) {
244 for(n = 0; *s && n < usable ; d++, s++, n++) {
245 register char c = *s;
247 if(unlikely(!isalnum(c))) *d = '_';
248 else *d = (char)toupper(c);
255 #define SHELL_ELEMENT_MAX 100
257 void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
258 rrdhost_rdlock(host);
262 rrdset_foreach_read(st, host) {
263 calculated_number total = 0.0;
264 char chart[SHELL_ELEMENT_MAX + 1];
265 shell_name_copy(chart, st->id, SHELL_ELEMENT_MAX);
267 buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name);
268 if(rrdset_is_available_for_viewers(st)) {
271 // for each dimension
273 rrddim_foreach_read(rd, st) {
274 if(rd->collections_counter) {
275 char dimension[SHELL_ELEMENT_MAX + 1];
276 shell_name_copy(dimension, rd->id, SHELL_ELEMENT_MAX);
278 calculated_number n = rd->last_stored_value;
280 if(isnan(n) || isinf(n))
281 buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, st->units);
283 if(rd->multiplier < 0 || rd->divisor < 0) n = -n;
285 if(!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) total += n;
286 buffer_sprintf(wb, "NETDATA_%s_%s=\"%0.0Lf\" # %s\n", chart, dimension, n, st->units);
291 total = roundl(total);
292 buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"%0.0Lf\" # %s\n", chart, total, st->units);
297 buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n");
300 for(rc = host->alarms; rc ;rc = rc->next) {
301 if(!rc->rrdset) continue;
303 char chart[SHELL_ELEMENT_MAX + 1];
304 shell_name_copy(chart, rc->rrdset->id, SHELL_ELEMENT_MAX);
306 char alarm[SHELL_ELEMENT_MAX + 1];
307 shell_name_copy(alarm, rc->name, SHELL_ELEMENT_MAX);
309 calculated_number n = rc->value;
311 if(isnan(n) || isinf(n))
312 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rc->units);
315 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"%0.0Lf\" # %s\n", chart, alarm, n, rc->units);
318 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status));
321 rrdhost_unlock(host);
324 // ----------------------------------------------------------------------------
326 // RRDR dimension options
327 #define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null)
328 #define RRDR_RESET 0x02 // the dimension contains / the value is reset
329 #define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
330 #define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
331 #define RRDR_SELECTED 0x10 // the dimension is selected
333 // RRDR result options
334 #define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
335 #define RRDR_RESULT_OPTION_RELATIVE 0x00000002
337 typedef struct rrdresult {
338 RRDSET *st; // the chart this result refers to
340 uint32_t result_options; // RRDR_RESULT_OPTION_*
342 int d; // the number of dimensions
343 long n; // the number of values in the arrays
344 long rows; // the number of rows used
346 uint8_t *od; // the options for the dimensions
348 time_t *t; // array of n timestamps
349 calculated_number *v; // array n x d values
350 uint8_t *o; // array n x d options
352 long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
354 long group; // how many collected values were grouped for each row
355 int update_every; // what is the suggested update frequency in seconds
357 calculated_number min;
358 calculated_number max;
363 int has_st_lock; // if st is read locked by us
366 #define rrdr_rows(r) ((r)->rows)
369 static void rrdr_dump(RRDR *r)
374 fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
376 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
377 fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
380 , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
381 , (r->od[c] & RRDR_RESET)?"RESET ":""
382 , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
383 , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
388 fprintf(stderr, "RRDR does not have any values in it.\n");
392 fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
394 // for each line in the array
395 for(i = 0; i < r->rows ;i++) {
396 calculated_number *cn = &r->v[ i * r->d ];
397 uint8_t *co = &r->o[ i * r->d ];
399 // print the id and the timestamp of the line
400 fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
402 // for each dimension
403 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
404 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
405 if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
407 if(co[c] & RRDR_EMPTY)
408 fprintf(stderr, "null ");
410 fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
412 , (co[c] & RRDR_EMPTY)?"E":" "
413 , (co[c] & RRDR_RESET)?"R":" "
414 , (co[c] & RRDR_HIDDEN)?"H":" "
415 , (co[c] & RRDR_NONZERO)?"N":" "
419 fprintf(stderr, "\n");
424 void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) {
425 rrdset_check_rdlock(r->st);
427 if(unlikely(!dims || !*dims)) return;
429 char b[strlen(dims) + 1];
433 long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
436 // disable all of them
437 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
438 r->od[c] |= RRDR_HIDDEN;
440 while(o && *o && (tok = mystrsep(&o, ",|"))) {
443 uint32_t hash = simple_hash(tok);
445 // find it and enable it
446 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
447 if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || (hash == d->hash_name && !strcmp(d->name, tok)))) {
449 if(likely(r->od[c] & RRDR_HIDDEN)) {
450 r->od[c] |= RRDR_SELECTED;
451 r->od[c] &= ~RRDR_HIDDEN;
455 // since the user needs this dimension
456 // make it appear as NONZERO, to return it
457 // even if the dimension has only zeros
458 // unless option non_zero is set
459 if(likely(!(options & RRDR_OPTION_NONZERO)))
460 r->od[c] |= RRDR_NONZERO;
462 // count the visible dimensions
463 if(likely(r->od[c] & RRDR_NONZERO))
464 dims_not_hidden_not_zero++;
469 // check if all dimensions are hidden
470 if(unlikely(!dims_not_hidden_not_zero && dims_selected)) {
471 // there are a few selected dimensions
472 // but they are all zero
473 // enable the selected ones
474 // to avoid returning an empty chart
475 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
476 if(unlikely(r->od[c] & RRDR_SELECTED))
477 r->od[c] |= RRDR_NONZERO;
481 void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
484 case DATASOURCE_JSON:
485 buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
488 case DATASOURCE_DATATABLE_JSON:
489 buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
492 case DATASOURCE_DATATABLE_JSONP:
493 buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
496 case DATASOURCE_JSONP:
497 buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
501 buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
505 buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
509 buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
512 case DATASOURCE_HTML:
513 buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
516 case DATASOURCE_JS_ARRAY:
517 buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
520 case DATASOURCE_SSV_COMMA:
521 buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
525 buffer_strcat(wb, "unknown");
530 uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
532 rrdset_check_rdlock(r->st);
536 if(options & RRDR_OPTION_NONZERO) {
539 // commented due to #1514
541 //if(dims && *dims) {
542 // the caller wants specific dimensions
543 // disable NONZERO option
544 // to make sure we don't accidentally prevent
545 // the specific dimensions from being returned
549 // find how many dimensions are not zero
552 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
553 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
554 if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
559 // if with nonzero we get i = 0 (no dimensions will be returned)
560 // disable nonzero to show all dimensions
561 if(!i) options &= ~RRDR_OPTION_NONZERO;
567 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
569 rrdset_check_rdlock(r->st);
571 long rows = rrdr_rows(r);
575 //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
576 char kq[2] = "", // key quote
577 sq[2] = ""; // string quote
579 if( options & RRDR_OPTION_GOOGLE_JSON ) {
588 buffer_sprintf(wb, "{\n"
591 " %sname%s: %s%s%s,\n"
592 " %sview_update_every%s: %d,\n"
593 " %supdate_every%s: %d,\n"
594 " %sfirst_entry%s: %u,\n"
595 " %slast_entry%s: %u,\n"
598 " %sdimension_names%s: ["
600 , kq, kq, sq, r->st->id, sq
601 , kq, kq, sq, r->st->name, sq
602 , kq, kq, r->update_every
603 , kq, kq, r->st->update_every
604 , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
605 , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
606 , kq, kq, (uint32_t)r->before
607 , kq, kq, (uint32_t)r->after
610 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
611 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
612 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
614 if(i) buffer_strcat(wb, ", ");
615 buffer_strcat(wb, sq);
616 buffer_strcat(wb, rd->name);
617 buffer_strcat(wb, sq);
621 #ifdef NETDATA_INTERNAL_CHECKS
622 error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
625 buffer_strcat(wb, sq);
626 buffer_strcat(wb, "no data");
627 buffer_strcat(wb, sq);
630 buffer_sprintf(wb, "],\n"
631 " %sdimension_ids%s: ["
634 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
635 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
636 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
638 if(i) buffer_strcat(wb, ", ");
639 buffer_strcat(wb, sq);
640 buffer_strcat(wb, rd->id);
641 buffer_strcat(wb, sq);
646 buffer_strcat(wb, sq);
647 buffer_strcat(wb, "no data");
648 buffer_strcat(wb, sq);
651 buffer_sprintf(wb, "],\n"
652 " %slatest_values%s: ["
655 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
656 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
657 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
659 if(i) buffer_strcat(wb, ", ");
662 storage_number n = rd->values[rrdset_last_slot(r->st)];
664 if(!does_storage_number_exist(n))
665 buffer_strcat(wb, "null");
667 buffer_rrd_value(wb, unpack_storage_number(n));
671 buffer_strcat(wb, "null");
674 buffer_sprintf(wb, "],\n"
675 " %sview_latest_values%s: ["
680 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
681 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
682 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
684 if(i) buffer_strcat(wb, ", ");
687 calculated_number *cn = &r->v[ (0) * r->d ];
688 uint8_t *co = &r->o[ (0) * r->d ];
690 if(co[c] & RRDR_EMPTY)
691 buffer_strcat(wb, "null");
693 buffer_rrd_value(wb, cn[c]);
698 buffer_strcat(wb, "null");
701 buffer_sprintf(wb, "],\n"
702 " %sdimensions%s: %ld,\n"
703 " %spoints%s: %ld,\n"
710 rrdr_buffer_print_format(wb, format);
712 buffer_sprintf(wb, "%s,\n"
718 if(string_value) buffer_strcat(wb, sq);
719 //info("JSONWRAPPER(): %s: END", r->st->id);
722 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
726 char kq[2] = "", // key quote
727 sq[2] = ""; // string quote
729 if( options & RRDR_OPTION_GOOGLE_JSON ) {
738 if(string_value) buffer_strcat(wb, sq);
740 buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
741 buffer_rrd_value(wb, r->min);
742 buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
743 buffer_rrd_value(wb, r->max);
744 buffer_strcat(wb, "\n}\n");
747 #define JSON_DATES_JS 1
748 #define JSON_DATES_TIMESTAMP 2
750 static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
752 rrdset_check_rdlock(r->st);
754 //info("RRD2JSON(): %s: BEGIN", r->st->id);
755 int row_annotations = 0, dates, dates_with_new = 0;
756 char kq[2] = "", // key quote
757 sq[2] = "", // string quote
758 pre_label[101] = "", // before each label
759 post_label[101] = "", // after each label
760 pre_date[101] = "", // the beginning of line, to the date
761 post_date[101] = "", // closing the date
762 pre_value[101] = "", // before each value
763 post_value[101] = "", // after each value
764 post_line[101] = "", // at the end of each row
765 normal_annotation[201] = "", // default row annotation
766 overflow_annotation[201] = "", // overflow row annotation
767 data_begin[101] = "", // between labels and values
768 finish[101] = ""; // at the end of everything
771 dates = JSON_DATES_JS;
772 if( options & RRDR_OPTION_GOOGLE_JSON ) {
781 snprintfz(pre_date, 100, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
782 snprintfz(post_date, 100, "%s}", sq);
783 snprintfz(pre_label, 100, ",\n {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
784 snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
785 snprintfz(pre_value, 100, ",{%sv%s:", kq, kq);
786 strcpy(post_value, "}");
787 strcpy(post_line, "]}");
788 snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq);
789 strcpy(finish, "\n ]\n}");
791 snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
792 snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
794 buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
795 buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
796 buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
797 buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
799 // remove the valueobjects flag
800 // google wants its own keys
801 if(options & RRDR_OPTION_OBJECTSROWS)
802 options &= ~RRDR_OPTION_OBJECTSROWS;
807 if(options & RRDR_OPTION_GOOGLE_JSON) {
808 dates = JSON_DATES_JS;
812 dates = JSON_DATES_TIMESTAMP;
815 if( options & RRDR_OPTION_OBJECTSROWS )
816 strcpy(pre_date, " { ");
818 strcpy(pre_date, " [ ");
819 strcpy(pre_label, ", \"");
820 strcpy(post_label, "\"");
821 strcpy(pre_value, ", ");
822 if( options & RRDR_OPTION_OBJECTSROWS )
823 strcpy(post_line, "}");
825 strcpy(post_line, "]");
826 snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
827 strcpy(finish, "\n ]\n}");
829 buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
830 buffer_sprintf(wb, "%stime%s", sq, sq);
833 // -------------------------------------------------------------------------
834 // print the JSON header
839 // print the header lines
840 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
841 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
842 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
844 buffer_strcat(wb, pre_label);
845 buffer_strcat(wb, rd->name);
846 buffer_strcat(wb, post_label);
850 buffer_strcat(wb, pre_label);
851 buffer_strcat(wb, "no data");
852 buffer_strcat(wb, post_label);
855 // print the begin of row data
856 buffer_strcat(wb, data_begin);
858 // if all dimensions are hidden, print a null
860 buffer_strcat(wb, finish);
864 long start = 0, end = rrdr_rows(r), step = 1;
865 if((options & RRDR_OPTION_REVERSED)) {
866 start = rrdr_rows(r) - 1;
871 // for each line in the array
872 calculated_number total = 1;
873 for(i = start; i != end ;i += step) {
874 calculated_number *cn = &r->v[ i * r->d ];
875 uint8_t *co = &r->o[ i * r->d ];
877 time_t now = r->t[i];
879 if(dates == JSON_DATES_JS) {
880 // generate the local date time
881 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
882 if(!tm) { error("localtime_r() failed."); continue; }
884 if(likely(i != start)) buffer_strcat(wb, ",\n");
885 buffer_strcat(wb, pre_date);
887 if( options & RRDR_OPTION_OBJECTSROWS )
888 buffer_sprintf(wb, "%stime%s: ", kq, kq);
891 buffer_strcat(wb, "new ");
893 buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
895 buffer_strcat(wb, post_date);
897 if(row_annotations) {
898 // google supports one annotation per row
899 int annotation_found = 0;
900 for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
901 if(co[c] & RRDR_RESET) {
902 buffer_strcat(wb, overflow_annotation);
903 annotation_found = 1;
907 if(!annotation_found)
908 buffer_strcat(wb, normal_annotation);
912 // print the timestamp of the line
913 if(likely(i != start)) buffer_strcat(wb, ",\n");
914 buffer_strcat(wb, pre_date);
916 if( options & RRDR_OPTION_OBJECTSROWS )
917 buffer_sprintf(wb, "%stime%s: ", kq, kq);
919 buffer_rrd_value(wb, (calculated_number)r->t[i]);
921 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
923 buffer_strcat(wb, post_date);
926 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
928 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
929 calculated_number n = cn[c];
931 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
936 // prevent a division by zero
937 if(total == 0) total = 1;
940 // for each dimension
941 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
942 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
943 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
945 calculated_number n = cn[c];
947 buffer_strcat(wb, pre_value);
949 if( options & RRDR_OPTION_OBJECTSROWS )
950 buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
952 if(co[c] & RRDR_EMPTY) {
953 if(options & RRDR_OPTION_NULL2ZERO)
954 buffer_strcat(wb, "0");
956 buffer_strcat(wb, "null");
959 if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
962 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
965 buffer_rrd_value(wb, n);
968 buffer_strcat(wb, post_value);
971 buffer_strcat(wb, post_line);
974 buffer_strcat(wb, finish);
975 //info("RRD2JSON(): %s: END", r->st->id);
978 static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
980 rrdset_check_rdlock(r->st);
982 //info("RRD2CSV(): %s: BEGIN", r->st->id);
986 // print the csv header
987 for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
988 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
989 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
992 buffer_strcat(wb, startline);
993 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
994 buffer_strcat(wb, "time");
995 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
997 buffer_strcat(wb, separator);
998 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
999 buffer_strcat(wb, d->name);
1000 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1003 buffer_strcat(wb, endline);
1006 // no dimensions present
1010 long start = 0, end = rrdr_rows(r), step = 1;
1011 if((options & RRDR_OPTION_REVERSED)) {
1012 start = rrdr_rows(r) - 1;
1017 // for each line in the array
1018 calculated_number total = 1;
1019 for(i = start; i != end ;i += step) {
1020 calculated_number *cn = &r->v[ i * r->d ];
1021 uint8_t *co = &r->o[ i * r->d ];
1023 buffer_strcat(wb, betweenlines);
1024 buffer_strcat(wb, startline);
1026 time_t now = r->t[i];
1028 if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
1029 // print the timestamp of the line
1030 buffer_rrd_value(wb, (calculated_number)now);
1032 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
1035 // generate the local date time
1036 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
1037 if(!tm) { error("localtime() failed."); continue; }
1038 buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
1041 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1043 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1044 calculated_number n = cn[c];
1046 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1051 // prevent a division by zero
1052 if(total == 0) total = 1;
1055 // for each dimension
1056 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1057 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1058 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1060 buffer_strcat(wb, separator);
1062 calculated_number n = cn[c];
1064 if(co[c] & RRDR_EMPTY) {
1065 if(options & RRDR_OPTION_NULL2ZERO)
1066 buffer_strcat(wb, "0");
1068 buffer_strcat(wb, "null");
1071 if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1074 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1075 n = n * 100 / total;
1077 buffer_rrd_value(wb, n);
1081 buffer_strcat(wb, endline);
1083 //info("RRD2CSV(): %s: END", r->st->id);
1086 inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
1087 rrdset_check_rdlock(r->st);
1092 calculated_number *cn = &r->v[ i * r->d ];
1093 uint8_t *co = &r->o[ i * r->d ];
1095 calculated_number sum = 0, min = 0, max = 0, v;
1096 int all_null = 1, init = 1;
1098 calculated_number total = 1;
1099 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1101 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1102 calculated_number n = cn[c];
1104 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1109 // prevent a division by zero
1110 if(total == 0) total = 1;
1113 // for each dimension
1114 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1115 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1116 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1118 calculated_number n = cn[c];
1120 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1123 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1124 n = n * 100 / total;
1126 if(unlikely(init)) {
1138 if(likely(!(co[c] & RRDR_EMPTY))) {
1143 if(n < min) min = n;
1144 if(n > max) max = n;
1147 if(unlikely(all_null)) {
1148 if(likely(all_values_are_null))
1149 *all_values_are_null = 1;
1153 if(likely(all_values_are_null))
1154 *all_values_are_null = 0;
1157 if(options & RRDR_OPTION_MIN2MAX)
1165 static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix)
1167 //info("RRD2SSV(): %s: BEGIN", r->st->id);
1170 buffer_strcat(wb, prefix);
1171 long start = 0, end = rrdr_rows(r), step = 1;
1172 if((options & RRDR_OPTION_REVERSED)) {
1173 start = rrdr_rows(r) - 1;
1178 // for each line in the array
1179 for(i = start; i != end ;i += step) {
1180 int all_values_are_null = 0;
1181 calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
1183 if(likely(i != start)) {
1184 if(r->min > v) r->min = v;
1185 if(r->max < v) r->max = v;
1192 if(likely(i != start))
1193 buffer_strcat(wb, separator);
1195 if(all_values_are_null) {
1196 if(options & RRDR_OPTION_NULL2ZERO)
1197 buffer_strcat(wb, "0");
1199 buffer_strcat(wb, "null");
1202 buffer_rrd_value(wb, v);
1204 buffer_strcat(wb, suffix);
1205 //info("RRD2SSV(): %s: END", r->st->id);
1208 inline static calculated_number *rrdr_line_values(RRDR *r)
1210 return &r->v[ r->c * r->d ];
1213 inline static uint8_t *rrdr_line_options(RRDR *r)
1215 return &r->o[ r->c * r->d ];
1218 inline static int rrdr_line_init(RRDR *r, time_t t)
1222 if(unlikely(r->c >= r->n)) {
1223 error("requested to step above RRDR size for chart %s", r->st->name);
1233 inline static void rrdr_lock_rrdset(RRDR *r) {
1235 error("NULL value given!");
1239 rrdset_rdlock(r->st);
1243 inline static void rrdr_unlock_rrdset(RRDR *r) {
1245 error("NULL value given!");
1249 if(likely(r->has_st_lock)) {
1250 rrdset_unlock(r->st);
1255 inline static void rrdr_free(RRDR *r)
1258 error("NULL value given!");
1262 rrdr_unlock_rrdset(r);
1270 static inline void rrdr_done(RRDR *r)
1276 static RRDR *rrdr_create(RRDSET *st, long n)
1279 error("NULL value given!");
1283 RRDR *r = callocz(1, sizeof(RRDR));
1286 rrdr_lock_rrdset(r);
1289 rrddim_foreach_read(rd, st) r->d++;
1293 r->t = mallocz(n * sizeof(time_t));
1294 r->v = mallocz(n * r->d * sizeof(calculated_number));
1295 r->o = mallocz(n * r->d * sizeof(uint8_t));
1296 r->od = mallocz(r->d * sizeof(uint8_t));
1298 // set the hidden flag on hidden dimensions
1300 for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
1301 if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)))
1302 r->od[c] = RRDR_HIDDEN;
1309 r->update_every = 1;
1314 RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
1316 int debug = rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?1:0;
1317 int absolute_period_requested = -1;
1319 time_t first_entry_t = rrdset_first_entry_t(st);
1320 time_t last_entry_t = rrdset_last_entry_t(st);
1322 if(before == 0 && after == 0) {
1323 // dump the all the data
1324 before = last_entry_t;
1325 after = first_entry_t;
1326 absolute_period_requested = 0;
1329 // allow relative for before (smaller than API_RELATIVE_TIME_MAX)
1330 if(((before < 0)?-before:before) <= API_RELATIVE_TIME_MAX) {
1331 if(abs(before) % st->update_every) {
1332 // make sure it is multiple of st->update_every
1333 if(before < 0) before = before - st->update_every - before % st->update_every;
1334 else before = before + st->update_every - before % st->update_every;
1336 if(before > 0) before = first_entry_t + before;
1337 else before = last_entry_t + before;
1338 absolute_period_requested = 0;
1341 // allow relative for after (smaller than API_RELATIVE_TIME_MAX)
1342 if(((after < 0)?-after:after) <= API_RELATIVE_TIME_MAX) {
1343 if(after == 0) after = -st->update_every;
1344 if(abs(after) % st->update_every) {
1345 // make sure it is multiple of st->update_every
1346 if(after < 0) after = after - st->update_every - after % st->update_every;
1347 else after = after + st->update_every - after % st->update_every;
1349 after = before + after;
1350 absolute_period_requested = 0;
1353 if(absolute_period_requested == -1)
1354 absolute_period_requested = 1;
1356 // make sure they are within our timeframe
1357 if(before > last_entry_t) before = last_entry_t;
1358 if(before < first_entry_t) before = first_entry_t;
1360 if(after > last_entry_t) after = last_entry_t;
1361 if(after < first_entry_t) after = first_entry_t;
1363 // check if they are upside down
1364 if(after > before) {
1365 time_t tmp = before;
1370 // the duration of the chart
1371 time_t duration = before - after;
1372 long available_points = duration / st->update_every;
1374 if(duration <= 0 || available_points <= 0)
1375 return rrdr_create(st, 1);
1377 // check the wanted points
1378 if(points < 0) points = -points;
1379 if(points > available_points) points = available_points;
1380 if(points == 0) points = available_points;
1382 // calculate proper grouping of source data
1383 long group = available_points / points;
1384 if(group <= 0) group = 1;
1386 // round group to the closest integer
1387 if(available_points % points > points / 2) group++;
1389 time_t after_new = (aligned) ? (after - (after % (group * st->update_every))) : after;
1390 time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
1391 long points_new = (before_new - after_new) / st->update_every / group;
1393 // find the starting and ending slots in our round robin db
1394 long start_at_slot = rrdset_time2slot(st, before_new),
1395 stop_at_slot = rrdset_time2slot(st, after_new);
1397 #ifdef NETDATA_INTERNAL_CHECKS
1398 if(after_new < first_entry_t) {
1399 error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
1401 if(after_new > last_entry_t) {
1402 error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
1404 if(before_new < first_entry_t) {
1405 error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
1407 if(before_new > last_entry_t) {
1408 error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
1410 if(start_at_slot < 0 || start_at_slot >= st->entries) {
1411 error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
1413 if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
1414 error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
1416 if(points_new > (before_new - after_new) / group / st->update_every + 1) {
1417 error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
1421 //info("RRD2RRDR(): %s: wanted %ld points, got %ld - group=%ld, wanted duration=%u, got %u - wanted %ld - %ld, got %ld - %ld", st->id, points, points_new, group, before - after, before_new - after_new, after, before, after_new, before_new);
1424 before = before_new;
1425 duration = before - after;
1426 points = points_new;
1429 // before = the end time of the calculation
1430 // after = the start time of the calculation
1431 // duration = the duration of the calculation
1432 // group = the number of source points to aggregate / group together
1433 // method = the method of grouping source points
1434 // points = the number of points to generate
1437 // -------------------------------------------------------------------------
1438 // initialize our result set
1440 RRDR *r = rrdr_create(st, points);
1442 #ifdef NETDATA_INTERNAL_CHECKS
1443 error("Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
1448 #ifdef NETDATA_INTERNAL_CHECKS
1449 error("Returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
1454 if(absolute_period_requested == 1)
1455 r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
1457 r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
1459 // find how many dimensions we have
1460 long dimensions = r->d;
1463 // -------------------------------------------------------------------------
1464 // checks for debugging
1466 if(debug) debug(D_RRD_STATS, "INFO %s first_t: %u, last_t: %u, all_duration: %u, after: %u, before: %u, duration: %u, points: %ld, group: %ld"
1468 , (uint32_t)first_entry_t
1469 , (uint32_t)last_entry_t
1470 , (uint32_t)(last_entry_t - first_entry_t)
1473 , (uint32_t)duration
1479 // -------------------------------------------------------------------------
1480 // temp arrays for keeping values per dimension
1482 calculated_number last_values[dimensions]; // keep the last value of each dimension
1483 calculated_number group_values[dimensions]; // keep sums when grouping
1484 long group_counts[dimensions]; // keep the number of values added to group_values
1485 uint8_t group_options[dimensions];
1486 uint8_t found_non_zero[dimensions];
1492 rrdset_check_rdlock(st);
1493 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1495 group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
1496 group_counts[c] = 0;
1497 group_options[c] = 0;
1498 found_non_zero[c] = 0;
1502 // -------------------------------------------------------------------------
1505 time_t now = rrdset_slot2time(st, start_at_slot),
1506 dt = st->update_every,
1509 if(unlikely(debug)) debug(D_RRD_STATS, "BEGIN %s after_t: %u (stop_at_t: %ld), before_t: %u (start_at_t: %ld), start_t(now): %u, current_entry: %ld, entries: %ld"
1521 r->update_every = (int)group * st->update_every;
1525 //info("RRD2RRDR(): %s: STARTING", st->id);
1527 long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
1528 for(; !stop_now ; now -= dt, slot--, counter++) {
1529 if(unlikely(slot < 0)) slot = st->entries - 1;
1530 if(unlikely(slot == stop_at_slot)) stop_now = counter;
1532 if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
1539 , (group_count + 1 == group)?"PRINT":" - "
1540 , (now >= after && now <= before)?"RANGE":" - "
1543 // make sure we return data in the proper time range
1544 if(unlikely(now > before)) continue;
1545 if(unlikely(now < after)) break;
1547 if(unlikely(group_count == 0)) {
1548 group_start_t = now;
1552 if(unlikely(group_count == group)) {
1553 if(unlikely(added >= points)) break;
1557 // do the calculations
1558 for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1559 storage_number n = rd->values[slot];
1560 if(unlikely(!does_storage_number_exist(n))) continue;
1564 calculated_number value = unpack_storage_number(n);
1565 if(likely(value != 0.0)) {
1566 group_options[c] |= RRDR_NONZERO;
1567 found_non_zero[c] = 1;
1570 if(unlikely(did_storage_number_reset(n)))
1571 group_options[c] |= RRDR_RESET;
1573 switch(group_method) {
1575 if(unlikely(isnan(group_values[c])) ||
1576 fabsl(value) < fabsl(group_values[c]))
1577 group_values[c] = value;
1581 if(unlikely(isnan(group_values[c])) ||
1582 fabsl(value) > fabsl(group_values[c]))
1583 group_values[c] = value;
1589 case GROUP_UNDEFINED:
1590 group_values[c] += value;
1593 case GROUP_INCREMENTAL_SUM:
1594 if(unlikely(slot == start_at_slot))
1595 last_values[c] = value;
1597 group_values[c] += last_values[c] - value;
1598 last_values[c] = value;
1604 if(unlikely(add_this)) {
1605 if(unlikely(!rrdr_line_init(r, group_start_t))) break;
1609 calculated_number *cn = rrdr_line_values(r);
1610 uint8_t *co = rrdr_line_options(r);
1612 for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1614 // update the dimension options
1615 if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
1617 // store the specific point options
1618 co[c] = group_options[c];
1621 if(unlikely(group_counts[c] == 0)) {
1623 co[c] |= RRDR_EMPTY;
1624 group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
1627 switch(group_method) {
1630 if(unlikely(isnan(group_values[c])))
1633 cn[c] = group_values[c];
1634 group_values[c] = NAN;
1639 case GROUP_INCREMENTAL_SUM:
1640 cn[c] = group_values[c];
1641 group_values[c] = 0;
1646 case GROUP_UNDEFINED:
1647 cn[c] = group_values[c] / group_counts[c];
1648 group_values[c] = 0;
1652 if(cn[c] < r->min) r->min = cn[c];
1653 if(cn[c] > r->max) r->max = cn[c];
1656 // reset for the next loop
1657 group_counts[c] = 0;
1658 group_options[c] = 0;
1668 //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
1669 //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
1673 int rrdset2value_api_v1(
1676 , calculated_number *n
1677 , const char *dimensions
1685 , int *value_is_null
1687 RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1689 if(value_is_null) *value_is_null = 1;
1693 if(rrdr_rows(r) == 0) {
1696 if(db_after) *db_after = 0;
1697 if(db_before) *db_before = 0;
1698 if(value_is_null) *value_is_null = 1;
1703 if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1704 buffer_no_cacheable(wb);
1705 else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1706 buffer_cacheable(wb);
1708 options = rrdr_check_options(r, options, dimensions);
1711 rrdr_disable_not_selected_dimensions(r, options, dimensions);
1713 if(db_after) *db_after = r->after;
1714 if(db_before) *db_before = r->before;
1716 long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
1717 *n = rrdr2value(r, i, options, value_is_null);
1723 int rrdset2anything_api_v1(
1726 , BUFFER *dimensions
1733 , time_t *latest_timestamp
1735 st->last_accessed_time = now_realtime_sec();
1737 RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1739 buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
1743 if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1744 buffer_no_cacheable(wb);
1745 else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1746 buffer_cacheable(wb);
1748 options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1751 rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions));
1753 if(latest_timestamp && rrdr_rows(r) > 0)
1754 *latest_timestamp = r->before;
1757 case DATASOURCE_SSV:
1758 if(options & RRDR_OPTION_JSON_WRAP) {
1759 wb->contenttype = CT_APPLICATION_JSON;
1760 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1761 rrdr2ssv(r, wb, options, "", " ", "");
1762 rrdr_json_wrapper_end(r, wb, format, options, 1);
1765 wb->contenttype = CT_TEXT_PLAIN;
1766 rrdr2ssv(r, wb, options, "", " ", "");
1770 case DATASOURCE_SSV_COMMA:
1771 if(options & RRDR_OPTION_JSON_WRAP) {
1772 wb->contenttype = CT_APPLICATION_JSON;
1773 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1774 rrdr2ssv(r, wb, options, "", ",", "");
1775 rrdr_json_wrapper_end(r, wb, format, options, 1);
1778 wb->contenttype = CT_TEXT_PLAIN;
1779 rrdr2ssv(r, wb, options, "", ",", "");
1783 case DATASOURCE_JS_ARRAY:
1784 if(options & RRDR_OPTION_JSON_WRAP) {
1785 wb->contenttype = CT_APPLICATION_JSON;
1786 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1787 rrdr2ssv(r, wb, options, "[", ",", "]");
1788 rrdr_json_wrapper_end(r, wb, format, options, 0);
1791 wb->contenttype = CT_APPLICATION_JSON;
1792 rrdr2ssv(r, wb, options, "[", ",", "]");
1796 case DATASOURCE_CSV:
1797 if(options & RRDR_OPTION_JSON_WRAP) {
1798 wb->contenttype = CT_APPLICATION_JSON;
1799 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1800 rrdr2csv(r, wb, options, "", ",", "\\n", "");
1801 rrdr_json_wrapper_end(r, wb, format, options, 1);
1804 wb->contenttype = CT_TEXT_PLAIN;
1805 rrdr2csv(r, wb, options, "", ",", "\r\n", "");
1809 case DATASOURCE_CSV_JSON_ARRAY:
1810 wb->contenttype = CT_APPLICATION_JSON;
1811 if(options & RRDR_OPTION_JSON_WRAP) {
1812 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1813 buffer_strcat(wb, "[\n");
1814 rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1815 buffer_strcat(wb, "\n]");
1816 rrdr_json_wrapper_end(r, wb, format, options, 0);
1819 wb->contenttype = CT_TEXT_PLAIN;
1820 buffer_strcat(wb, "[\n");
1821 rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1822 buffer_strcat(wb, "\n]");
1826 case DATASOURCE_TSV:
1827 if(options & RRDR_OPTION_JSON_WRAP) {
1828 wb->contenttype = CT_APPLICATION_JSON;
1829 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1830 rrdr2csv(r, wb, options, "", "\t", "\\n", "");
1831 rrdr_json_wrapper_end(r, wb, format, options, 1);
1834 wb->contenttype = CT_TEXT_PLAIN;
1835 rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
1839 case DATASOURCE_HTML:
1840 if(options & RRDR_OPTION_JSON_WRAP) {
1841 wb->contenttype = CT_APPLICATION_JSON;
1842 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1843 buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
1844 rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
1845 buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
1846 rrdr_json_wrapper_end(r, wb, format, options, 1);
1849 wb->contenttype = CT_TEXT_HTML;
1850 buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
1851 rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
1852 buffer_strcat(wb, "</table>\n</center>\n</html>\n");
1856 case DATASOURCE_DATATABLE_JSONP:
1857 wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1859 if(options & RRDR_OPTION_JSON_WRAP)
1860 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1862 rrdr2json(r, wb, options, 1);
1864 if(options & RRDR_OPTION_JSON_WRAP)
1865 rrdr_json_wrapper_end(r, wb, format, options, 0);
1868 case DATASOURCE_DATATABLE_JSON:
1869 wb->contenttype = CT_APPLICATION_JSON;
1871 if(options & RRDR_OPTION_JSON_WRAP)
1872 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1874 rrdr2json(r, wb, options, 1);
1876 if(options & RRDR_OPTION_JSON_WRAP)
1877 rrdr_json_wrapper_end(r, wb, format, options, 0);
1880 case DATASOURCE_JSONP:
1881 wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1882 if(options & RRDR_OPTION_JSON_WRAP)
1883 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1885 rrdr2json(r, wb, options, 0);
1887 if(options & RRDR_OPTION_JSON_WRAP)
1888 rrdr_json_wrapper_end(r, wb, format, options, 0);
1891 case DATASOURCE_JSON:
1893 wb->contenttype = CT_APPLICATION_JSON;
1895 if(options & RRDR_OPTION_JSON_WRAP)
1896 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1898 rrdr2json(r, wb, options, 0);
1900 if(options & RRDR_OPTION_JSON_WRAP)
1901 rrdr_json_wrapper_end(r, wb, format, options, 0);