fixed white space on mobile devices, added cpu graphs
Costa Tsaousis (ktsaou) committed
Apr 2, 2014 at 01:21 UTC
f97b71f1e44d0195c980fc564d4b3b11a3e98147
4 files changed
+337
-58
netdata.c
+281
-33
@@ -33,6 +33,7 @@
33
34
#define RRD_DIMENSION_ABSOLUTE 0
35
#define RRD_DIMENSION_INCREMENTAL 1
36
+#define RRD_DIMENSION_PCENT_OVER_TOTAL 2
37
38
#define RRD_TYPE_NET "net"
39
#define RRD_TYPE_NET_LEN strlen(RRD_TYPE_NET)
@@ -52,6 +53,9 @@
53
#define RRD_TYPE_NET_IPVS "ipvs"
54
#define RRD_TYPE_NET_IPVS_LEN strlen(RRD_TYPE_NET_IPVS)
55
56
+#define RRD_TYPE_STAT "cpu"
57
+#define RRD_TYPE_STAT_LEN strlen(RRD_TYPE_STAT)
58
+
59
#define WEB_PATH_FILE "file"
60
#define WEB_PATH_DATA "data"
61
#define WEB_PATH_GRAPH "graph"
@@ -120,6 +124,9 @@
124
#define MAX_PROC_NET_IPVS_LINE 4096
125
#define MAX_PROC_NET_IPVS_NAME 1024
126
127
+#define MAX_PROC_STAT_LINE 4096
128
+#define MAX_PROC_STAT_NAME 1024
129
+
130
131
int silent = 0;
132
int save_history = HISTORY;
@@ -131,7 +138,7 @@ int listen_port = LISTEN_PORT;
138
// helpers
139
140
unsigned long long usecdiff(struct timeval *now, struct timeval *last) {
134
- return ((((now->tv_sec * 1000000) + now->tv_usec) - ((last->tv_sec * 1000000) + last->tv_usec)));
141
+ return ((((now->tv_sec * 1000000L) + now->tv_usec) - ((last->tv_sec * 1000000L) + last->tv_usec)));
142
}
143
144
// ----------------------------------------------------------------------------
@@ -338,6 +345,7 @@ struct rrd_dimension {
345
size_t entries;
346
347
int type;
348
+ int hidden; // if set to non zero, this dimension will not be sent to the client
349
350
long multiplier;
351
long divisor;
@@ -592,6 +600,19 @@ void rrd_stats_done(RRD_STATS *st)
600
pthread_mutex_unlock(&st->mutex);
601
}
602
603
+int rrd_stats_dimension_hide(RRD_STATS *st, const char *id)
604
+{
605
+ RRD_DIMENSION *rd = rrd_stats_dimension_find(st, id);
606
+ if(!rd) {
607
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
608
+ return 1;
609
+ }
610
+
611
+ rd->hidden = 1;
612
+ return 0;
613
+}
614
+
615
+
616
int rrd_stats_dimension_set(RRD_STATS *st, const char *id, void *data)
617
{
618
RRD_DIMENSION *rd = rrd_stats_dimension_find(st, id);
@@ -640,7 +661,7 @@ size_t rrd_stats_one_json(RRD_STATS *st, char *options, char *buffer, size_t len
661
i += sprintf(&buffer[i], "\t\t\t\"name\" : \"%s\",\n", st->name);
662
i += sprintf(&buffer[i], "\t\t\t\"type\" : \"%s\",\n", st->type);
663
i += sprintf(&buffer[i], "\t\t\t\"title\" : \"%s %s\",\n", st->title, st->name);
643
- i += sprintf(&buffer[i], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->name);
664
+ i += sprintf(&buffer[i], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->id);
665
i += sprintf(&buffer[i], "\t\t\t\"userpriority\" : \"%s\",\n", st->userpriority);
666
i += sprintf(&buffer[i], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
667
i += sprintf(&buffer[i], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
@@ -685,6 +706,29 @@ size_t rrd_stats_all_json(char *buffer, size_t len)
706
return(i);
707
}
708
709
+long long rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
710
+{
711
+ if(rd->bytes == sizeof(long long)) {
712
+ long long *dimension = rd->values;
713
+ return(dimension[position]);
714
+ }
715
+ else if(rd->bytes == sizeof(long)) {
716
+ long *dimension = rd->values;
717
+ return(dimension[position]);
718
+ }
719
+ else if(rd->bytes == sizeof(int)) {
720
+ int *dimension = rd->values;
721
+ return(dimension[position]);
722
+ }
723
+ else if(rd->bytes == sizeof(char)) {
724
+ char *dimension = rd->values;
725
+ return(dimension[position]);
726
+ }
727
+ else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
728
+
729
+ return(0);
730
+}
731
+
732
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)
733
{
734
pthread_mutex_lock(&st->mutex);
@@ -709,9 +753,13 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
753
unsigned long long usec = 0;// usec between the entries
754
char dtm[201]; // temp variable for storing dates
755
756
+ int we_need_totals = 0; // if set, we should calculate totals for all dimensions
757
+
758
// find how many dimensions we have
713
- for( rd = st->dimensions ; rd ; rd = rd->next)
759
+ for( rd = st->dimensions ; rd ; rd = rd->next) {
760
dimensions++;
761
+ if(rd->type == RRD_DIMENSION_PCENT_OVER_TOTAL) we_need_totals++;
762
+ }
763
764
if(!dimensions) {
765
pthread_mutex_unlock(&st->mutex);
@@ -725,10 +773,11 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
773
group_values[c] = group_counts[c] = 0;
774
775
i += sprintf(&b[i], "{\n \"cols\":\n [\n");
728
- i += sprintf(&b[i], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"},\n");
776
+ i += sprintf(&b[i], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"}");
777
778
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
731
- i += sprintf(&b[i], " {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}%s\n", rd->name, rd->next?",":"");
779
+ if(!rd->hidden)
780
+ i += sprintf(&b[i], ",\n {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}", rd->name);
781
782
i += sprintf(&b[i], " ],\n \"rows\":\n [\n");
783
@@ -777,37 +826,31 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
826
sprintf(dtm, "\"Date(%d, %d, %d, %d, %d, %d, %d)\"", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(st->times[t].tv_usec / 1000)); // datetime
827
// strftime(dtm, 200, "\"Date(%Y, %m, %d, %H, %M, %S)\"", tm); // datetime
828
// strftime(dtm, 200, "[%H, %M, %S, 0]", tm); // timeofday
780
- i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s},", printed?"]},\n":"", dtm);
829
+ i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s}", printed?"]},\n":"", dtm);
830
831
printed++;
832
}
833
834
+ // if we need a PCENT_OVER_TOTAL, calculate the totals for the current and the last
835
+ long long total = 0, oldtotal = 0;
836
+ if(we_need_totals) {
837
+ for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
838
+ total += rrd_stats_dimension_get(rd, t);
839
+ oldtotal += rrd_stats_dimension_get(rd, lt);
840
+ }
841
+ }
842
+
843
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
786
- long long oldvalue = 0, value = 0; // temp variable for storing data values
844
+ long long oldvalue, value; // temp variable for storing data values
845
788
- if(rd->bytes == sizeof(long long)) {
789
- long long *dimension = rd->values;
790
- value = dimension[t];
791
- oldvalue = dimension[lt];
792
- }
793
- else if(rd->bytes == sizeof(long)) {
794
- long *dimension = rd->values;
795
- value = dimension[t];
796
- oldvalue = dimension[lt];
797
- }
798
- else if(rd->bytes == sizeof(int)) {
799
- int *dimension = rd->values;
800
- value = dimension[t];
801
- oldvalue = dimension[lt];
802
- }
803
- else if(rd->bytes == sizeof(char)) {
804
- char *dimension = rd->values;
805
- value = dimension[t];
806
- oldvalue = dimension[lt];
807
- }
808
- else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
846
+ value = rrd_stats_dimension_get(rd, t);
847
+ oldvalue = rrd_stats_dimension_get(rd, lt);
848
849
switch(rd->type) {
850
+ case RRD_DIMENSION_PCENT_OVER_TOTAL:
851
+ value = 100 * (value - oldvalue) / (total - oldtotal);
852
+ break;
853
+
854
case RRD_DIMENSION_INCREMENTAL:
855
if(oldvalue > value) value = 0; // detect overflows and resets
856
else value -= oldvalue;
@@ -834,7 +877,9 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
877
}
878
879
if(((count-pad) % group_count) == 0) {
837
- i += sprintf(&b[i], "{\"v\":%lld}%s", group_values[c], rd->next?",":"");
880
+ if(!rd->hidden)
881
+ i += sprintf(&b[i], ",{\"v\":%lld}", group_values[c]);
882
+
883
group_values[c] = group_counts[c] = 0;
884
}
885
}
@@ -1169,6 +1214,7 @@ void web_client_process(struct web_client *w)
1214
1215
// do we have such a data set?
1216
RRD_STATS *st = rrd_stats_find_byname(tok);
1217
+ if(!st) st = rrd_stats_find(tok);
1218
if(!st) {
1219
// we don't have it
1220
// try to send a file with that name
@@ -2000,11 +2046,11 @@ int do_proc_net_snmp() {
2046
if(r == EOF) break;
2047
if(r != 19) error("Cannot read /proc/net/snmp IP line. Expected 19 params, read %d.", r);
2048
2003
- RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".ip");
2049
+ RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".packets");
2050
if(!st) {
2005
- st = rrd_stats_create(RRD_TYPE_NET_SNMP ".ip", RRD_TYPE_NET_SNMP ".ip", save_history, "IPv4 Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2051
+ st = rrd_stats_create(RRD_TYPE_NET_SNMP ".packets", RRD_TYPE_NET_SNMP ".packets", save_history, "IPv4 Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2052
if(!st) {
2007
- error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".ip");
2053
+ error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".packets");
2054
continue;
2055
}
2056
@@ -2399,6 +2445,205 @@ int do_proc_net_ip_vs_stats() {
2445
return 0;
2446
}
2447
2448
+int do_proc_stat() {
2449
+ char buffer[MAX_PROC_STAT_LINE+1] = "";
2450
+
2451
+ FILE *fp = fopen("/proc/stat", "r");
2452
+ if(!fp) {
2453
+ error("Cannot read /proc/stat.");
2454
+ return 1;
2455
+ }
2456
+
2457
+ for(;1;) {
2458
+ char *p = fgets(buffer, MAX_PROC_STAT_LINE, fp);
2459
+ if(!p) break;
2460
+
2461
+ if(strncmp(p, "cpu", 3) == 0) {
2462
+ char id[MAX_PROC_STAT_NAME + 1] = RRD_TYPE_STAT ".";
2463
+ unsigned long long user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
2464
+ char *name = &id[RRD_TYPE_STAT_LEN + 1];
2465
+
2466
+ int r = sscanf(buffer, "%s %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
2467
+ name, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice);
2468
+
2469
+ if(r == EOF) break;
2470
+ if(r != 11) error("Cannot read /proc/stat cpu line. Expected 11 params, read %d.", r);
2471
+
2472
+ RRD_STATS *st = rrd_stats_find(id);
2473
+ if(!st) {
2474
+ st = rrd_stats_create(id, id, save_history, "Time for ", "Percentage", RRD_TYPE_STAT);
2475
+ if(!st) {
2476
+ error("Cannot create RRD_STATS for %s.", id);
2477
+ continue;
2478
+ }
2479
+
2480
+ if(strcmp(id, "cpu.cpu") == 0) strcpy(st->usertitle, "all CPUs");
2481
+ else strcpy(st->usertitle, name);
2482
+
2483
+ long multiplier = 1;
2484
+ long divisor = 1; // sysconf(_SC_CLK_TCK);
2485
+
2486
+ if(!rrd_stats_dimension_add(st, "iowait", "iowait", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2487
+ error("Cannot add RRD_STATS dimension %s.", "iowait");
2488
+
2489
+ if(!rrd_stats_dimension_add(st, "nice", "nice", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2490
+ error("Cannot add RRD_STATS dimension %s.", "nice");
2491
+
2492
+ if(!rrd_stats_dimension_add(st, "system", "system", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2493
+ error("Cannot add RRD_STATS dimension %s.", "system");
2494
+
2495
+ if(!rrd_stats_dimension_add(st, "user", "user", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2496
+ error("Cannot add RRD_STATS dimension %s.", "user");
2497
+
2498
+ if(!rrd_stats_dimension_add(st, "idle", "idle", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2499
+ error("Cannot add RRD_STATS dimension %s.", "idle");
2500
+ else rrd_stats_dimension_hide(st, "idle");
2501
+
2502
+ if(!rrd_stats_dimension_add(st, "irq", "irq", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2503
+ error("Cannot add RRD_STATS dimension %s.", "irq");
2504
+
2505
+ if(!rrd_stats_dimension_add(st, "softirq", "softirq", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2506
+ error("Cannot add RRD_STATS dimension %s.", "softirq");
2507
+
2508
+ if(!rrd_stats_dimension_add(st, "steal", "steal", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2509
+ error("Cannot add RRD_STATS dimension %s.", "steal");
2510
+
2511
+ if(!rrd_stats_dimension_add(st, "guest", "guest", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2512
+ error("Cannot add RRD_STATS dimension %s.", "guest");
2513
+
2514
+ if(!rrd_stats_dimension_add(st, "guest_nice", "guest_nice", sizeof(unsigned long long), multiplier, divisor, RRD_DIMENSION_PCENT_OVER_TOTAL))
2515
+ error("Cannot add RRD_STATS dimension %s.", "guest_nice");
2516
+
2517
+ }
2518
+ else rrd_stats_next(st);
2519
+
2520
+ rrd_stats_dimension_set(st, "user", &user);
2521
+ rrd_stats_dimension_set(st, "nice", &nice);
2522
+ rrd_stats_dimension_set(st, "system", &system);
2523
+ rrd_stats_dimension_set(st, "idle", &idle);
2524
+ rrd_stats_dimension_set(st, "iowait", &iowait);
2525
+ rrd_stats_dimension_set(st, "irq", &irq);
2526
+ rrd_stats_dimension_set(st, "softirq", &softirq);
2527
+ rrd_stats_dimension_set(st, "steal", &steal);
2528
+ rrd_stats_dimension_set(st, "guest", &guest);
2529
+ rrd_stats_dimension_set(st, "guest_nice", &guest_nice);
2530
+ rrd_stats_done(st);
2531
+ }
2532
+ else if(strncmp(p, "intr ", 5) == 0) {
2533
+ char id[MAX_PROC_STAT_NAME + 1] = RRD_TYPE_STAT ".";
2534
+ char *name = &id[RRD_TYPE_STAT_LEN + 1];
2535
+
2536
+ unsigned long long value;
2537
+
2538
+ int r = sscanf(buffer, "%s %llu ", name, &value);
2539
+ if(r == EOF) break;
2540
+ if(r != 2) error("Cannot read /proc/stat intr line. Expected 2 params, read %d.", r);
2541
+
2542
+ RRD_STATS *st = rrd_stats_find(id);
2543
+ if(!st) {
2544
+ st = rrd_stats_create(id, id, save_history, "CPU Interrupts", "interrupts/s", RRD_TYPE_STAT);
2545
+ if(!st) {
2546
+ error("Cannot create RRD_STATS for %s.", id);
2547
+ continue;
2548
+ }
2549
+
2550
+ if(!rrd_stats_dimension_add(st, "interrupts", "interrupts", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_INCREMENTAL))
2551
+ error("Cannot add RRD_STATS dimension %s.", "interrupts");
2552
+
2553
+ }
2554
+ else rrd_stats_next(st);
2555
+
2556
+ rrd_stats_dimension_set(st, "interrupts", &value);
2557
+ rrd_stats_done(st);
2558
+ }
2559
+ else if(strncmp(p, "ctxt ", 5) == 0) {
2560
+ char id[MAX_PROC_STAT_NAME + 1] = RRD_TYPE_STAT ".";
2561
+ char *name = &id[RRD_TYPE_STAT_LEN + 1];
2562
+
2563
+ unsigned long long value;
2564
+
2565
+ int r = sscanf(buffer, "%s %llu ", name, &value);
2566
+ if(r == EOF) break;
2567
+ if(r != 2) error("Cannot read /proc/stat ctxt line. Expected 2 params, read %d.", r);
2568
+
2569
+ RRD_STATS *st = rrd_stats_find(id);
2570
+ if(!st) {
2571
+ st = rrd_stats_create(id, id, save_history, "CPU Context Switches", "context switches/s", RRD_TYPE_STAT);
2572
+ if(!st) {
2573
+ error("Cannot create RRD_STATS for %s.", id);
2574
+ continue;
2575
+ }
2576
+
2577
+ if(!rrd_stats_dimension_add(st, "switches", "switches", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_INCREMENTAL))
2578
+ error("Cannot add RRD_STATS dimension %s.", "switches");
2579
+
2580
+ }
2581
+ else rrd_stats_next(st);
2582
+
2583
+ rrd_stats_dimension_set(st, "switches", &value);
2584
+ rrd_stats_done(st);
2585
+ }
2586
+ else if(strncmp(p, "processes ", 10) == 0) {
2587
+ char id[MAX_PROC_STAT_NAME + 1] = RRD_TYPE_STAT ".";
2588
+ char *name = &id[RRD_TYPE_STAT_LEN + 1];
2589
+
2590
+ unsigned long long value;
2591
+
2592
+ int r = sscanf(buffer, "%s %llu ", name, &value);
2593
+ if(r == EOF) break;
2594
+ if(r != 2) error("Cannot read /proc/stat processes line. Expected 2 params, read %d.", r);
2595
+
2596
+ RRD_STATS *st = rrd_stats_find(id);
2597
+ if(!st) {
2598
+ st = rrd_stats_create(id, id, save_history, "Started Processes", "processes started", RRD_TYPE_STAT);
2599
+ if(!st) {
2600
+ error("Cannot create RRD_STATS for %s.", id);
2601
+ continue;
2602
+ }
2603
+
2604
+ if(!rrd_stats_dimension_add(st, "started", "started", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_INCREMENTAL))
2605
+ error("Cannot add RRD_STATS dimension %s.", "started");
2606
+
2607
+ }
2608
+ else rrd_stats_next(st);
2609
+
2610
+ rrd_stats_dimension_set(st, "started", &value);
2611
+ rrd_stats_done(st);
2612
+ }
2613
+ else if(strncmp(p, "procs_running ", 14) == 0) {
2614
+ char id[MAX_PROC_STAT_NAME + 1] = RRD_TYPE_STAT ".";
2615
+ char *name = &id[RRD_TYPE_STAT_LEN + 1];
2616
+
2617
+ unsigned long long value;
2618
+
2619
+ int r = sscanf(buffer, "%s %llu ", name, &value);
2620
+ if(r == EOF) break;
2621
+ if(r != 2) error("Cannot read /proc/stat processes line. Expected 2 params, read %d.", r);
2622
+
2623
+ RRD_STATS *st = rrd_stats_find(id);
2624
+ if(!st) {
2625
+ st = rrd_stats_create(id, id, save_history, "CPU Running Processes", "processes running", RRD_TYPE_STAT);
2626
+ if(!st) {
2627
+ error("Cannot create RRD_STATS for %s.", id);
2628
+ continue;
2629
+ }
2630
+
2631
+ if(!rrd_stats_dimension_add(st, "running", "running", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_ABSOLUTE))
2632
+ error("Cannot add RRD_STATS dimension %s.", "running");
2633
+
2634
+ }
2635
+ else rrd_stats_next(st);
2636
+
2637
+ rrd_stats_dimension_set(st, "running", &value);
2638
+ rrd_stats_done(st);
2639
+ }
2640
+ }
2641
+
2642
+ fclose(fp);
2643
+ return 0;
2644
+}
2645
+
2646
+
2647
// ----------------------------------------------------------------------------
2648
// /proc processor
2649
@@ -2416,6 +2661,7 @@ void *proc_main(void *ptr)
2661
int vdo_proc_net_netstat = 0;
2662
int vdo_proc_net_stat_conntrack = 0;
2663
int vdo_proc_net_ip_vs_stats = 0;
2664
+ int vdo_proc_stat = 0;
2665
2666
for(;1;) {
2667
unsigned long long usec, susec;
@@ -2432,6 +2678,7 @@ void *proc_main(void *ptr)
2678
if(!vdo_proc_net_netstat) vdo_proc_net_netstat = do_proc_net_netstat(usec);
2679
if(!vdo_proc_net_stat_conntrack) vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(usec);
2680
if(!vdo_proc_net_ip_vs_stats) vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(usec);
2681
+ if(!vdo_proc_stat) vdo_proc_stat = do_proc_stat(usec);
2682
// END -- the job is done
2683
2684
// find the time to sleep in order to wait exactly update_every seconds
@@ -2716,6 +2963,7 @@ void sig_handler(int signo)
2963
case SIGQUIT:
2964
case SIGINT:
2965
case SIGHUP:
2966
+ case SIGSEGV:
2967
error("Signaled cleanup (signal %d).", signo);
2968
if(tc_child_pid) kill(tc_child_pid, SIGTERM);
2969
tc_child_pid = 0;
@@ -2874,7 +3122,7 @@ int main(int argc, char **argv)
3122
atexit(bye);
3123
3124
// catch all signals
2877
- for (i = 1 ; i < 65 ;i++) signal(i, sig_handler);
3125
+ for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV) signal(i, sig_handler);
3126
3127
3128
pthread_t p_proc, p_tc;
web/index.html
+29
-22
@@ -5,6 +5,8 @@
5
<meta charset="utf-8">
6
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7
<meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <meta name="apple-mobile-web-app-capable" content="yes">
9
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
10
<meta name="description" content="">
11
<meta name="author" content="costa@tsaousis.gr">
12
@@ -35,7 +37,7 @@
37
var mycharts = new Array();
38
var mainchart;
39
38
- function chartIsLoadingHTML(width, height) { return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading chart<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
40
+ function chartIsLoadingHTML(width, height) { return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading chart<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
41
42
function showChartIsLoading(id, width, height) { document.getElementById(id).innerHTML = chartIsLoadingHTML(width, height); }
43
@@ -53,19 +55,11 @@
55
56
mainchart.thumbnail = false;
57
mainchart.group = 5;
56
- mainchart.group_method = "max";
58
mainchart.div = 'maingraph';
59
mainchart.last_updated = 0;
60
mainchart.explorer = false;
61
61
- if(mainchart.type == "tc") {
62
- mainchart.group = 15;
63
- mainchart.group_method = "average";
64
- }
65
- else if(mainchart.type == "ipv4" || mainchart.type == "conntrack" || mainchart.type == "ipvs") {
66
- mainchart.group = 15;
67
- mainchart.group_method = "max";
68
- }
62
+ if(mainchart.chartOptions.isStacked) mainchart.group = 15;
63
64
// calculate the time to refresh each chart
65
mainchart.chart_update_every = mainchart.group * 1000; // milliseconds
@@ -150,6 +144,8 @@
144
var width = thumbWidth();
145
var height = 200;
146
147
+ document.getElementById('splash').height = $(window).height() * 0.95;
148
+
149
loadCharts(function(c) {
150
mycharts = c;
151
@@ -158,7 +154,7 @@
154
return;
155
}
156
161
- var thumbsContainer = document.getElementById("graphs");
157
+ var thumbsContainer = document.getElementById("thumbgraphs");
158
if(!thumbsContainer) {
159
alert("Cannot find the thumbsContainer");
160
return;
@@ -184,43 +180,41 @@
180
case "tc":
181
c.glyphicon = "glyphicon-transfer";
182
c.group = 30;
187
- c.group_method = "average";
183
break;
184
185
case "net":
186
c.glyphicon = "glyphicon-cloud";
187
c.group = 10;
193
- c.group_method = "max";
188
break;
189
190
case "ipv4":
191
c.glyphicon = "glyphicon-resize-full";
192
c.group = 30;
199
- c.group_method = "max";
193
break;
194
195
case "conntrack":
196
c.glyphicon = "glyphicon-eye-open";
197
c.group = 30;
205
- c.group_method = "max";
198
break;
199
200
case "ipvs":
201
c.glyphicon = "glyphicon-sort";
202
c.group = 30;
211
- c.group_method = "max";
203
break;
204
205
case "disk":
206
c.glyphicon = "glyphicon-floppy-disk";
207
c.group = 20;
217
- c.group_method = "max";
208
+ break;
209
+
210
+ case "cpu":
211
+ c.glyphicon = "glyphicon-search";
212
+ c.group = 10;
213
break;
214
215
default:
216
c.glyphicon = "glyphicon-search";
217
c.group = 60;
223
- c.group_method = "max";
218
break;
219
}
220
@@ -259,8 +253,9 @@
253
else if(a.name == "conntrack") a.priority = 3;
254
else if(a.name == "ipvs") a.priority = 4;
255
else if(a.name == "ipv4") a.priority = 5;
262
- else if(a.name == "disk") a.priority = 6;
263
- else a.priority = 4;
256
+ else if(a.name == "cpu") a.priority = 6;
257
+ else if(a.name == "disk") a.priority = 7;
258
+ else a.priority = 99;
259
260
a.html = "<tr><td><ol class=\"breadcrumb graphs\"><li class=\"active\"><span class=\"glyphicon " + a.glyphicon + "\"></span> <a id=\"" + a.name + "\" href=\"#" + a.name + "\"><b>" + a.title + "</b> " + a.description + " </a></li></ol></td></tr><tr><td><div class=\"thumbgraphs\">" + a.html + "</td></tr>";
261
});
@@ -401,8 +396,20 @@
396
</div>
397
398
<div class="container graphs" id="thumbgraphs_container">
404
- <div class="allgraphs" id="graphs">
405
- <table width="100%"><tr><td align="center"><p/> <p/> <p/> <h1><span class="glyphicon glyphicon-refresh"></span><br/><br/>loading charts<br/><br/><span class="label label-default">Please wait...</span></h1></td></tr></table>
399
+ <div class="allgraphs" id="thumbgraphs">
400
+ <table width="100%" height="95%">
401
+ <tr><td id="splash" align="center" style="vertical-align:middle">
402
+ <h1>
403
+ Welcome to <b>NetData</b>!
404
+ <br/><br/>
405
+ <span class="glyphicon glyphicon-refresh"></span>
406
+ <br/><br/>
407
+ loading charts
408
+ <br/><br/>
409
+ <span class="label label-default">Please wait...</span>
410
+ </h1>
411
+ </td></tr>
412
+ </table>
413
</div>
414
</div>
415
</html>
web/netdata.js
+18
-3
@@ -8,7 +8,10 @@ function refreshChart(chart, doNext) {
8
chart.refreshCount++;
9
10
if(chart.chart != null) {
11
- if(chart.chart.getSelection()[0]) return;
11
+ if(chart.chart.getSelection()[0]) {
12
+ if(typeof doNext == "function") doNext();
13
+ return;
14
+ }
15
}
16
17
var url = chart.url;
@@ -97,7 +100,15 @@ function loadCharts(doNext) {
100
};
101
102
// set the chart type
100
- if((json.charts[i].type == "ipv4" || json.charts[i].type == "ipv6" || json.charts[i].type == "ipvs" || json.charts[i].type == "conntrack")
103
+ if((json.charts[i].type == "ipv4"
104
+ || json.charts[i].type == "ipv6"
105
+ || json.charts[i].type == "ipvs"
106
+ || json.charts[i].type == "conntrack"
107
+ || json.charts[i].id == "cpu.ctxt"
108
+ || json.charts[i].id == "cpu.intr"
109
+ || json.charts[i].id == "cpu.processes"
110
+ || json.charts[i].id == "cpu.procs_running"
111
+ )
112
&& json.charts[i].name != "ipv4.net" && json.charts[i].name != "ipvs.net") {
113
114
// default for all LineChart
@@ -105,7 +116,7 @@ function loadCharts(doNext) {
116
json.charts[i].chartOptions.lineWidth = 3;
117
json.charts[i].chartOptions.curveType = 'function';
118
}
108
- else if(json.charts[i].type == "tc") {
119
+ else if(json.charts[i].type == "tc" || json.charts[i].type == "cpu") {
120
121
// default for all stacked AreaChart
122
json.charts[i].chartType = "AreaChart";
@@ -125,6 +136,10 @@ function loadCharts(doNext) {
136
137
// the category name, and other options, per type
138
switch(json.charts[i].type) {
139
+ case "cpu":
140
+ json.charts[i].category = "CPU";
141
+ break;
142
+
143
case "tc":
144
json.charts[i].category = "Quality of Service";
145
break;
web/theme.css
+9
@@ -1,4 +1,13 @@
1
+/* http://stackoverflow.com/questions/17005500/bootstrap-css-responsive-left-with-a-white-space-on-the-right */
2
+
3
+html {
4
+ width: auto !important;
5
+ overflow-x: hidden !important;
6
+}
7
+
8
body {
9
+ width: auto !important;
10
+ overflow-x: hidden !important;
11
padding-top: 70px;
12
padding-bottom: 30px;
13
}