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,
222 // (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000)));
224 buffer_sprintf(wb, "%s_%s{instance=\"%s\"} " COLLECTED_NUMBER_FORMAT " %llu\n",
225 chart, dimension, hostname, rd->last_collected_value,
226 (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000)));
235 rrdhost_unlock(host);
238 // ----------------------------------------------------------------------------
240 // /api/v1/allmetrics?format=bash
242 static inline size_t shell_name_copy(char *d, const char *s, size_t usable) {
245 for(n = 0; *s && n < usable ; d++, s++, n++) {
246 register char c = *s;
248 if(unlikely(!isalnum(c))) *d = '_';
249 else *d = (char)toupper(c);
256 #define SHELL_ELEMENT_MAX 100
258 void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
259 rrdhost_rdlock(host);
263 rrdset_foreach_read(st, host) {
264 calculated_number total = 0.0;
265 char chart[SHELL_ELEMENT_MAX + 1];
266 shell_name_copy(chart, st->id, SHELL_ELEMENT_MAX);
268 buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name);
269 if(rrdset_is_available_for_viewers(st)) {
272 // for each dimension
274 rrddim_foreach_read(rd, st) {
275 if(rd->collections_counter) {
276 char dimension[SHELL_ELEMENT_MAX + 1];
277 shell_name_copy(dimension, rd->id, SHELL_ELEMENT_MAX);
279 calculated_number n = rd->last_stored_value;
281 if(isnan(n) || isinf(n))
282 buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, st->units);
284 if(rd->multiplier < 0 || rd->divisor < 0) n = -n;
286 if(!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) total += n;
287 buffer_sprintf(wb, "NETDATA_%s_%s=\"%0.0Lf\" # %s\n", chart, dimension, n, st->units);
292 total = roundl(total);
293 buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"%0.0Lf\" # %s\n", chart, total, st->units);
298 buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n");
301 for(rc = host->alarms; rc ;rc = rc->next) {
302 if(!rc->rrdset) continue;
304 char chart[SHELL_ELEMENT_MAX + 1];
305 shell_name_copy(chart, rc->rrdset->id, SHELL_ELEMENT_MAX);
307 char alarm[SHELL_ELEMENT_MAX + 1];
308 shell_name_copy(alarm, rc->name, SHELL_ELEMENT_MAX);
310 calculated_number n = rc->value;
312 if(isnan(n) || isinf(n))
313 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rc->units);
316 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"%0.0Lf\" # %s\n", chart, alarm, n, rc->units);
319 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status));
322 rrdhost_unlock(host);
325 // ----------------------------------------------------------------------------
327 // RRDR dimension options
328 #define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null)
329 #define RRDR_RESET 0x02 // the dimension contains / the value is reset
330 #define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
331 #define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
332 #define RRDR_SELECTED 0x10 // the dimension is selected
334 // RRDR result options
335 #define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
336 #define RRDR_RESULT_OPTION_RELATIVE 0x00000002
338 typedef struct rrdresult {
339 RRDSET *st; // the chart this result refers to
341 uint32_t result_options; // RRDR_RESULT_OPTION_*
343 int d; // the number of dimensions
344 long n; // the number of values in the arrays
345 long rows; // the number of rows used
347 uint8_t *od; // the options for the dimensions
349 time_t *t; // array of n timestamps
350 calculated_number *v; // array n x d values
351 uint8_t *o; // array n x d options
353 long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
355 long group; // how many collected values were grouped for each row
356 int update_every; // what is the suggested update frequency in seconds
358 calculated_number min;
359 calculated_number max;
364 int has_st_lock; // if st is read locked by us
367 #define rrdr_rows(r) ((r)->rows)
370 static void rrdr_dump(RRDR *r)
375 fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
377 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
378 fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
381 , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
382 , (r->od[c] & RRDR_RESET)?"RESET ":""
383 , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
384 , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
389 fprintf(stderr, "RRDR does not have any values in it.\n");
393 fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
395 // for each line in the array
396 for(i = 0; i < r->rows ;i++) {
397 calculated_number *cn = &r->v[ i * r->d ];
398 uint8_t *co = &r->o[ i * r->d ];
400 // print the id and the timestamp of the line
401 fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
403 // for each dimension
404 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
405 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
406 if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
408 if(co[c] & RRDR_EMPTY)
409 fprintf(stderr, "null ");
411 fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
413 , (co[c] & RRDR_EMPTY)?"E":" "
414 , (co[c] & RRDR_RESET)?"R":" "
415 , (co[c] & RRDR_HIDDEN)?"H":" "
416 , (co[c] & RRDR_NONZERO)?"N":" "
420 fprintf(stderr, "\n");
425 void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) {
426 rrdset_check_rdlock(r->st);
428 if(unlikely(!dims || !*dims)) return;
430 char b[strlen(dims) + 1];
434 long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
437 // disable all of them
438 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
439 r->od[c] |= RRDR_HIDDEN;
441 while(o && *o && (tok = mystrsep(&o, ",|"))) {
444 uint32_t hash = simple_hash(tok);
446 // find it and enable it
447 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
448 if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || (hash == d->hash_name && !strcmp(d->name, tok)))) {
450 if(likely(r->od[c] & RRDR_HIDDEN)) {
451 r->od[c] |= RRDR_SELECTED;
452 r->od[c] &= ~RRDR_HIDDEN;
456 // since the user needs this dimension
457 // make it appear as NONZERO, to return it
458 // even if the dimension has only zeros
459 // unless option non_zero is set
460 if(likely(!(options & RRDR_OPTION_NONZERO)))
461 r->od[c] |= RRDR_NONZERO;
463 // count the visible dimensions
464 if(likely(r->od[c] & RRDR_NONZERO))
465 dims_not_hidden_not_zero++;
470 // check if all dimensions are hidden
471 if(unlikely(!dims_not_hidden_not_zero && dims_selected)) {
472 // there are a few selected dimensions
473 // but they are all zero
474 // enable the selected ones
475 // to avoid returning an empty chart
476 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
477 if(unlikely(r->od[c] & RRDR_SELECTED))
478 r->od[c] |= RRDR_NONZERO;
482 void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
485 case DATASOURCE_JSON:
486 buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
489 case DATASOURCE_DATATABLE_JSON:
490 buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
493 case DATASOURCE_DATATABLE_JSONP:
494 buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
497 case DATASOURCE_JSONP:
498 buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
502 buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
506 buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
510 buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
513 case DATASOURCE_HTML:
514 buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
517 case DATASOURCE_JS_ARRAY:
518 buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
521 case DATASOURCE_SSV_COMMA:
522 buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
526 buffer_strcat(wb, "unknown");
531 uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
533 rrdset_check_rdlock(r->st);
537 if(options & RRDR_OPTION_NONZERO) {
540 // commented due to #1514
542 //if(dims && *dims) {
543 // the caller wants specific dimensions
544 // disable NONZERO option
545 // to make sure we don't accidentally prevent
546 // the specific dimensions from being returned
550 // find how many dimensions are not zero
553 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
554 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
555 if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
560 // if with nonzero we get i = 0 (no dimensions will be returned)
561 // disable nonzero to show all dimensions
562 if(!i) options &= ~RRDR_OPTION_NONZERO;
568 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
570 rrdset_check_rdlock(r->st);
572 long rows = rrdr_rows(r);
576 //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
577 char kq[2] = "", // key quote
578 sq[2] = ""; // string quote
580 if( options & RRDR_OPTION_GOOGLE_JSON ) {
589 buffer_sprintf(wb, "{\n"
592 " %sname%s: %s%s%s,\n"
593 " %sview_update_every%s: %d,\n"
594 " %supdate_every%s: %d,\n"
595 " %sfirst_entry%s: %u,\n"
596 " %slast_entry%s: %u,\n"
599 " %sdimension_names%s: ["
601 , kq, kq, sq, r->st->id, sq
602 , kq, kq, sq, r->st->name, sq
603 , kq, kq, r->update_every
604 , kq, kq, r->st->update_every
605 , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
606 , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
607 , kq, kq, (uint32_t)r->before
608 , kq, kq, (uint32_t)r->after
611 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
612 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
613 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
615 if(i) buffer_strcat(wb, ", ");
616 buffer_strcat(wb, sq);
617 buffer_strcat(wb, rd->name);
618 buffer_strcat(wb, sq);
622 #ifdef NETDATA_INTERNAL_CHECKS
623 error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
626 buffer_strcat(wb, sq);
627 buffer_strcat(wb, "no data");
628 buffer_strcat(wb, sq);
631 buffer_sprintf(wb, "],\n"
632 " %sdimension_ids%s: ["
635 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
636 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
637 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
639 if(i) buffer_strcat(wb, ", ");
640 buffer_strcat(wb, sq);
641 buffer_strcat(wb, rd->id);
642 buffer_strcat(wb, sq);
647 buffer_strcat(wb, sq);
648 buffer_strcat(wb, "no data");
649 buffer_strcat(wb, sq);
652 buffer_sprintf(wb, "],\n"
653 " %slatest_values%s: ["
656 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
657 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
658 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
660 if(i) buffer_strcat(wb, ", ");
663 storage_number n = rd->values[rrdset_last_slot(r->st)];
665 if(!does_storage_number_exist(n))
666 buffer_strcat(wb, "null");
668 buffer_rrd_value(wb, unpack_storage_number(n));
672 buffer_strcat(wb, "null");
675 buffer_sprintf(wb, "],\n"
676 " %sview_latest_values%s: ["
681 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
682 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
683 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
685 if(i) buffer_strcat(wb, ", ");
688 calculated_number *cn = &r->v[ (0) * r->d ];
689 uint8_t *co = &r->o[ (0) * r->d ];
691 if(co[c] & RRDR_EMPTY)
692 buffer_strcat(wb, "null");
694 buffer_rrd_value(wb, cn[c]);
699 buffer_strcat(wb, "null");
702 buffer_sprintf(wb, "],\n"
703 " %sdimensions%s: %ld,\n"
704 " %spoints%s: %ld,\n"
711 rrdr_buffer_print_format(wb, format);
713 buffer_sprintf(wb, "%s,\n"
719 if(string_value) buffer_strcat(wb, sq);
720 //info("JSONWRAPPER(): %s: END", r->st->id);
723 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
727 char kq[2] = "", // key quote
728 sq[2] = ""; // string quote
730 if( options & RRDR_OPTION_GOOGLE_JSON ) {
739 if(string_value) buffer_strcat(wb, sq);
741 buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
742 buffer_rrd_value(wb, r->min);
743 buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
744 buffer_rrd_value(wb, r->max);
745 buffer_strcat(wb, "\n}\n");
748 #define JSON_DATES_JS 1
749 #define JSON_DATES_TIMESTAMP 2
751 static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
753 rrdset_check_rdlock(r->st);
755 //info("RRD2JSON(): %s: BEGIN", r->st->id);
756 int row_annotations = 0, dates, dates_with_new = 0;
757 char kq[2] = "", // key quote
758 sq[2] = "", // string quote
759 pre_label[101] = "", // before each label
760 post_label[101] = "", // after each label
761 pre_date[101] = "", // the beginning of line, to the date
762 post_date[101] = "", // closing the date
763 pre_value[101] = "", // before each value
764 post_value[101] = "", // after each value
765 post_line[101] = "", // at the end of each row
766 normal_annotation[201] = "", // default row annotation
767 overflow_annotation[201] = "", // overflow row annotation
768 data_begin[101] = "", // between labels and values
769 finish[101] = ""; // at the end of everything
772 dates = JSON_DATES_JS;
773 if( options & RRDR_OPTION_GOOGLE_JSON ) {
782 snprintfz(pre_date, 100, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
783 snprintfz(post_date, 100, "%s}", sq);
784 snprintfz(pre_label, 100, ",\n {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
785 snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
786 snprintfz(pre_value, 100, ",{%sv%s:", kq, kq);
787 strcpy(post_value, "}");
788 strcpy(post_line, "]}");
789 snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq);
790 strcpy(finish, "\n ]\n}");
792 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);
793 snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
795 buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
796 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);
797 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);
798 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);
800 // remove the valueobjects flag
801 // google wants its own keys
802 if(options & RRDR_OPTION_OBJECTSROWS)
803 options &= ~RRDR_OPTION_OBJECTSROWS;
808 if(options & RRDR_OPTION_GOOGLE_JSON) {
809 dates = JSON_DATES_JS;
813 dates = JSON_DATES_TIMESTAMP;
816 if( options & RRDR_OPTION_OBJECTSROWS )
817 strcpy(pre_date, " { ");
819 strcpy(pre_date, " [ ");
820 strcpy(pre_label, ", \"");
821 strcpy(post_label, "\"");
822 strcpy(pre_value, ", ");
823 if( options & RRDR_OPTION_OBJECTSROWS )
824 strcpy(post_line, "}");
826 strcpy(post_line, "]");
827 snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
828 strcpy(finish, "\n ]\n}");
830 buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
831 buffer_sprintf(wb, "%stime%s", sq, sq);
834 // -------------------------------------------------------------------------
835 // print the JSON header
840 // print the header lines
841 for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
842 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
843 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
845 buffer_strcat(wb, pre_label);
846 buffer_strcat(wb, rd->name);
847 buffer_strcat(wb, post_label);
851 buffer_strcat(wb, pre_label);
852 buffer_strcat(wb, "no data");
853 buffer_strcat(wb, post_label);
856 // print the begin of row data
857 buffer_strcat(wb, data_begin);
859 // if all dimensions are hidden, print a null
861 buffer_strcat(wb, finish);
865 long start = 0, end = rrdr_rows(r), step = 1;
866 if((options & RRDR_OPTION_REVERSED)) {
867 start = rrdr_rows(r) - 1;
872 // for each line in the array
873 calculated_number total = 1;
874 for(i = start; i != end ;i += step) {
875 calculated_number *cn = &r->v[ i * r->d ];
876 uint8_t *co = &r->o[ i * r->d ];
878 time_t now = r->t[i];
880 if(dates == JSON_DATES_JS) {
881 // generate the local date time
882 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
883 if(!tm) { error("localtime_r() failed."); continue; }
885 if(likely(i != start)) buffer_strcat(wb, ",\n");
886 buffer_strcat(wb, pre_date);
888 if( options & RRDR_OPTION_OBJECTSROWS )
889 buffer_sprintf(wb, "%stime%s: ", kq, kq);
892 buffer_strcat(wb, "new ");
894 buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
896 buffer_strcat(wb, post_date);
898 if(row_annotations) {
899 // google supports one annotation per row
900 int annotation_found = 0;
901 for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
902 if(co[c] & RRDR_RESET) {
903 buffer_strcat(wb, overflow_annotation);
904 annotation_found = 1;
908 if(!annotation_found)
909 buffer_strcat(wb, normal_annotation);
913 // print the timestamp of the line
914 if(likely(i != start)) buffer_strcat(wb, ",\n");
915 buffer_strcat(wb, pre_date);
917 if( options & RRDR_OPTION_OBJECTSROWS )
918 buffer_sprintf(wb, "%stime%s: ", kq, kq);
920 buffer_rrd_value(wb, (calculated_number)r->t[i]);
922 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
924 buffer_strcat(wb, post_date);
927 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
929 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
930 calculated_number n = cn[c];
932 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
937 // prevent a division by zero
938 if(total == 0) total = 1;
941 // for each dimension
942 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
943 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
944 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
946 calculated_number n = cn[c];
948 buffer_strcat(wb, pre_value);
950 if( options & RRDR_OPTION_OBJECTSROWS )
951 buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
953 if(co[c] & RRDR_EMPTY) {
954 if(options & RRDR_OPTION_NULL2ZERO)
955 buffer_strcat(wb, "0");
957 buffer_strcat(wb, "null");
960 if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
963 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
966 buffer_rrd_value(wb, n);
969 buffer_strcat(wb, post_value);
972 buffer_strcat(wb, post_line);
975 buffer_strcat(wb, finish);
976 //info("RRD2JSON(): %s: END", r->st->id);
979 static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
981 rrdset_check_rdlock(r->st);
983 //info("RRD2CSV(): %s: BEGIN", r->st->id);
987 // print the csv header
988 for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
989 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
990 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
993 buffer_strcat(wb, startline);
994 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
995 buffer_strcat(wb, "time");
996 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
998 buffer_strcat(wb, separator);
999 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1000 buffer_strcat(wb, d->name);
1001 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
1004 buffer_strcat(wb, endline);
1007 // no dimensions present
1011 long start = 0, end = rrdr_rows(r), step = 1;
1012 if((options & RRDR_OPTION_REVERSED)) {
1013 start = rrdr_rows(r) - 1;
1018 // for each line in the array
1019 calculated_number total = 1;
1020 for(i = start; i != end ;i += step) {
1021 calculated_number *cn = &r->v[ i * r->d ];
1022 uint8_t *co = &r->o[ i * r->d ];
1024 buffer_strcat(wb, betweenlines);
1025 buffer_strcat(wb, startline);
1027 time_t now = r->t[i];
1029 if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
1030 // print the timestamp of the line
1031 buffer_rrd_value(wb, (calculated_number)now);
1033 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
1036 // generate the local date time
1037 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
1038 if(!tm) { error("localtime() failed."); continue; }
1039 buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
1042 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1044 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1045 calculated_number n = cn[c];
1047 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1052 // prevent a division by zero
1053 if(total == 0) total = 1;
1056 // for each dimension
1057 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1058 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1059 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1061 buffer_strcat(wb, separator);
1063 calculated_number n = cn[c];
1065 if(co[c] & RRDR_EMPTY) {
1066 if(options & RRDR_OPTION_NULL2ZERO)
1067 buffer_strcat(wb, "0");
1069 buffer_strcat(wb, "null");
1072 if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1075 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1076 n = n * 100 / total;
1078 buffer_rrd_value(wb, n);
1082 buffer_strcat(wb, endline);
1084 //info("RRD2CSV(): %s: END", r->st->id);
1087 inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
1088 rrdset_check_rdlock(r->st);
1093 calculated_number *cn = &r->v[ i * r->d ];
1094 uint8_t *co = &r->o[ i * r->d ];
1096 calculated_number sum = 0, min = 0, max = 0, v;
1097 int all_null = 1, init = 1;
1099 calculated_number total = 1;
1100 if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1102 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1103 calculated_number n = cn[c];
1105 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1110 // prevent a division by zero
1111 if(total == 0) total = 1;
1114 // for each dimension
1115 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1116 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1117 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1119 calculated_number n = cn[c];
1121 if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1124 if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1125 n = n * 100 / total;
1127 if(unlikely(init)) {
1139 if(likely(!(co[c] & RRDR_EMPTY))) {
1144 if(n < min) min = n;
1145 if(n > max) max = n;
1148 if(unlikely(all_null)) {
1149 if(likely(all_values_are_null))
1150 *all_values_are_null = 1;
1154 if(likely(all_values_are_null))
1155 *all_values_are_null = 0;
1158 if(options & RRDR_OPTION_MIN2MAX)
1166 static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix)
1168 //info("RRD2SSV(): %s: BEGIN", r->st->id);
1171 buffer_strcat(wb, prefix);
1172 long start = 0, end = rrdr_rows(r), step = 1;
1173 if((options & RRDR_OPTION_REVERSED)) {
1174 start = rrdr_rows(r) - 1;
1179 // for each line in the array
1180 for(i = start; i != end ;i += step) {
1181 int all_values_are_null = 0;
1182 calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
1184 if(likely(i != start)) {
1185 if(r->min > v) r->min = v;
1186 if(r->max < v) r->max = v;
1193 if(likely(i != start))
1194 buffer_strcat(wb, separator);
1196 if(all_values_are_null) {
1197 if(options & RRDR_OPTION_NULL2ZERO)
1198 buffer_strcat(wb, "0");
1200 buffer_strcat(wb, "null");
1203 buffer_rrd_value(wb, v);
1205 buffer_strcat(wb, suffix);
1206 //info("RRD2SSV(): %s: END", r->st->id);
1209 inline static calculated_number *rrdr_line_values(RRDR *r)
1211 return &r->v[ r->c * r->d ];
1214 inline static uint8_t *rrdr_line_options(RRDR *r)
1216 return &r->o[ r->c * r->d ];
1219 inline static int rrdr_line_init(RRDR *r, time_t t)
1223 if(unlikely(r->c >= r->n)) {
1224 error("requested to step above RRDR size for chart %s", r->st->name);
1234 inline static void rrdr_lock_rrdset(RRDR *r) {
1236 error("NULL value given!");
1240 rrdset_rdlock(r->st);
1244 inline static void rrdr_unlock_rrdset(RRDR *r) {
1246 error("NULL value given!");
1250 if(likely(r->has_st_lock)) {
1251 rrdset_unlock(r->st);
1256 inline static void rrdr_free(RRDR *r)
1259 error("NULL value given!");
1263 rrdr_unlock_rrdset(r);
1271 static inline void rrdr_done(RRDR *r)
1277 static RRDR *rrdr_create(RRDSET *st, long n)
1280 error("NULL value given!");
1284 RRDR *r = callocz(1, sizeof(RRDR));
1287 rrdr_lock_rrdset(r);
1290 rrddim_foreach_read(rd, st) r->d++;
1294 r->t = mallocz(n * sizeof(time_t));
1295 r->v = mallocz(n * r->d * sizeof(calculated_number));
1296 r->o = mallocz(n * r->d * sizeof(uint8_t));
1297 r->od = mallocz(r->d * sizeof(uint8_t));
1299 // set the hidden flag on hidden dimensions
1301 for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
1302 if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)))
1303 r->od[c] = RRDR_HIDDEN;
1310 r->update_every = 1;
1315 RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
1317 int debug = rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?1:0;
1318 int absolute_period_requested = -1;
1320 time_t first_entry_t = rrdset_first_entry_t(st);
1321 time_t last_entry_t = rrdset_last_entry_t(st);
1323 if(before == 0 && after == 0) {
1324 // dump the all the data
1325 before = last_entry_t;
1326 after = first_entry_t;
1327 absolute_period_requested = 0;
1330 // allow relative for before (smaller than API_RELATIVE_TIME_MAX)
1331 if(((before < 0)?-before:before) <= API_RELATIVE_TIME_MAX) {
1332 if(abs(before) % st->update_every) {
1333 // make sure it is multiple of st->update_every
1334 if(before < 0) before = before - st->update_every - before % st->update_every;
1335 else before = before + st->update_every - before % st->update_every;
1337 if(before > 0) before = first_entry_t + before;
1338 else before = last_entry_t + before;
1339 absolute_period_requested = 0;
1342 // allow relative for after (smaller than API_RELATIVE_TIME_MAX)
1343 if(((after < 0)?-after:after) <= API_RELATIVE_TIME_MAX) {
1344 if(after == 0) after = -st->update_every;
1345 if(abs(after) % st->update_every) {
1346 // make sure it is multiple of st->update_every
1347 if(after < 0) after = after - st->update_every - after % st->update_every;
1348 else after = after + st->update_every - after % st->update_every;
1350 after = before + after;
1351 absolute_period_requested = 0;
1354 if(absolute_period_requested == -1)
1355 absolute_period_requested = 1;
1357 // make sure they are within our timeframe
1358 if(before > last_entry_t) before = last_entry_t;
1359 if(before < first_entry_t) before = first_entry_t;
1361 if(after > last_entry_t) after = last_entry_t;
1362 if(after < first_entry_t) after = first_entry_t;
1364 // check if they are upside down
1365 if(after > before) {
1366 time_t tmp = before;
1371 // the duration of the chart
1372 time_t duration = before - after;
1373 long available_points = duration / st->update_every;
1375 if(duration <= 0 || available_points <= 0)
1376 return rrdr_create(st, 1);
1378 // check the wanted points
1379 if(points < 0) points = -points;
1380 if(points > available_points) points = available_points;
1381 if(points == 0) points = available_points;
1383 // calculate proper grouping of source data
1384 long group = available_points / points;
1385 if(group <= 0) group = 1;
1387 // round group to the closest integer
1388 if(available_points % points > points / 2) group++;
1390 time_t after_new = (aligned) ? (after - (after % (group * st->update_every))) : after;
1391 time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
1392 long points_new = (before_new - after_new) / st->update_every / group;
1394 // find the starting and ending slots in our round robin db
1395 long start_at_slot = rrdset_time2slot(st, before_new),
1396 stop_at_slot = rrdset_time2slot(st, after_new);
1398 #ifdef NETDATA_INTERNAL_CHECKS
1399 if(after_new < first_entry_t) {
1400 error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
1402 if(after_new > last_entry_t) {
1403 error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
1405 if(before_new < first_entry_t) {
1406 error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
1408 if(before_new > last_entry_t) {
1409 error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
1411 if(start_at_slot < 0 || start_at_slot >= st->entries) {
1412 error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
1414 if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
1415 error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
1417 if(points_new > (before_new - after_new) / group / st->update_every + 1) {
1418 error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
1422 //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);
1425 before = before_new;
1426 duration = before - after;
1427 points = points_new;
1430 // before = the end time of the calculation
1431 // after = the start time of the calculation
1432 // duration = the duration of the calculation
1433 // group = the number of source points to aggregate / group together
1434 // method = the method of grouping source points
1435 // points = the number of points to generate
1438 // -------------------------------------------------------------------------
1439 // initialize our result set
1441 RRDR *r = rrdr_create(st, points);
1443 #ifdef NETDATA_INTERNAL_CHECKS
1444 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);
1449 #ifdef NETDATA_INTERNAL_CHECKS
1450 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);
1455 if(absolute_period_requested == 1)
1456 r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
1458 r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
1460 // find how many dimensions we have
1461 long dimensions = r->d;
1464 // -------------------------------------------------------------------------
1465 // checks for debugging
1467 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"
1469 , (uint32_t)first_entry_t
1470 , (uint32_t)last_entry_t
1471 , (uint32_t)(last_entry_t - first_entry_t)
1474 , (uint32_t)duration
1480 // -------------------------------------------------------------------------
1481 // temp arrays for keeping values per dimension
1483 calculated_number last_values[dimensions]; // keep the last value of each dimension
1484 calculated_number group_values[dimensions]; // keep sums when grouping
1485 long group_counts[dimensions]; // keep the number of values added to group_values
1486 uint8_t group_options[dimensions];
1487 uint8_t found_non_zero[dimensions];
1493 rrdset_check_rdlock(st);
1494 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1496 group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
1497 group_counts[c] = 0;
1498 group_options[c] = 0;
1499 found_non_zero[c] = 0;
1503 // -------------------------------------------------------------------------
1506 time_t now = rrdset_slot2time(st, start_at_slot),
1507 dt = st->update_every,
1510 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"
1522 r->update_every = (int)group * st->update_every;
1526 //info("RRD2RRDR(): %s: STARTING", st->id);
1528 long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
1529 for(; !stop_now ; now -= dt, slot--, counter++) {
1530 if(unlikely(slot < 0)) slot = st->entries - 1;
1531 if(unlikely(slot == stop_at_slot)) stop_now = counter;
1533 if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
1540 , (group_count + 1 == group)?"PRINT":" - "
1541 , (now >= after && now <= before)?"RANGE":" - "
1544 // make sure we return data in the proper time range
1545 if(unlikely(now > before)) continue;
1546 if(unlikely(now < after)) break;
1548 if(unlikely(group_count == 0)) {
1549 group_start_t = now;
1553 if(unlikely(group_count == group)) {
1554 if(unlikely(added >= points)) break;
1558 // do the calculations
1559 for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1560 storage_number n = rd->values[slot];
1561 if(unlikely(!does_storage_number_exist(n))) continue;
1565 calculated_number value = unpack_storage_number(n);
1566 if(likely(value != 0.0)) {
1567 group_options[c] |= RRDR_NONZERO;
1568 found_non_zero[c] = 1;
1571 if(unlikely(did_storage_number_reset(n)))
1572 group_options[c] |= RRDR_RESET;
1574 switch(group_method) {
1576 if(unlikely(isnan(group_values[c])) ||
1577 fabsl(value) < fabsl(group_values[c]))
1578 group_values[c] = value;
1582 if(unlikely(isnan(group_values[c])) ||
1583 fabsl(value) > fabsl(group_values[c]))
1584 group_values[c] = value;
1590 case GROUP_UNDEFINED:
1591 group_values[c] += value;
1594 case GROUP_INCREMENTAL_SUM:
1595 if(unlikely(slot == start_at_slot))
1596 last_values[c] = value;
1598 group_values[c] += last_values[c] - value;
1599 last_values[c] = value;
1605 if(unlikely(add_this)) {
1606 if(unlikely(!rrdr_line_init(r, group_start_t))) break;
1610 calculated_number *cn = rrdr_line_values(r);
1611 uint8_t *co = rrdr_line_options(r);
1613 for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1615 // update the dimension options
1616 if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
1618 // store the specific point options
1619 co[c] = group_options[c];
1622 if(unlikely(group_counts[c] == 0)) {
1624 co[c] |= RRDR_EMPTY;
1625 group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
1628 switch(group_method) {
1631 if(unlikely(isnan(group_values[c])))
1634 cn[c] = group_values[c];
1635 group_values[c] = NAN;
1640 case GROUP_INCREMENTAL_SUM:
1641 cn[c] = group_values[c];
1642 group_values[c] = 0;
1647 case GROUP_UNDEFINED:
1648 cn[c] = group_values[c] / group_counts[c];
1649 group_values[c] = 0;
1653 if(cn[c] < r->min) r->min = cn[c];
1654 if(cn[c] > r->max) r->max = cn[c];
1657 // reset for the next loop
1658 group_counts[c] = 0;
1659 group_options[c] = 0;
1669 //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
1670 //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
1674 int rrdset2value_api_v1(
1677 , calculated_number *n
1678 , const char *dimensions
1686 , int *value_is_null
1688 RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1690 if(value_is_null) *value_is_null = 1;
1694 if(rrdr_rows(r) == 0) {
1697 if(db_after) *db_after = 0;
1698 if(db_before) *db_before = 0;
1699 if(value_is_null) *value_is_null = 1;
1704 if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1705 buffer_no_cacheable(wb);
1706 else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1707 buffer_cacheable(wb);
1709 options = rrdr_check_options(r, options, dimensions);
1712 rrdr_disable_not_selected_dimensions(r, options, dimensions);
1714 if(db_after) *db_after = r->after;
1715 if(db_before) *db_before = r->before;
1717 long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
1718 *n = rrdr2value(r, i, options, value_is_null);
1724 int rrdset2anything_api_v1(
1727 , BUFFER *dimensions
1734 , time_t *latest_timestamp
1736 st->last_accessed_time = now_realtime_sec();
1738 RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1740 buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
1744 if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1745 buffer_no_cacheable(wb);
1746 else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1747 buffer_cacheable(wb);
1749 options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1752 rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions));
1754 if(latest_timestamp && rrdr_rows(r) > 0)
1755 *latest_timestamp = r->before;
1758 case DATASOURCE_SSV:
1759 if(options & RRDR_OPTION_JSON_WRAP) {
1760 wb->contenttype = CT_APPLICATION_JSON;
1761 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1762 rrdr2ssv(r, wb, options, "", " ", "");
1763 rrdr_json_wrapper_end(r, wb, format, options, 1);
1766 wb->contenttype = CT_TEXT_PLAIN;
1767 rrdr2ssv(r, wb, options, "", " ", "");
1771 case DATASOURCE_SSV_COMMA:
1772 if(options & RRDR_OPTION_JSON_WRAP) {
1773 wb->contenttype = CT_APPLICATION_JSON;
1774 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1775 rrdr2ssv(r, wb, options, "", ",", "");
1776 rrdr_json_wrapper_end(r, wb, format, options, 1);
1779 wb->contenttype = CT_TEXT_PLAIN;
1780 rrdr2ssv(r, wb, options, "", ",", "");
1784 case DATASOURCE_JS_ARRAY:
1785 if(options & RRDR_OPTION_JSON_WRAP) {
1786 wb->contenttype = CT_APPLICATION_JSON;
1787 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1788 rrdr2ssv(r, wb, options, "[", ",", "]");
1789 rrdr_json_wrapper_end(r, wb, format, options, 0);
1792 wb->contenttype = CT_APPLICATION_JSON;
1793 rrdr2ssv(r, wb, options, "[", ",", "]");
1797 case DATASOURCE_CSV:
1798 if(options & RRDR_OPTION_JSON_WRAP) {
1799 wb->contenttype = CT_APPLICATION_JSON;
1800 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1801 rrdr2csv(r, wb, options, "", ",", "\\n", "");
1802 rrdr_json_wrapper_end(r, wb, format, options, 1);
1805 wb->contenttype = CT_TEXT_PLAIN;
1806 rrdr2csv(r, wb, options, "", ",", "\r\n", "");
1810 case DATASOURCE_CSV_JSON_ARRAY:
1811 wb->contenttype = CT_APPLICATION_JSON;
1812 if(options & RRDR_OPTION_JSON_WRAP) {
1813 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1814 buffer_strcat(wb, "[\n");
1815 rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1816 buffer_strcat(wb, "\n]");
1817 rrdr_json_wrapper_end(r, wb, format, options, 0);
1820 wb->contenttype = CT_TEXT_PLAIN;
1821 buffer_strcat(wb, "[\n");
1822 rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1823 buffer_strcat(wb, "\n]");
1827 case DATASOURCE_TSV:
1828 if(options & RRDR_OPTION_JSON_WRAP) {
1829 wb->contenttype = CT_APPLICATION_JSON;
1830 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1831 rrdr2csv(r, wb, options, "", "\t", "\\n", "");
1832 rrdr_json_wrapper_end(r, wb, format, options, 1);
1835 wb->contenttype = CT_TEXT_PLAIN;
1836 rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
1840 case DATASOURCE_HTML:
1841 if(options & RRDR_OPTION_JSON_WRAP) {
1842 wb->contenttype = CT_APPLICATION_JSON;
1843 rrdr_json_wrapper_begin(r, wb, format, options, 1);
1844 buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
1845 rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
1846 buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
1847 rrdr_json_wrapper_end(r, wb, format, options, 1);
1850 wb->contenttype = CT_TEXT_HTML;
1851 buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
1852 rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
1853 buffer_strcat(wb, "</table>\n</center>\n</html>\n");
1857 case DATASOURCE_DATATABLE_JSONP:
1858 wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1860 if(options & RRDR_OPTION_JSON_WRAP)
1861 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1863 rrdr2json(r, wb, options, 1);
1865 if(options & RRDR_OPTION_JSON_WRAP)
1866 rrdr_json_wrapper_end(r, wb, format, options, 0);
1869 case DATASOURCE_DATATABLE_JSON:
1870 wb->contenttype = CT_APPLICATION_JSON;
1872 if(options & RRDR_OPTION_JSON_WRAP)
1873 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1875 rrdr2json(r, wb, options, 1);
1877 if(options & RRDR_OPTION_JSON_WRAP)
1878 rrdr_json_wrapper_end(r, wb, format, options, 0);
1881 case DATASOURCE_JSONP:
1882 wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1883 if(options & RRDR_OPTION_JSON_WRAP)
1884 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1886 rrdr2json(r, wb, options, 0);
1888 if(options & RRDR_OPTION_JSON_WRAP)
1889 rrdr_json_wrapper_end(r, wb, format, options, 0);
1892 case DATASOURCE_JSON:
1894 wb->contenttype = CT_APPLICATION_JSON;
1896 if(options & RRDR_OPTION_JSON_WRAP)
1897 rrdr_json_wrapper_begin(r, wb, format, options, 0);
1899 rrdr2json(r, wb, options, 0);
1901 if(options & RRDR_OPTION_JSON_WRAP)
1902 rrdr_json_wrapper_end(r, wb, format, options, 0);