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\": %ld"
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 void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) {
327 rrdhost_rdlock(host);
329 buffer_strcat(wb, "{");
331 size_t chart_counter = 0;
332 size_t dimension_counter = 0;
336 rrdset_foreach_read(st, host) {
337 if(rrdset_is_available_for_viewers(st)) {
340 buffer_sprintf(wb, "%s\n"
342 "\t\t\"name\":\"%s\",\n"
343 "\t\t\"context\":\"%s\",\n"
344 "\t\t\"units\":\"%s\",\n"
345 "\t\t\"last_updated\": %ld,\n"
346 "\t\t\"dimensions\": {"
347 , chart_counter?",":""
352 , rrdset_last_entry_t(st)
356 dimension_counter = 0;
358 // for each dimension
360 rrddim_foreach_read(rd, st) {
361 if(rd->collections_counter) {
363 buffer_sprintf(wb, "%s\n"
365 "\t\t\t\t\"name\": \"%s\",\n"
366 "\t\t\t\t\"value\": "
367 , dimension_counter?",":""
372 if(isnan(rd->last_stored_value))
373 buffer_strcat(wb, "null");
375 buffer_sprintf(wb, CALCULATED_NUMBER_FORMAT, rd->last_stored_value);
377 buffer_strcat(wb, "\n\t\t\t}");
383 buffer_strcat(wb, "\n\t\t}\n\t}");
388 buffer_strcat(wb, "\n}");
389 rrdhost_unlock(host);
392 // ----------------------------------------------------------------------------
394 // RRDR dimension options
395 #define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null)
396 #define RRDR_RESET 0x02 // the dimension contains / the value is reset
397 #define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
398 #define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
399 #define RRDR_SELECTED 0x10 // the dimension is selected
401 // RRDR result options
402 #define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
403 #define RRDR_RESULT_OPTION_RELATIVE 0x00000002
405 typedef struct rrdresult {
406 RRDSET *st; // the chart this result refers to
408 uint32_t result_options; // RRDR_RESULT_OPTION_*
410 int d; // the number of dimensions
411 long n; // the number of values in the arrays
412 long rows; // the number of rows used
414 uint8_t *od; // the options for the dimensions
416 time_t *t; // array of n timestamps
417 calculated_number *v; // array n x d values
418 uint8_t *o; // array n x d options
420 long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
422 long group; // how many collected values were grouped for each row
423 int update_every; // what is the suggested update frequency in seconds
425 calculated_number min;
426 calculated_number max;
431 int has_st_lock; // if st is read locked by us
434 #define rrdr_rows(r) ((r)->rows)
437 static void rrdr_dump(RRDR *r)
442 fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
444 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
445 fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
448 , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
449 , (r->od[c] & RRDR_RESET)?"RESET ":""
450 , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
451 , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
456 fprintf(stderr, "RRDR does not have any values in it.\n");
460 fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
462 // for each line in the array
463 for(i = 0; i < r->rows ;i++) {
464 calculated_number *cn = &r->v[ i * r->d ];
465 uint8_t *co = &r->o[ i * r->d ];
467 // print the id and the timestamp of the line
468 fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
470 // for each dimension
471 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
472 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
473 if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
475 if(co[c] & RRDR_EMPTY)
476 fprintf(stderr, "null ");
478 fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
480 , (co[c] & RRDR_EMPTY)?"E":" "
481 , (co[c] & RRDR_RESET)?"R":" "
482 , (co[c] & RRDR_HIDDEN)?"H":" "
483 , (co[c] & RRDR_NONZERO)?"N":" "
487 fprintf(stderr, "\n");
492 void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) {
493 rrdset_check_rdlock(r->st);
495 if(unlikely(!dims || !*dims)) return;
497 char b[strlen(dims) + 1];
501 long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
504 // disable all of them
505 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
506 r->od[c] |= RRDR_HIDDEN;
508 while(o && *o && (tok = mystrsep(&o, ",|"))) {
511 uint32_t hash = simple_hash(tok);
513 // find it and enable it
514 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
515 if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || (hash == d->hash_name && !strcmp(d->name, tok)))) {
517 if(likely(r->od[c] & RRDR_HIDDEN)) {
518 r->od[c] |= RRDR_SELECTED;
519 r->od[c] &= ~RRDR_HIDDEN;
523 // since the user needs this dimension
524 // make it appear as NONZERO, to return it
525 // even if the dimension has only zeros
526 // unless option non_zero is set
527 if(likely(!(options & RRDR_OPTION_NONZERO)))
528 r->od[c] |= RRDR_NONZERO;
530 // count the visible dimensions
531 if(likely(r->od[c] & RRDR_NONZERO))
532 dims_not_hidden_not_zero++;
537 // check if all dimensions are hidden
538 if(unlikely(!dims_not_hidden_not_zero && dims_selected)) {
539 // there are a few selected dimensions
540 // but they are all zero
541 // enable the selected ones
542 // to avoid returning an empty chart
543 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
544 if(unlikely(r->od[c] & RRDR_SELECTED))
545 r->od[c] |= RRDR_NONZERO;
549 void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
552 case DATASOURCE_JSON:
553 buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
556 case DATASOURCE_DATATABLE_JSON:
557 buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
560 case DATASOURCE_DATATABLE_JSONP:
561 buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
564 case DATASOURCE_JSONP:
565 buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
569 buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
573 buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
577 buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
580 case DATASOURCE_HTML:
581 buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
584 case DATASOURCE_JS_ARRAY:
585 buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
588 case DATASOURCE_SSV_COMMA:
589 buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
593 buffer_strcat(wb, "unknown");
598 uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
600 rrdset_check_rdlock(r->st);
604 if(options & RRDR_OPTION_NONZERO) {
607 // commented due to #1514
609 //if(dims && *dims) {
610 // the caller wants specific dimensions
611 // disable NONZERO option
612 // to make sure we don't accidentally prevent
613 // the specific dimensions from being returned
617 // find how many dimensions are not zero
620 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
621 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
622 if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
627 // if with nonzero we get i = 0 (no dimensions will be returned)
628 // disable nonzero to show all dimensions
629 if(!i) options &= ~RRDR_OPTION_NONZERO;
635 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
637 rrdset_check_rdlock(r->st);
639 long rows = rrdr_rows(r);
643 //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
644 char kq[2] = "", // key quote
645 sq[2] = ""; // string quote
647 if( options & RRDR_OPTION_GOOGLE_JSON ) {
656 buffer_sprintf(wb, "{\n"
659 " %sname%s: %s%s%s,\n"
660 " %sview_update_every%s: %d,\n"
661 " %supdate_every%s: %d,\n"
662 " %sfirst_entry%s: %u,\n"
663 " %slast_entry%s: %u,\n"
666 " %sdimension_names%s: ["
668 , kq, kq, sq, r->st->id, sq
669 , kq, kq, sq, r->st->name, sq
670 , kq, kq, r->update_every
671 , kq, kq, r->st->update_every
672 , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
673 , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
674 , kq, kq, (uint32_t)r->before
675 , kq, kq, (uint32_t)r->after
678 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
679 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
680 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
682 if(i) buffer_strcat(wb, ", ");
683 buffer_strcat(wb, sq);
684 buffer_strcat(wb, rd->name);
685 buffer_strcat(wb, sq);
689 #ifdef NETDATA_INTERNAL_CHECKS
690 error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
693 buffer_strcat(wb, sq);
694 buffer_strcat(wb, "no data");
695 buffer_strcat(wb, sq);
698 buffer_sprintf(wb, "],\n"
699 " %sdimension_ids%s: ["
702 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
703 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
704 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
706 if(i) buffer_strcat(wb, ", ");
707 buffer_strcat(wb, sq);
708 buffer_strcat(wb, rd->id);
709 buffer_strcat(wb, sq);
714 buffer_strcat(wb, sq);
715 buffer_strcat(wb, "no data");
716 buffer_strcat(wb, sq);
719 buffer_sprintf(wb, "],\n"
720 " %slatest_values%s: ["
723 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
724 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
725 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
727 if(i) buffer_strcat(wb, ", ");
730 storage_number n = rd->values[rrdset_last_slot(r->st)];
732 if(!does_storage_number_exist(n))
733 buffer_strcat(wb, "null");
735 buffer_rrd_value(wb, unpack_storage_number(n));
739 buffer_strcat(wb, "null");
742 buffer_sprintf(wb, "],\n"
743 " %sview_latest_values%s: ["
748 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
749 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
750 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
752 if(i) buffer_strcat(wb, ", ");
755 calculated_number *cn = &r->v[ (0) * r->d ];
756 uint8_t *co = &r->o[ (0) * r->d ];
758 if(co[c] & RRDR_EMPTY)
759 buffer_strcat(wb, "null");
761 buffer_rrd_value(wb, cn[c]);
766 buffer_strcat(wb, "null");
769 buffer_sprintf(wb, "],\n"
770 " %sdimensions%s: %ld,\n"
771 " %spoints%s: %ld,\n"
778 rrdr_buffer_print_format(wb, format);
780 buffer_sprintf(wb, "%s,\n"
786 if(string_value) buffer_strcat(wb, sq);
787 //info("JSONWRAPPER(): %s: END", r->st->id);
790 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
794 char kq[2] = "", // key quote
795 sq[2] = ""; // string quote
797 if( options & RRDR_OPTION_GOOGLE_JSON ) {
806 if(string_value) buffer_strcat(wb, sq);
808 buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
809 buffer_rrd_value(wb, r->min);
810 buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
811 buffer_rrd_value(wb, r->max);
812 buffer_strcat(wb, "\n}\n");
815 #define JSON_DATES_JS 1
816 #define JSON_DATES_TIMESTAMP 2
818 static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
820 rrdset_check_rdlock(r->st);
822 //info("RRD2JSON(): %s: BEGIN", r->st->id);
823 int row_annotations = 0, dates, dates_with_new = 0;
824 char kq[2] = "", // key quote
825 sq[2] = "", // string quote
826 pre_label[101] = "", // before each label
827 post_label[101] = "", // after each label
828 pre_date[101] = "", // the beginning of line, to the date
829 post_date[101] = "", // closing the date
830 pre_value[101] = "", // before each value
831 post_value[101] = "", // after each value
832 post_line[101] = "", // at the end of each row
833 normal_annotation[201] = "", // default row annotation
834 overflow_annotation[201] = "", // overflow row annotation
835 data_begin[101] = "", // between labels and values
836 finish[101] = ""; // at the end of everything
839 dates = JSON_DATES_JS;
840 if( options & RRDR_OPTION_GOOGLE_JSON ) {
849 snprintfz(pre_date, 100, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
850 snprintfz(post_date, 100, "%s}", sq);
851 snprintfz(pre_label, 100, ",\n {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
852 snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
853 snprintfz(pre_value, 100, ",{%sv%s:", kq, kq);
854 strcpy(post_value, "}");
855 strcpy(post_line, "]}");
856 snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq);
857 strcpy(finish, "\n ]\n}");
859 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);
860 snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
862 buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
863 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);
864 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);
865 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);
867 // remove the valueobjects flag
868 // google wants its own keys
869 if(options & RRDR_OPTION_OBJECTSROWS)
870 options &= ~RRDR_OPTION_OBJECTSROWS;
875 if(options & RRDR_OPTION_GOOGLE_JSON) {
876 dates = JSON_DATES_JS;
880 dates = JSON_DATES_TIMESTAMP;
883 if( options & RRDR_OPTION_OBJECTSROWS )
884 strcpy(pre_date, " { ");
886 strcpy(pre_date, " [ ");
887 strcpy(pre_label, ", \"");
888 strcpy(post_label, "\"");
889 strcpy(pre_value, ", ");
890 if( options & RRDR_OPTION_OBJECTSROWS )
891 strcpy(post_line, "}");
893 strcpy(post_line, "]");
894 snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
895 strcpy(finish, "\n ]\n}");
897 buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
898 buffer_sprintf(wb, "%stime%s", sq, sq);
901 // -------------------------------------------------------------------------
902 // print the JSON header
907 // print the header lines
908 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
909 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
910 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
912 buffer_strcat(wb, pre_label);
913 buffer_strcat(wb, rd->name);
914 buffer_strcat(wb, post_label);
918 buffer_strcat(wb, pre_label);
919 buffer_strcat(wb, "no data");
920 buffer_strcat(wb, post_label);
923 // print the begin of row data
924 buffer_strcat(wb, data_begin);
926 // if all dimensions are hidden, print a null
928 buffer_strcat(wb, finish);
932 long start = 0, end = rrdr_rows(r), step = 1;
933 if((options & RRDR_OPTION_REVERSED)) {
934 start = rrdr_rows(r) - 1;
939 // for each line in the array
940 calculated_number total = 1;
941 for(i = start; i != end ;i += step) {
942 calculated_number *cn = &r->v[ i * r->d ];
943 uint8_t *co = &r->o[ i * r->d ];
945 time_t now = r->t[i];
947 if(dates == JSON_DATES_JS) {
948 // generate the local date time
949 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
950 if(!tm) { error("localtime_r() failed."); continue; }
952 if(likely(i != start)) buffer_strcat(wb, ",\n");
953 buffer_strcat(wb, pre_date);
955 if( options & RRDR_OPTION_OBJECTSROWS )
956 buffer_sprintf(wb, "%stime%s: ", kq, kq);
959 buffer_strcat(wb, "new ");
961 buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
963 buffer_strcat(wb, post_date);
965 if(row_annotations) {
966 // google supports one annotation per row
967 int annotation_found = 0;
968 for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
969 if(co[c] & RRDR_RESET) {
970 buffer_strcat(wb, overflow_annotation);
971 annotation_found = 1;
975 if(!annotation_found)
976 buffer_strcat(wb, normal_annotation);
980 // print the timestamp of the line
981 if(likely(i != start)) buffer_strcat(wb, ",\n");
982 buffer_strcat(wb, pre_date);
984 if( options & RRDR_OPTION_OBJECTSROWS )
985 buffer_sprintf(wb, "%stime%s: ", kq, kq);
987 buffer_rrd_value(wb, (calculated_number)r->t[i]);
989 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
991 buffer_strcat(wb, post_date);
994 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
996 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
997 calculated_number n = cn[c];
999 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1004 // prevent a division by zero
1005 if(total == 0) total = 1;
1008 // for each dimension
1009 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
1010 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1011 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1013 calculated_number n = cn[c];
1015 buffer_strcat(wb, pre_value);
1017 if( options & RRDR_OPTION_OBJECTSROWS )
1018 buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
1020 if(co[c] & RRDR_EMPTY) {
1021 if(options & RRDR_OPTION_NULL2ZERO)
1022 buffer_strcat(wb, "0");
1024 buffer_strcat(wb, "null");
1027 if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1030 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1031 n = n * 100 / total;
1033 buffer_rrd_value(wb, n);
1036 buffer_strcat(wb, post_value);
1039 buffer_strcat(wb, post_line);
1042 buffer_strcat(wb, finish);
1043 //info("RRD2JSON(): %s: END", r->st->id);
1046 static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
1048 rrdset_check_rdlock(r->st);
1050 //info("RRD2CSV(): %s: BEGIN", r->st->id);
1054 // print the csv header
1055 for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1056 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1057 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1060 buffer_strcat(wb, startline);
1061 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1062 buffer_strcat(wb, "time");
1063 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1065 buffer_strcat(wb, separator);
1066 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1067 buffer_strcat(wb, d->name);
1068 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1071 buffer_strcat(wb, endline);
1074 // no dimensions present
1078 long start = 0, end = rrdr_rows(r), step = 1;
1079 if((options & RRDR_OPTION_REVERSED)) {
1080 start = rrdr_rows(r) - 1;
1085 // for each line in the array
1086 calculated_number total = 1;
1087 for(i = start; i != end ;i += step) {
1088 calculated_number *cn = &r->v[ i * r->d ];
1089 uint8_t *co = &r->o[ i * r->d ];
1091 buffer_strcat(wb, betweenlines);
1092 buffer_strcat(wb, startline);
1094 time_t now = r->t[i];
1096 if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
1097 // print the timestamp of the line
1098 buffer_rrd_value(wb, (calculated_number)now);
1100 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
1103 // generate the local date time
1104 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
1105 if(!tm) { error("localtime() failed."); continue; }
1106 buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
1109 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1111 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1112 calculated_number n = cn[c];
1114 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1119 // prevent a division by zero
1120 if(total == 0) total = 1;
1123 // for each dimension
1124 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1125 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1126 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1128 buffer_strcat(wb, separator);
1130 calculated_number n = cn[c];
1132 if(co[c] & RRDR_EMPTY) {
1133 if(options & RRDR_OPTION_NULL2ZERO)
1134 buffer_strcat(wb, "0");
1136 buffer_strcat(wb, "null");
1139 if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1142 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1143 n = n * 100 / total;
1145 buffer_rrd_value(wb, n);
1149 buffer_strcat(wb, endline);
1151 //info("RRD2CSV(): %s: END", r->st->id);
1154 inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
1155 rrdset_check_rdlock(r->st);
1160 calculated_number *cn = &r->v[ i * r->d ];
1161 uint8_t *co = &r->o[ i * r->d ];
1163 calculated_number sum = 0, min = 0, max = 0, v;
1164 int all_null = 1, init = 1;
1166 calculated_number total = 1;
1167 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1169 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1170 calculated_number n = cn[c];
1172 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1177 // prevent a division by zero
1178 if(total == 0) total = 1;
1181 // for each dimension
1182 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1183 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1184 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1186 calculated_number n = cn[c];
1188 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1191 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1192 n = n * 100 / total;
1194 if(unlikely(init)) {
1206 if(likely(!(co[c] & RRDR_EMPTY))) {
1211 if(n < min) min = n;
1212 if(n > max) max = n;
1215 if(unlikely(all_null)) {
1216 if(likely(all_values_are_null))
1217 *all_values_are_null = 1;
1221 if(likely(all_values_are_null))
1222 *all_values_are_null = 0;
1225 if(options & RRDR_OPTION_MIN2MAX)
1233 static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix)
1235 //info("RRD2SSV(): %s: BEGIN", r->st->id);
1238 buffer_strcat(wb, prefix);
1239 long start = 0, end = rrdr_rows(r), step = 1;
1240 if((options & RRDR_OPTION_REVERSED)) {
1241 start = rrdr_rows(r) - 1;
1246 // for each line in the array
1247 for(i = start; i != end ;i += step) {
1248 int all_values_are_null = 0;
1249 calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
1251 if(likely(i != start)) {
1252 if(r->min > v) r->min = v;
1253 if(r->max < v) r->max = v;
1260 if(likely(i != start))
1261 buffer_strcat(wb, separator);
1263 if(all_values_are_null) {
1264 if(options & RRDR_OPTION_NULL2ZERO)
1265 buffer_strcat(wb, "0");
1267 buffer_strcat(wb, "null");
1270 buffer_rrd_value(wb, v);
1272 buffer_strcat(wb, suffix);
1273 //info("RRD2SSV(): %s: END", r->st->id);
1276 inline static calculated_number *rrdr_line_values(RRDR *r)
1278 return &r->v[ r->c * r->d ];
1281 inline static uint8_t *rrdr_line_options(RRDR *r)
1283 return &r->o[ r->c * r->d ];
1286 inline static int rrdr_line_init(RRDR *r, time_t t)
1290 if(unlikely(r->c >= r->n)) {
1291 error("requested to step above RRDR size for chart %s", r->st->name);
1301 inline static void rrdr_lock_rrdset(RRDR *r) {
1303 error("NULL value given!");
1307 rrdset_rdlock(r->st);
1311 inline static void rrdr_unlock_rrdset(RRDR *r) {
1313 error("NULL value given!");
1317 if(likely(r->has_st_lock)) {
1318 rrdset_unlock(r->st);
1323 inline static void rrdr_free(RRDR *r)
1326 error("NULL value given!");
1330 rrdr_unlock_rrdset(r);
1338 static inline void rrdr_done(RRDR *r)
1344 static RRDR *rrdr_create(RRDSET *st, long n)
1347 error("NULL value given!");
1351 RRDR *r = callocz(1, sizeof(RRDR));
1354 rrdr_lock_rrdset(r);
1357 rrddim_foreach_read(rd, st) r->d++;
1361 r->t = mallocz(n * sizeof(time_t));
1362 r->v = mallocz(n * r->d * sizeof(calculated_number));
1363 r->o = mallocz(n * r->d * sizeof(uint8_t));
1364 r->od = mallocz(r->d * sizeof(uint8_t));
1366 // set the hidden flag on hidden dimensions
1368 for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
1369 if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)))
1370 r->od[c] = RRDR_HIDDEN;
1377 r->update_every = 1;
1382 RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
1384 int debug = rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?1:0;
1385 int absolute_period_requested = -1;
1387 time_t first_entry_t = rrdset_first_entry_t(st);
1388 time_t last_entry_t = rrdset_last_entry_t(st);
1390 if(before == 0 && after == 0) {
1391 // dump the all the data
1392 before = last_entry_t;
1393 after = first_entry_t;
1394 absolute_period_requested = 0;
1397 // allow relative for before (smaller than API_RELATIVE_TIME_MAX)
1398 if(((before < 0)?-before:before) <= API_RELATIVE_TIME_MAX) {
1399 if(abs(before) % st->update_every) {
1400 // make sure it is multiple of st->update_every
1401 if(before < 0) before = before - st->update_every - before % st->update_every;
1402 else before = before + st->update_every - before % st->update_every;
1404 if(before > 0) before = first_entry_t + before;
1405 else before = last_entry_t + before;
1406 absolute_period_requested = 0;
1409 // allow relative for after (smaller than API_RELATIVE_TIME_MAX)
1410 if(((after < 0)?-after:after) <= API_RELATIVE_TIME_MAX) {
1411 if(after == 0) after = -st->update_every;
1412 if(abs(after) % st->update_every) {
1413 // make sure it is multiple of st->update_every
1414 if(after < 0) after = after - st->update_every - after % st->update_every;
1415 else after = after + st->update_every - after % st->update_every;
1417 after = before + after;
1418 absolute_period_requested = 0;
1421 if(absolute_period_requested == -1)
1422 absolute_period_requested = 1;
1424 // make sure they are within our timeframe
1425 if(before > last_entry_t) before = last_entry_t;
1426 if(before < first_entry_t) before = first_entry_t;
1428 if(after > last_entry_t) after = last_entry_t;
1429 if(after < first_entry_t) after = first_entry_t;
1431 // check if they are upside down
1432 if(after > before) {
1433 time_t tmp = before;
1438 // the duration of the chart
1439 time_t duration = before - after;
1440 long available_points = duration / st->update_every;
1442 if(duration <= 0 || available_points <= 0)
1443 return rrdr_create(st, 1);
1445 // check the wanted points
1446 if(points < 0) points = -points;
1447 if(points > available_points) points = available_points;
1448 if(points == 0) points = available_points;
1450 // calculate proper grouping of source data
1451 long group = available_points / points;
1452 if(group <= 0) group = 1;
1454 // round group to the closest integer
1455 if(available_points % points > points / 2) group++;
1457 time_t after_new = (aligned) ? (after - (after % (group * st->update_every))) : after;
1458 time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
1459 long points_new = (before_new - after_new) / st->update_every / group;
1461 // find the starting and ending slots in our round robin db
1462 long start_at_slot = rrdset_time2slot(st, before_new),
1463 stop_at_slot = rrdset_time2slot(st, after_new);
1465 #ifdef NETDATA_INTERNAL_CHECKS
1466 if(after_new < first_entry_t) {
1467 error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
1469 if(after_new > last_entry_t) {
1470 error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
1472 if(before_new < first_entry_t) {
1473 error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
1475 if(before_new > last_entry_t) {
1476 error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
1478 if(start_at_slot < 0 || start_at_slot >= st->entries) {
1479 error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
1481 if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
1482 error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
1484 if(points_new > (before_new - after_new) / group / st->update_every + 1) {
1485 error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
1489 //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);
1492 before = before_new;
1493 duration = before - after;
1494 points = points_new;
1497 // before = the end time of the calculation
1498 // after = the start time of the calculation
1499 // duration = the duration of the calculation
1500 // group = the number of source points to aggregate / group together
1501 // method = the method of grouping source points
1502 // points = the number of points to generate
1505 // -------------------------------------------------------------------------
1506 // initialize our result set
1508 RRDR *r = rrdr_create(st, points);
1510 #ifdef NETDATA_INTERNAL_CHECKS
1511 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);
1516 #ifdef NETDATA_INTERNAL_CHECKS
1517 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);
1522 if(absolute_period_requested == 1)
1523 r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
1525 r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
1527 // find how many dimensions we have
1528 long dimensions = r->d;
1531 // -------------------------------------------------------------------------
1532 // checks for debugging
1534 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"
1536 , (uint32_t)first_entry_t
1537 , (uint32_t)last_entry_t
1538 , (uint32_t)(last_entry_t - first_entry_t)
1541 , (uint32_t)duration
1547 // -------------------------------------------------------------------------
1548 // temp arrays for keeping values per dimension
1550 calculated_number last_values[dimensions]; // keep the last value of each dimension
1551 calculated_number group_values[dimensions]; // keep sums when grouping
1552 long group_counts[dimensions]; // keep the number of values added to group_values
1553 uint8_t group_options[dimensions];
1554 uint8_t found_non_zero[dimensions];
1560 rrdset_check_rdlock(st);
1561 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1563 group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
1564 group_counts[c] = 0;
1565 group_options[c] = 0;
1566 found_non_zero[c] = 0;
1570 // -------------------------------------------------------------------------
1573 time_t now = rrdset_slot2time(st, start_at_slot),
1574 dt = st->update_every,
1577 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"
1589 r->update_every = (int)group * st->update_every;
1593 //info("RRD2RRDR(): %s: STARTING", st->id);
1595 long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
1596 for(; !stop_now ; now -= dt, slot--, counter++) {
1597 if(unlikely(slot < 0)) slot = st->entries - 1;
1598 if(unlikely(slot == stop_at_slot)) stop_now = counter;
1600 if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
1607 , (group_count + 1 == group)?"PRINT":" - "
1608 , (now >= after && now <= before)?"RANGE":" - "
1611 // make sure we return data in the proper time range
1612 if(unlikely(now > before)) continue;
1613 if(unlikely(now < after)) break;
1615 if(unlikely(group_count == 0)) {
1616 group_start_t = now;
1620 if(unlikely(group_count == group)) {
1621 if(unlikely(added >= points)) break;
1625 // do the calculations
1626 for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1627 storage_number n = rd->values[slot];
1628 if(unlikely(!does_storage_number_exist(n))) continue;
1632 calculated_number value = unpack_storage_number(n);
1633 if(likely(value != 0.0)) {
1634 group_options[c] |= RRDR_NONZERO;
1635 found_non_zero[c] = 1;
1638 if(unlikely(did_storage_number_reset(n)))
1639 group_options[c] |= RRDR_RESET;
1641 switch(group_method) {
1643 if(unlikely(isnan(group_values[c])) ||
1644 fabsl(value) < fabsl(group_values[c]))
1645 group_values[c] = value;
1649 if(unlikely(isnan(group_values[c])) ||
1650 fabsl(value) > fabsl(group_values[c]))
1651 group_values[c] = value;
1657 case GROUP_UNDEFINED:
1658 group_values[c] += value;
1661 case GROUP_INCREMENTAL_SUM:
1662 if(unlikely(slot == start_at_slot))
1663 last_values[c] = value;
1665 group_values[c] += last_values[c] - value;
1666 last_values[c] = value;
1672 if(unlikely(add_this)) {
1673 if(unlikely(!rrdr_line_init(r, group_start_t))) break;
1677 calculated_number *cn = rrdr_line_values(r);
1678 uint8_t *co = rrdr_line_options(r);
1680 for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1682 // update the dimension options
1683 if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
1685 // store the specific point options
1686 co[c] = group_options[c];
1689 if(unlikely(group_counts[c] == 0)) {
1691 co[c] |= RRDR_EMPTY;
1692 group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
1695 switch(group_method) {
1698 if(unlikely(isnan(group_values[c])))
1701 cn[c] = group_values[c];
1702 group_values[c] = NAN;
1707 case GROUP_INCREMENTAL_SUM:
1708 cn[c] = group_values[c];
1709 group_values[c] = 0;
1714 case GROUP_UNDEFINED:
1715 cn[c] = group_values[c] / group_counts[c];
1716 group_values[c] = 0;
1720 if(cn[c] < r->min) r->min = cn[c];
1721 if(cn[c] > r->max) r->max = cn[c];
1724 // reset for the next loop
1725 group_counts[c] = 0;
1726 group_options[c] = 0;
1736 //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
1737 //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
1741 int rrdset2value_api_v1(
1744 , calculated_number *n
1745 , const char *dimensions
1753 , int *value_is_null
1755 RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1757 if(value_is_null) *value_is_null = 1;
1761 if(rrdr_rows(r) == 0) {
1764 if(db_after) *db_after = 0;
1765 if(db_before) *db_before = 0;
1766 if(value_is_null) *value_is_null = 1;
1771 if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1772 buffer_no_cacheable(wb);
1773 else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1774 buffer_cacheable(wb);
1776 options = rrdr_check_options(r, options, dimensions);
1779 rrdr_disable_not_selected_dimensions(r, options, dimensions);
1781 if(db_after) *db_after = r->after;
1782 if(db_before) *db_before = r->before;
1784 long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
1785 *n = rrdr2value(r, i, options, value_is_null);
1791 int rrdset2anything_api_v1(
1794 , BUFFER *dimensions
1801 , time_t *latest_timestamp
1803 st->last_accessed_time = now_realtime_sec();
1805 RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1807 buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
1811 if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1812 buffer_no_cacheable(wb);
1813 else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1814 buffer_cacheable(wb);
1816 options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1819 rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions));
1821 if(latest_timestamp && rrdr_rows(r) > 0)
1822 *latest_timestamp = r->before;
1825 case DATASOURCE_SSV:
1826 if(options & RRDR_OPTION_JSON_WRAP) {
1827 wb->contenttype = CT_APPLICATION_JSON;
1828 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1829 rrdr2ssv(r, wb, options, "", " ", "");
1830 rrdr_json_wrapper_end(r, wb, format, options, 1);
1833 wb->contenttype = CT_TEXT_PLAIN;
1834 rrdr2ssv(r, wb, options, "", " ", "");
1838 case DATASOURCE_SSV_COMMA:
1839 if(options & RRDR_OPTION_JSON_WRAP) {
1840 wb->contenttype = CT_APPLICATION_JSON;
1841 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1842 rrdr2ssv(r, wb, options, "", ",", "");
1843 rrdr_json_wrapper_end(r, wb, format, options, 1);
1846 wb->contenttype = CT_TEXT_PLAIN;
1847 rrdr2ssv(r, wb, options, "", ",", "");
1851 case DATASOURCE_JS_ARRAY:
1852 if(options & RRDR_OPTION_JSON_WRAP) {
1853 wb->contenttype = CT_APPLICATION_JSON;
1854 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1855 rrdr2ssv(r, wb, options, "[", ",", "]");
1856 rrdr_json_wrapper_end(r, wb, format, options, 0);
1859 wb->contenttype = CT_APPLICATION_JSON;
1860 rrdr2ssv(r, wb, options, "[", ",", "]");
1864 case DATASOURCE_CSV:
1865 if(options & RRDR_OPTION_JSON_WRAP) {
1866 wb->contenttype = CT_APPLICATION_JSON;
1867 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1868 rrdr2csv(r, wb, options, "", ",", "\\n", "");
1869 rrdr_json_wrapper_end(r, wb, format, options, 1);
1872 wb->contenttype = CT_TEXT_PLAIN;
1873 rrdr2csv(r, wb, options, "", ",", "\r\n", "");
1877 case DATASOURCE_CSV_JSON_ARRAY:
1878 wb->contenttype = CT_APPLICATION_JSON;
1879 if(options & RRDR_OPTION_JSON_WRAP) {
1880 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1881 buffer_strcat(wb, "[\n");
1882 rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1883 buffer_strcat(wb, "\n]");
1884 rrdr_json_wrapper_end(r, wb, format, options, 0);
1887 wb->contenttype = CT_TEXT_PLAIN;
1888 buffer_strcat(wb, "[\n");
1889 rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1890 buffer_strcat(wb, "\n]");
1894 case DATASOURCE_TSV:
1895 if(options & RRDR_OPTION_JSON_WRAP) {
1896 wb->contenttype = CT_APPLICATION_JSON;
1897 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1898 rrdr2csv(r, wb, options, "", "\t", "\\n", "");
1899 rrdr_json_wrapper_end(r, wb, format, options, 1);
1902 wb->contenttype = CT_TEXT_PLAIN;
1903 rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
1907 case DATASOURCE_HTML:
1908 if(options & RRDR_OPTION_JSON_WRAP) {
1909 wb->contenttype = CT_APPLICATION_JSON;
1910 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1911 buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
1912 rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
1913 buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
1914 rrdr_json_wrapper_end(r, wb, format, options, 1);
1917 wb->contenttype = CT_TEXT_HTML;
1918 buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
1919 rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
1920 buffer_strcat(wb, "</table>\n</center>\n</html>\n");
1924 case DATASOURCE_DATATABLE_JSONP:
1925 wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1927 if(options & RRDR_OPTION_JSON_WRAP)
1928 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1930 rrdr2json(r, wb, options, 1);
1932 if(options & RRDR_OPTION_JSON_WRAP)
1933 rrdr_json_wrapper_end(r, wb, format, options, 0);
1936 case DATASOURCE_DATATABLE_JSON:
1937 wb->contenttype = CT_APPLICATION_JSON;
1939 if(options & RRDR_OPTION_JSON_WRAP)
1940 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1942 rrdr2json(r, wb, options, 1);
1944 if(options & RRDR_OPTION_JSON_WRAP)
1945 rrdr_json_wrapper_end(r, wb, format, options, 0);
1948 case DATASOURCE_JSONP:
1949 wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1950 if(options & RRDR_OPTION_JSON_WRAP)
1951 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1953 rrdr2json(r, wb, options, 0);
1955 if(options & RRDR_OPTION_JSON_WRAP)
1956 rrdr_json_wrapper_end(r, wb, format, options, 0);
1959 case DATASOURCE_JSON:
1961 wb->contenttype = CT_APPLICATION_JSON;
1963 if(options & RRDR_OPTION_JSON_WRAP)
1964 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1966 rrdr2json(r, wb, options, 0);
1968 if(options & RRDR_OPTION_JSON_WRAP)
1969 rrdr_json_wrapper_end(r, wb, format, options, 0);