@cryptotaxi247 / netdata-1 / commits / 9fde950a8

added support for /nonzero option to chart, which shows only dimensions which have data; this still needs some work on the javascript to be fully supported

Costa Tsaousis (ktsaou) committed May 14, 2014 at 01:23 UTC 9fde950a89dea7edb6faf8a4839dfbb20678f87b
1 file changed +161 -119
netdata.c
+161 -119
@@ -1769,6 +1769,7 @@ struct web_buffer {
1769 };
1770
1771 #define web_buffer_printf(wb, args...) wb->bytes += snprintf(&wb->buffer[wb->bytes], (wb->size - wb->bytes), ##args)
1772 +#define web_buffer_reset(wb) wb->buffer[wb->bytes = 0] = '\0'
1773
1774 void web_buffer_strcpy(struct web_buffer *wb, const char *txt)
1775 {
@@ -2168,6 +2169,7 @@ void rrd_stats_all_json(struct web_buffer *wb)
2169
2170 web_buffer_printf(wb, RRD_GRAPH_JSON_HEADER);
2171
2172 + pthread_rwlock_rdlock(&root_rwlock);
2173 for(st = root, c = 0; st ; st = st->next) {
2174 if(st->enabled) {
2175 if(c) web_buffer_printf(wb, "%s", ",\n");
@@ -2175,6 +2177,7 @@ void rrd_stats_all_json(struct web_buffer *wb)
2177 c++;
2178 }
2179 }
2180 + pthread_rwlock_unlock(&root_rwlock);
2181
2182 web_buffer_printf(wb, "\n\t],\n"
2183 "\t\"hostname\": \"%s\",\n"
@@ -2189,7 +2192,7 @@ void rrd_stats_all_json(struct web_buffer *wb)
2192 );
2193 }
2194
2192 -unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int entries_to_show, int group, int group_method, time_t after, time_t before)
2195 +unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int entries_to_show, int group, int group_method, time_t after, time_t before, int only_non_zero)
2196 {
2197 int c;
2198 pthread_rwlock_rdlock(&st->rwlock);
@@ -2230,6 +2233,12 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int
2233 if(before == 0) before = st->last_updated.tv_sec;
2234 if(after == 0) after = rrd_stats_first_entry_t(st);
2235
2236 + // ---
2237 +
2238 + // our return value (the last timestamp printed)
2239 + // this is required to detect re-transmit in google JSONP
2240 + time_t last_timestamp = 0;
2241 +
2242
2243 // -------------------------------------------------------------------------
2244 // find how many dimensions we have
@@ -2244,24 +2253,6 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int
2253 }
2254
2255
2247 - // -------------------------------------------------------------------------
2248 - // print the JSON header
2249 -
2250 - web_buffer_printf(wb, "{\n %scols%s:\n [\n", kq, kq);
2251 - web_buffer_printf(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);
2252 - web_buffer_printf(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);
2253 - web_buffer_printf(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);
2254 -
2255 - // print the header for each dimension
2256 - // and update the print_hidden array for the dimensions that should be hidden
2257 - for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2258 - if(!rd->hidden) web_buffer_printf(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);
2259 - }
2260 -
2261 - // print the begin of row data
2262 - web_buffer_printf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
2263 -
2264 -
2256 // -------------------------------------------------------------------------
2257 // prepare various strings, to speed up the loop
2258
@@ -2304,139 +2295,184 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int
2295 calculated_number group_values[dimensions]; // keep sums when grouping
2296 storage_number print_values[dimensions]; // keep the final value to be printed
2297 int print_hidden[dimensions]; // keep hidden flags
2298 + int found_non_zero[dimensions];
2299
2300 // initialize them
2301 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2302 group_values[c] = print_values[c] = 0;
2303 print_hidden[c] = rd->hidden;
2304 + found_non_zero[c] = 0;
2305 }
2306
2307 // -------------------------------------------------------------------------
2315 - // the main loop
2308 + // remove dimensions that contain only zeros
2309
2317 - // our return value (the last timestamp printed)
2318 - // this is required to detect re-transmit in google JSONP
2319 - time_t last_timestamp = 0;
2320 -
2321 - int annotate_reset = 0;
2322 - int annotation_count = 0;
2323 -
2324 - // to allow grouping on the same values, we need a pad
2325 - long pad = before % group;
2310 + int max_loop = 1;
2311 + if(only_non_zero) max_loop = 2;
2312
2327 - // the minimum line length we expect
2328 - int line_size = 4096 + (dimensions * 200);
2313 + for(; max_loop ; max_loop--) {
2314
2330 - unsigned long long time_usec = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
2331 - long t, count, printed, group_count;
2332 -
2333 - for (count = printed = group_count = 0, t = current_entry; max_entries ; time_usec -= st->timediff[t], t--, max_entries--) {
2334 - if(t < 0) t = st->entries - 1;
2335 -
2336 - if(st->debug)
2337 - if(st->timediff[t] == 0) debug(D_RRD_STATS, "WARNING: %s time diff is zero at position %ld", st->id, t);
2338 -
2339 - int print_this = 0;
2340 - time_t now = time_usec / 1000000ULL;
2341 -
2342 - if(st->debug) {
2343 - debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %lu, %s %s"
2344 - , st->id
2345 - , t
2346 - , count + 1
2347 - , group_count + 1
2348 - , printed
2349 - , now
2350 - , (((count + 1 - pad) % group) == 0)?"PRINT":" - "
2351 - , (now >= after && now <= before)?"RANGE":" - "
2352 - );
2315 + // -------------------------------------------------------------------------
2316 + // print the JSON header
2317 +
2318 + web_buffer_printf(wb, "{\n %scols%s:\n [\n", kq, kq);
2319 + web_buffer_printf(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);
2320 + web_buffer_printf(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);
2321 + web_buffer_printf(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);
2322 +
2323 + // print the header for each dimension
2324 + // and update the print_hidden array for the dimensions that should be hidden
2325 + for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2326 + if(!print_hidden[c])
2327 + web_buffer_printf(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);
2328 }
2329
2355 - // make sure we return data in the proper time range
2356 - if(now < after || now > before) continue;
2330 + // print the begin of row data
2331 + web_buffer_printf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
2332
2358 - count++;
2359 - group_count++;
2333
2361 - if(((count - pad) % group) == 0) {
2362 - if(printed >= entries_to_show) {
2363 - // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
2364 - break;
2365 - }
2366 -
2367 - if(group_count != group) {
2368 - // this is an incomplete group, skip it.
2369 - for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
2370 - group_values[c] = 0;
2371 -
2372 - group_count = 0;
2373 - continue;
2374 - }
2334 + // -------------------------------------------------------------------------
2335 + // the main loop
2336
2376 - // check if we may exceed the buffer provided
2377 - web_buffer_increase(wb, line_size);
2337 + int annotate_reset = 0;
2338 + int annotation_count = 0;
2339 +
2340 + // to allow grouping on the same values, we need a pad
2341 + long pad = before % group;
2342
2379 - // generate the local date time
2380 - struct tm *tm = localtime(&now);
2381 - if(!tm) { error("localtime() failed."); continue; }
2382 - if(now > last_timestamp) last_timestamp = now;
2343 + // the minimum line length we expect
2344 + int line_size = 4096 + (dimensions * 200);
2345
2384 - if(printed) web_buffer_strcpy(wb, "]},\n");
2385 - web_buffer_strcpy(wb, pre_date);
2386 - web_buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)((time_usec % 1000000ULL) / 1000));
2387 - web_buffer_strcpy(wb, post_date);
2346 + unsigned long long time_usec = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
2347 + long t;
2348
2389 - print_this = 1;
2390 - }
2349 + long count = 0, printed = 0, group_count = 0;
2350 + last_timestamp = 0;
2351 + for(t = current_entry; max_entries ; time_usec -= st->timediff[t], t--, max_entries--) {
2352 + if(t < 0) t = st->entries - 1;
2353
2392 - for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2393 - long value = rd->values[t];
2394 -
2395 - switch(group_method) {
2396 - case GROUP_MAX:
2397 - if(abs(value) > abs(group_values[c])) group_values[c] = value;
2398 - break;
2354 + if(st->debug)
2355 + if(st->timediff[t] == 0) debug(D_RRD_STATS, "WARNING: %s time diff is zero at position %ld", st->id, t);
2356
2400 - default:
2401 - case GROUP_AVERAGE:
2402 - group_values[c] += value;
2403 - if(print_this) group_values[c] /= group_count;
2357 + int print_this = 0;
2358 + time_t now = time_usec / 1000000ULL;
2359 +
2360 + if(st->debug) {
2361 + debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %lu, %s %s"
2362 + , st->id
2363 + , t
2364 + , count + 1
2365 + , group_count + 1
2366 + , printed
2367 + , now
2368 + , (((count + 1 - pad) % group) == 0)?"PRINT":" - "
2369 + , (now >= after && now <= before)?"RANGE":" - "
2370 + );
2371 + }
2372 +
2373 + // make sure we return data in the proper time range
2374 + if(now < after || now > before) continue;
2375 +
2376 + count++;
2377 + group_count++;
2378 +
2379 + if(((count - pad) % group) == 0) {
2380 + if(printed >= entries_to_show) {
2381 + // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
2382 break;
2383 + }
2384 +
2385 + if(group_count != group) {
2386 + // this is an incomplete group, skip it.
2387 + for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
2388 + group_values[c] = 0;
2389 +
2390 + group_count = 0;
2391 + continue;
2392 + }
2393 +
2394 + // check if we may exceed the buffer provided
2395 + web_buffer_increase(wb, line_size);
2396 +
2397 + // generate the local date time
2398 + struct tm *tm = localtime(&now);
2399 + if(!tm) { error("localtime() failed."); continue; }
2400 + if(now > last_timestamp) last_timestamp = now;
2401 +
2402 + if(printed) web_buffer_strcpy(wb, "]},\n");
2403 + web_buffer_strcpy(wb, pre_date);
2404 + web_buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)((time_usec % 1000000ULL) / 1000));
2405 + web_buffer_strcpy(wb, post_date);
2406 +
2407 + print_this = 1;
2408 + }
2409 +
2410 + for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2411 + long value = rd->values[t];
2412 +
2413 + switch(group_method) {
2414 + case GROUP_MAX:
2415 + if(abs(value) > abs(group_values[c])) group_values[c] = value;
2416 + break;
2417 +
2418 + default:
2419 + case GROUP_AVERAGE:
2420 + group_values[c] += value;
2421 + if(print_this) group_values[c] /= group_count;
2422 + break;
2423 + }
2424 +
2425 + if(print_this) {
2426 + print_values[c] = group_values[c];
2427 + group_values[c] = 0;
2428 + }
2429 }
2430
2431 if(print_this) {
2408 - print_values[c] = group_values[c];
2409 - group_values[c] = 0;
2432 + group_count = 0;
2433 +
2434 + if(annotate_reset) {
2435 + annotation_count++;
2436 + web_buffer_strcpy(wb, overflow_annotation);
2437 + annotate_reset = 0;
2438 + }
2439 + else
2440 + web_buffer_strcpy(wb, normal_annotation);
2441 +
2442 + for(c = 0 ; c < dimensions ; c++) {
2443 + if(!print_hidden[c]) {
2444 + web_buffer_strcpy(wb, pre_value);
2445 + web_buffer_rrd_value(wb, print_values[c]);
2446 + web_buffer_strcpy(wb, post_value);
2447 +
2448 + if(print_values[c]) found_non_zero[c]++;
2449 + }
2450 + }
2451 +
2452 + printed++;
2453 }
2454 }
2455
2413 - if(print_this) {
2414 - group_count = 0;
2415 -
2416 - if(annotate_reset) {
2417 - annotation_count++;
2418 - web_buffer_strcpy(wb, overflow_annotation);
2419 - annotate_reset = 0;
2420 - }
2421 - else
2422 - web_buffer_strcpy(wb, normal_annotation);
2456 + if(printed) web_buffer_printf(wb, "]}");
2457 + web_buffer_printf(wb, "\n ]\n}\n");
2458
2424 - for(c = 0 ; c < dimensions ; c++) {
2425 - if(!print_hidden[c]) {
2426 - web_buffer_strcpy(wb, pre_value);
2427 - web_buffer_rrd_value(wb, print_values[c]);
2428 - web_buffer_strcpy(wb, post_value);
2459 + if(only_non_zero && max_loop > 1) {
2460 + int changed = 0;
2461 + for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2462 + if(!print_hidden[c] && !found_non_zero[c]) {
2463 + changed = 1;
2464 + print_hidden[c] = 1;
2465 }
2466 }
2467
2432 - printed++;
2468 + if(changed) web_buffer_reset(wb);
2469 + else break;
2470 }
2434 - }
2435 -
2436 - if(printed) web_buffer_printf(wb, "]}");
2437 - web_buffer_printf(wb, "\n ]\n}\n");
2471 + else break;
2472 +
2473 + } // max_loop
2474
2439 - debug(D_RRD_STATS, "RRD_STATS_JSON: %s Generated %ld rows, total %ld bytes", st->name, printed, wb->bytes);
2475 + debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %ld bytes", st->name, wb->bytes);
2476
2477 pthread_rwlock_unlock(&st->rwlock);
2478 return last_timestamp;
@@ -2733,6 +2769,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
2769 long group_count = 1;
2770 time_t after = 0, before = 0;
2771 int group_method = GROUP_AVERAGE;
2772 + int nonzero = 0;
2773
2774 if(url) {
2775 // parse the lines required
@@ -2766,6 +2803,11 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
2803 if(tok) before = strtoul(tok, NULL, 10);
2804 if(before < 0) before = 0;
2805 }
2806 + if(url) {
2807 + // parse nonzero
2808 + tok = mystrsep(&url, "/");
2809 + if(tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
2810 + }
2811
2812 w->data->contenttype = CT_APPLICATION_JSON;
2813 w->data->bytes = 0;
@@ -2835,7 +2877,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
2877 }
2878
2879 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %lu after, %lu before).", w->id, st->name, st->id, lines, group_count, group_method, after, before);
2838 - unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method, after, before);
2880 + unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method, after, before, nonzero);
2881
2882 if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
2883 if(timestamp_in_data > last_timestamp_in_data)