]> arthur.barton.de Git - netdata.git/blob - src/rrd2json_api_old.c
Merge branch 'master' into ab-debian
[netdata.git] / src / rrd2json_api_old.c
1 #include "common.h"
2
3 unsigned long rrdset_info2json_api_old(RRDSET *st, char *options, BUFFER *wb) {
4     time_t now = now_realtime_sec();
5
6     rrdset_rdlock(st);
7
8     st->last_accessed_time = now;
9
10     buffer_sprintf(wb,
11             "\t\t{\n"
12             "\t\t\t\"id\": \"%s\",\n"
13             "\t\t\t\"name\": \"%s\",\n"
14             "\t\t\t\"type\": \"%s\",\n"
15             "\t\t\t\"family\": \"%s\",\n"
16             "\t\t\t\"context\": \"%s\",\n"
17             "\t\t\t\"title\": \"%s\",\n"
18             "\t\t\t\"priority\": %ld,\n"
19             "\t\t\t\"enabled\": %d,\n"
20             "\t\t\t\"units\": \"%s\",\n"
21             "\t\t\t\"url\": \"/data/%s/%s\",\n"
22             "\t\t\t\"chart_type\": \"%s\",\n"
23             "\t\t\t\"counter\": %lu,\n"
24             "\t\t\t\"entries\": %ld,\n"
25             "\t\t\t\"first_entry_t\": %ld,\n"
26             "\t\t\t\"last_entry\": %lu,\n"
27             "\t\t\t\"last_entry_t\": %ld,\n"
28             "\t\t\t\"last_entry_secs_ago\": %ld,\n"
29             "\t\t\t\"update_every\": %d,\n"
30             "\t\t\t\"isdetail\": %d,\n"
31             "\t\t\t\"usec_since_last_update\": %llu,\n"
32             "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
33             "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
34             "\t\t\t\"dimensions\": [\n"
35             , st->id
36             , st->name
37             , st->type
38             , st->family
39             , st->context
40             , st->title
41             , st->priority
42             , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?1:0
43             , st->units
44             , st->name, options?options:""
45             , rrdset_type_name(st->chart_type)
46             , st->counter
47             , st->entries
48             , rrdset_first_entry_t(st)
49             , rrdset_last_slot(st)
50             , rrdset_last_entry_t(st)
51             , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
52             , st->update_every
53             , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?1:0
54             , st->usec_since_last_update
55             , st->collected_total
56             , st->last_collected_total
57     );
58
59     unsigned long memory = st->memsize;
60
61     RRDDIM *rd;
62     rrddim_foreach_read(rd, st) {
63
64         memory += rd->memsize;
65
66         buffer_sprintf(wb,
67                 "\t\t\t\t{\n"
68                 "\t\t\t\t\t\"id\": \"%s\",\n"
69                 "\t\t\t\t\t\"name\": \"%s\",\n"
70                 "\t\t\t\t\t\"entries\": %ld,\n"
71                 "\t\t\t\t\t\"isHidden\": %d,\n"
72                 "\t\t\t\t\t\"algorithm\": \"%s\",\n"
73                 "\t\t\t\t\t\"multiplier\": " COLLECTED_NUMBER_FORMAT ",\n"
74                 "\t\t\t\t\t\"divisor\": " COLLECTED_NUMBER_FORMAT ",\n"
75                 "\t\t\t\t\t\"last_entry_t\": %ld,\n"
76                 "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
77                 "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
78                 "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
79                 "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
80                 "\t\t\t\t\t\"memory\": %lu\n"
81                 "\t\t\t\t}%s\n"
82                 , rd->id
83                 , rd->name
84                 , rd->entries
85                 , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?1:0
86                 , rrd_algorithm_name(rd->algorithm)
87                 , rd->multiplier
88                 , rd->divisor
89                 , rd->last_collected_time.tv_sec
90                 , rd->collected_value
91                 , rd->calculated_value
92                 , rd->last_collected_value
93                 , rd->last_calculated_value
94                 , rd->memsize
95                 , rd->next?",":""
96         );
97     }
98
99     buffer_sprintf(wb,
100             "\t\t\t],\n"
101                     "\t\t\t\"memory\" : %lu\n"
102                     "\t\t}"
103                    , memory
104     );
105
106     rrdset_unlock(st);
107     return memory;
108 }
109
110 #define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
111 #define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
112
113 void rrd_graph2json_api_old(RRDSET *st, char *options, BUFFER *wb)
114 {
115     buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
116     rrdset_info2json_api_old(st, options, wb);
117     buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
118 }
119
120 void rrd_all2json_api_old(RRDHOST *host, BUFFER *wb)
121 {
122     unsigned long memory = 0;
123     long c = 0;
124     RRDSET *st;
125
126     time_t now = now_realtime_sec();
127
128     buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
129
130     rrdhost_rdlock(host);
131     rrdset_foreach_read(st, host) {
132         if(rrdset_is_available_for_viewers(st)) {
133             if(c) buffer_strcat(wb, ",\n");
134             memory += rrdset_info2json_api_old(st, NULL, wb);
135
136             c++;
137             st->last_accessed_time = now;
138         }
139     }
140     rrdhost_unlock(host);
141
142     buffer_sprintf(wb, "\n\t],\n"
143                     "\t\"hostname\": \"%s\",\n"
144                     "\t\"update_every\": %d,\n"
145                     "\t\"history\": %ld,\n"
146                     "\t\"memory\": %lu\n"
147                     "}\n"
148                    , host->hostname
149                    , host->rrd_update_every
150                    , host->rrd_history_entries
151                    , memory
152     );
153 }
154
155 time_t rrdset2json_api_old(
156         int type
157         , RRDSET *st
158         , BUFFER *wb
159         , long points
160         , long group
161         , int group_method
162         , time_t after
163         , time_t before
164         , int only_non_zero
165 ) {
166     int c;
167     rrdset_rdlock(st);
168
169     st->last_accessed_time = now_realtime_sec();
170
171     // -------------------------------------------------------------------------
172     // switch from JSON to google JSON
173
174     char kq[2] = "\"";
175     char sq[2] = "\"";
176     switch(type) {
177         case DATASOURCE_DATATABLE_JSON:
178         case DATASOURCE_DATATABLE_JSONP:
179             kq[0] = '\0';
180             sq[0] = '\'';
181             break;
182
183         case DATASOURCE_JSON:
184         default:
185             break;
186     }
187
188
189     // -------------------------------------------------------------------------
190     // validate the parameters
191
192     if(points < 1) points = 1;
193     if(group < 1) group = 1;
194
195     if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
196     if(after  == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
197
198     // ---
199
200     // our return value (the last timestamp printed)
201     // this is required to detect re-transmit in google JSONP
202     time_t last_timestamp = 0;
203
204
205     // -------------------------------------------------------------------------
206     // find how many dimensions we have
207
208     int dimensions = 0;
209     RRDDIM *rd;
210     rrddim_foreach_read(rd, st) dimensions++;
211     if(!dimensions) {
212         rrdset_unlock(st);
213         buffer_strcat(wb, "No dimensions yet.");
214         return 0;
215     }
216
217
218     // -------------------------------------------------------------------------
219     // prepare various strings, to speed up the loop
220
221     char overflow_annotation[201]; 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);
222     char normal_annotation[201];   snprintfz(normal_annotation,   200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
223     char pre_date[51];             snprintfz(pre_date,             50, "        {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
224     char post_date[21];            snprintfz(post_date,            20, "%s}", sq);
225     char pre_value[21];            snprintfz(pre_value,            20, ",{%sv%s:", kq, kq);
226     char post_value[21];           strcpy(post_value,                  "}");
227
228
229     // -------------------------------------------------------------------------
230     // checks for debugging
231
232     if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)) {
233         debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
234               , st->id
235               , rrdset_first_entry_t(st)
236               , rrdset_last_entry_t(st)
237               , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
238               , after
239               , before
240               , before - after
241               , points
242               , group
243         );
244
245         if(before < after)
246             debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
247
248         if((before - after) > st->entries * st->update_every)
249             debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
250     }
251
252
253     // -------------------------------------------------------------------------
254     // temp arrays for keeping values per dimension
255
256     calculated_number group_values[dimensions]; // keep sums when grouping
257     int               print_hidden[dimensions]; // keep hidden flags
258     int               found_non_zero[dimensions];
259     int               found_non_existing[dimensions];
260
261     // initialize them
262     for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
263         group_values[c] = 0;
264         print_hidden[c] = rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?1:0;
265         found_non_zero[c] = 0;
266         found_non_existing[c] = 0;
267     }
268
269
270     // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
271     // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
272     // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
273
274     // -------------------------------------------------------------------------
275     // remove dimensions that contain only zeros
276
277     int max_loop = 1;
278     if(only_non_zero) max_loop = 2;
279
280     for(; max_loop ; max_loop--) {
281
282         // -------------------------------------------------------------------------
283         // print the JSON header
284
285         buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
286         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);
287         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);
288         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);
289
290         // print the header for each dimension
291         // and update the print_hidden array for the dimensions that should be hidden
292         int pc = 0;
293         for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
294             if(!print_hidden[c]) {
295                 pc++;
296                 buffer_sprintf(wb, ",\n     {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
297             }
298         }
299         if(!pc) {
300             buffer_sprintf(wb, ",\n     {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
301         }
302
303         // print the begin of row data
304         buffer_sprintf(wb, "\n  ],\n    %srows%s:\n [\n", kq, kq);
305
306
307         // -------------------------------------------------------------------------
308         // the main loop
309
310         int annotate_reset = 0;
311         int annotation_count = 0;
312
313         long    t = rrdset_time2slot(st, before),
314                 stop_at_t = rrdset_time2slot(st, after),
315                 stop_now = 0;
316
317         t -= t % group;
318
319         time_t  now = rrdset_slot2time(st, t),
320                 dt = st->update_every;
321
322         long count = 0, printed = 0, group_count = 0;
323         last_timestamp = 0;
324
325         if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
326             debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
327                   , st->id
328                   , (uint32_t)after
329                   , (uint32_t)before
330                   , points
331                   , group
332                   , st->current_entry
333                   , (uint32_t)rrdset_first_entry_t(st)
334                   , (uint32_t)rrdset_last_entry_t(st)
335                   , t
336                   , stop_at_t
337             );
338
339         long counter = 0;
340         for(; !stop_now ; now -= dt, t--, counter++) {
341             if(t < 0) t = st->entries - 1;
342             if(t == stop_at_t) stop_now = counter;
343
344             int print_this = 0;
345
346             if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
347                 debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
348                       , st->id
349                       , t
350                       , count + 1
351                       , group_count + 1
352                       , printed
353                       , now
354                       , (group_count + 1 == group)?"PRINT":"  -  "
355                       , (now >= after && now <= before)?"RANGE":"  -  "
356                 );
357
358
359             // make sure we return data in the proper time range
360             if(now > before) continue;
361             if(now < after) break;
362
363             //if(rrdset_slot2time(st, t) != now)
364             //  error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
365
366             count++;
367             group_count++;
368
369             // check if we have to print this now
370             if(group_count == group) {
371                 if(printed >= points) {
372                     // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
373                     break;
374                 }
375
376                 // generate the local date time
377                 struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
378                 if(!tm) { error("localtime() failed."); continue; }
379                 if(now > last_timestamp) last_timestamp = now;
380
381                 if(printed) buffer_strcat(wb, "]},\n");
382                 buffer_strcat(wb, pre_date);
383                 buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
384                 buffer_strcat(wb, post_date);
385
386                 print_this = 1;
387             }
388
389             // do the calculations
390             for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
391                 storage_number n = rd->values[t];
392                 calculated_number value = unpack_storage_number(n);
393
394                 if(!does_storage_number_exist(n)) {
395                     value = 0.0;
396                     found_non_existing[c]++;
397                 }
398                 if(did_storage_number_reset(n)) annotate_reset = 1;
399
400                 switch(group_method) {
401                     case GROUP_MAX:
402                         if(abs(value) > abs(group_values[c])) group_values[c] = value;
403                         break;
404
405                     case GROUP_SUM:
406                         group_values[c] += value;
407                         break;
408
409                     default:
410                     case GROUP_AVERAGE:
411                         group_values[c] += value;
412                         if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
413                         break;
414                 }
415             }
416
417             if(print_this) {
418                 if(annotate_reset) {
419                     annotation_count++;
420                     buffer_strcat(wb, overflow_annotation);
421                     annotate_reset = 0;
422                 }
423                 else
424                     buffer_strcat(wb, normal_annotation);
425
426                 pc = 0;
427                 for(c = 0 ; c < dimensions ; c++) {
428                     if(found_non_existing[c] == group_count) {
429                         // all entries are non-existing
430                         pc++;
431                         buffer_strcat(wb, pre_value);
432                         buffer_strcat(wb, "null");
433                         buffer_strcat(wb, post_value);
434                     }
435                     else if(!print_hidden[c]) {
436                         pc++;
437                         buffer_strcat(wb, pre_value);
438                         buffer_rrd_value(wb, group_values[c]);
439                         buffer_strcat(wb, post_value);
440
441                         if(group_values[c]) found_non_zero[c]++;
442                     }
443
444                     // reset them for the next loop
445                     group_values[c] = 0;
446                     found_non_existing[c] = 0;
447                 }
448
449                 // if all dimensions are hidden, print a null
450                 if(!pc) {
451                     buffer_strcat(wb, pre_value);
452                     buffer_strcat(wb, "null");
453                     buffer_strcat(wb, post_value);
454                 }
455
456                 printed++;
457                 group_count = 0;
458             }
459         }
460
461         if(printed) buffer_strcat(wb, "]}");
462         buffer_strcat(wb, "\n   ]\n}\n");
463
464         if(only_non_zero && max_loop > 1) {
465             int changed = 0;
466             for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
467                 group_values[c] = 0;
468                 found_non_existing[c] = 0;
469
470                 if(!print_hidden[c] && !found_non_zero[c]) {
471                     changed = 1;
472                     print_hidden[c] = 1;
473                 }
474             }
475
476             if(changed) buffer_flush(wb);
477             else break;
478         }
479         else break;
480
481     } // max_loop
482
483     debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %zu bytes", st->name, wb->len);
484
485     rrdset_unlock(st);
486     return last_timestamp;
487 }