@cryptotaxi247 / netdata-1 / commits / 4093d4851

added support for grouping values (average, max)

Costa Tsaousis (ktsaou) committed Mar 23, 2014 at 03:31 UTC 4093d485190ffe324760707c9d837db34e5a6ba7
2 files changed +106 -43
netdata.c
+97 -40
@@ -32,11 +32,11 @@
32
33
34 // internal defaults
35 -#define UPDATE_EVERY 2
35 +#define UPDATE_EVERY 1
36 #define UPDATE_EVERY_MAX 3600
37 #define LISTEN_PORT 19999
38 -#define HISTORY 120
39 -#define HISTORY_MAX 86400
38 +#define HISTORY 3600
39 +#define HISTORY_MAX (86400*10)
40 #define SAVE_PATH "/tmp"
41
42 #define D_WEB_BUFFER 0x00000001
@@ -405,36 +405,54 @@ void rrd_stats_dimension_set(RRD_STATS *st, const char *dimension, void *data)
405 }
406
407 if(rd->bytes == sizeof(unsigned long long)) {
408 - unsigned long long *dimension = rd->values, *value = data;
408 + long long *dimension = rd->values, *value = data;
409
410 dimension[st->last_entry] = (*value);
411 }
412 else if(rd->bytes == sizeof(unsigned long)) {
413 - unsigned long *dimension = rd->values, *value = data;
413 + long *dimension = rd->values, *value = data;
414
415 dimension[st->last_entry] = (*value);
416 }
417 else if(rd->bytes == sizeof(unsigned int)) {
418 - unsigned int *dimension = rd->values, *value = data;
418 + int *dimension = rd->values, *value = data;
419
420 dimension[st->last_entry] = (*value);
421 }
422 else if(rd->bytes == sizeof(unsigned char)) {
423 - unsigned char *dimension = rd->values, *value = data;
423 + char *dimension = rd->values, *value = data;
424
425 dimension[st->last_entry] = (*value);
426 }
427 else fatal("I don't know how to handle data of length %d bytes.", rd->bytes);
428 }
429
430 -size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_show)
430 +#define GROUP_AVERAGE 0
431 +#define GROUP_MAX 1
432 +
433 +size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_show, size_t group_count, int group_method)
434 {
432 - size_t i = 0, t, lt, c;
435 + size_t i = 0, c, t, lt, printed = 0, dimensions = 0, last_entry = st->last_entry;
436 + int pad = 0;
437 long count = st->entries;
438 RRD_DIMENSION *rd;
439 unsigned long long usec = 0;
440 + long long value;
441 char dtm[1025];
442
443 + // find how many dimensions we have
444 + for( rd = st->dimensions ; rd ; rd = rd->next)
445 + dimensions++;
446 +
447 + if(!dimensions)
448 + return sprintf(b, "No dimensions yet.");
449 +
450 + // keep track of group values and counts
451 + long long group_values[dimensions];
452 + long long group_counts[dimensions];
453 + for( rd = st->dimensions, c = 0 ; rd ; rd = rd->next, c++)
454 + group_values[c] = group_counts[c] = 0;
455 +
456 i += sprintf(&b[i], "{\n \"cols\":\n [\n");
457 i += sprintf(&b[i], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"timeofday\"},\n");
458
@@ -443,8 +461,11 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
461
462 i += sprintf(&b[i], " ],\n \"rows\":\n [\n");
463
446 - // find the old entry
447 - t = st->last_entry + 1;
464 + // to allow grouping on the same values, we need a pad
465 + pad = last_entry % group_count;
466 +
467 + // find the old entry of the round-robin
468 + t = last_entry + 1;
469 if(t >= st->entries) t = 0;
470 lt = t;
471
@@ -452,9 +473,9 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
473 t++;
474 if(t >= st->entries) t = 0;
475
455 - count -= 2;
476 // the loop in dimension data
457 - for ( c = 0 ; t != st->last_entry ; lt = t++, count--) {
477 + count -= 2;
478 + for ( ; t != last_entry ; lt = t++, count--) {
479 if(t >= st->entries) t = 0;
480
481 // if the last is empty, loop again
@@ -463,48 +484,69 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
484 // check if we may exceed the buffer provided
485 if((length - i) < 1024) break;
486
466 - if(count > entries_to_show) continue;
487 + if(((count-pad) / group_count) > entries_to_show) continue;
488
489 // find how much usec since the previous entry
490 usec = usecdiff(&st->times[t], &st->times[lt]);
491
471 - // generate the local date time
472 - struct tm *tm = localtime(&st->times[t].tv_sec);
473 - if(!tm) { error("localtime() failed."); continue; }
492 + if(((count-pad) % group_count) == 0) {
493 + if(printed >= entries_to_show) break;
494
475 - strftime(dtm, 1024, "[%H, %M, %S, 0]", tm);
476 - i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s},", c?",\n":"", dtm);
495 + // generate the local date time
496 + struct tm *tm = localtime(&st->times[t].tv_sec);
497 + if(!tm) { error("localtime() failed."); continue; }
498
478 - for( rd = st->dimensions ; rd ; rd = rd->next) {
479 - if(rd->bytes == sizeof(unsigned long long)) {
480 - unsigned long long *dimension = rd->values, v;
481 - v = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
499 + strftime(dtm, 1024, "[%H, %M, %S, 0]", tm);
500 + i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s},", printed?"]},\n":"", dtm);
501 +
502 + printed++;
503 + }
504 +
505 + for( rd = st->dimensions, c = 0 ; rd ; rd = rd->next, c++) {
506 + // check if new dimensions have been added since we started
507 + if(c >= dimensions)
508 + return sprintf(b, "New dimensions added while we were working on them. Try again later.");
509
483 - i += sprintf(&b[i], "{\"v\":%lld}%s", v, rd->next?",":"");
510 + if(rd->bytes == sizeof(unsigned long long)) {
511 + long long *dimension = rd->values;
512 + value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
513 }
514 else if(rd->bytes == sizeof(unsigned long)) {
486 - unsigned long *dimension = rd->values, v;
487 - v = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
488 -
489 - i += sprintf(&b[i], "{\"v\":%ld}%s", v, rd->next?",":"");
515 + long *dimension = rd->values;
516 + value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
517 }
518 else if(rd->bytes == sizeof(unsigned int)) {
492 - unsigned int *dimension = rd->values, v;
493 - v = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
494 -
495 - i += sprintf(&b[i], "{\"v\":%d}%s", v, rd->next?",":"");
519 + int *dimension = rd->values;
520 + value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
521 }
522 else if(rd->bytes == sizeof(unsigned char)) {
498 - unsigned char *dimension = rd->values, v;
499 - v = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
523 + char *dimension = rd->values;
524 + value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
525 + }
526 + else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
527 +
528 + switch(group_method) {
529 + case GROUP_MAX:
530 + if(value > group_values[c]) group_values[c] = value;
531 + break;
532
501 - i += sprintf(&b[i], "{\"v\":%d}%s", (int)v, rd->next?",":"");
533 + default:
534 + case GROUP_AVERAGE:
535 + group_values[c] += value;
536 + break;
537 + }
538 + group_counts[c]++;
539 +
540 + if(((count-pad) % group_count) == 0) {
541 + if(group_method == GROUP_AVERAGE) group_values[c] /= group_counts[c];
542 +
543 + i += sprintf(&b[i], "{\"v\":%lld}%s", group_values[c], rd->next?",":"");
544 +
545 + group_values[c] = group_counts[c] = 0;
546 }
503 - else fatal("Cannot produce JSON for size %d bytes data.", rd->bytes);
547 }
505 - i += sprintf(&b[i], "]}");
506 - c++;
548 }
549 + if(printed) i += sprintf(&b[i], "]}");
550 i += sprintf(&b[i], "\n ]\n}\n");
551
552 if(count != 0) error("RRD count should be zero, but found to be %d.", count);
@@ -795,17 +837,32 @@ void web_client_process(struct web_client *w)
837
838 // how many entries does the client want?
839 size_t lines = save_history;
840 + size_t group_count = 1;
841 + int group_method = GROUP_AVERAGE;
842 +
843 if(url) {
844 tok = mystrsep(&url, "/?");
845 if(tok) lines = atoi(tok);
846 if(lines < 5) lines = save_history;
847 }
848 + if(url) {
849 + tok = mystrsep(&url, "/?");
850 + if(tok) group_count = atoi(tok);
851 + if(group_count < 1) group_count = 1;
852 + if(group_count > save_history / 20) group_count = save_history / 20;
853 + }
854 + if(url) {
855 + tok = mystrsep(&url, "/?");
856 + if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
857 + else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
858 + else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", tok);
859 + }
860
804 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (%d lines).", w->id, st->name, lines);
861 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (%d lines, %d group_count, %d group_method).", w->id, st->name, lines, group_count, group_method);
862
863 code = 200;
864 w->data->contenttype = CT_APPLICATION_JSON;
808 - w->data->bytes = rrd_stats_json(st, w->data->buffer, w->data->size, lines);
865 + w->data->bytes = rrd_stats_json(st, w->data->buffer, w->data->size, lines, group_count, group_method);
866 }
867 }
868 else if(strcmp(tok, "mirror") == 0) {
netdata.start
+9 -3
@@ -9,9 +9,12 @@ then
9 fi
10 cd "$base" || exit 1
11
12 -# every how many seconds to update the JSON files
12 +# every how many seconds to show the graphs
13 NETDATA_CONFIG_UPDATE_EVERY=2
14
15 +# the detail of the data that will be kept in netdata
16 +NETDATA_CONFIG_INTERNAL_UPDATE_EVERY=1
17 +
18 # how many points should the graphs have
19 NETDATA_CONFIG_HISTORY_POINTS=120
20
@@ -28,6 +31,9 @@ then
31 source netdata.conf
32 fi
33
34 +# how many history lines to keep in netdata
35 +NETDATA_HISTORY_LINES=$[NETDATA_CONFIG_UPDATE_EVERY * NETDATA_CONFIG_HISTORY_POINTS / NETDATA_CONFIG_INTERNAL_UPDATE_EVERY]
36 +
37 echo "Creating a directory for netdata..."
38 data=
39 for x in /run/netdata /var/run/netdata /tmp/netdata
@@ -80,7 +86,7 @@ gcc -Wall -O3 -o netdata netdata.c -lpthread || exit 1
86 echo "Starting netdata"
87 p=`pwd`
88 cd data
83 -$p/netdata -d -u $NETDATA_CONFIG_UPDATE_EVERY -l $NETDATA_CONFIG_HISTORY_DATA || exit 1
89 +$p/netdata -d -u $NETDATA_CONFIG_INTERNAL_UPDATE_EVERY -l $NETDATA_HISTORY_LINES || exit 1
90 cd "$p"
91
92 sleep 1
@@ -175,7 +181,7 @@ do
181 if [ ! "$p" = "IGNORE" ]
182 then
183 cat >>${data}/index.html <<EOF2
178 - drawChart('${x}', '${y}_div', width, height, "data/${x}/${NETDATA_CONFIG_HISTORY_POINTS}", "${t}");
184 + drawChart('${x}', '${y}_div', width, height, "data/${x}/${NETDATA_CONFIG_HISTORY_POINTS}/${NETDATA_CONFIG_UPDATE_EVERY}/average/", "${t}");
185 EOF2
186 fi
187 done