@cryptotaxi247 / netdata-1 / commits / f165a5e7f

moved xml to json, added syslog support, managed all signals

Costa Tsaousis (ktsaou) committed Mar 29, 2014 at 02:52 UTC f165a5e7f1824b3295b1e61e6522487e6ab4a958
2 files changed +309 -202
netdata.c
+120 -57
@@ -27,6 +27,7 @@
27 #include <ctype.h>
28 #include <time.h>
29 #include <fcntl.h>
30 +#include <syslog.h>
31
32 #include <pthread.h>
33
@@ -171,6 +172,10 @@ void error_int( const char *file, const char *function, const unsigned long line
172 errno = 0;
173 }
174 else fprintf(stderr, "\n");
175 +
176 + va_start( args, fmt );
177 + vsyslog(LOG_ERR, fmt, args );
178 + va_end( args );
179 }
180
181 #define fatal(args...) fatal_int(__FILE__, __FUNCTION__, __LINE__, ##args)
@@ -191,6 +196,10 @@ void fatal_int( const char *file, const char *function, const unsigned long line
196 perror(" # ");
197 fprintf(stderr, "\n");
198
199 + va_start( args, fmt );
200 + vsyslog(LOG_CRIT, fmt, args );
201 + va_end( args );
202 +
203 exit(EXIT_FAILURE);
204 }
205
@@ -492,6 +501,8 @@ void rrd_stats_next(RRD_STATS *st)
501 now = &st->times[st->current_entry];
502 gettimeofday(now, NULL);
503
504 + st->last_updated = now->tv_sec;
505 +
506 // leave mutex locked
507 }
508
@@ -563,47 +574,52 @@ void rrd_stats_dimension_set(RRD_STATS *st, const char *id, void *data)
574 #define GROUP_AVERAGE 0
575 #define GROUP_MAX 1
576
566 -size_t rrd_stats_one_xml(RRD_STATS *st, char *options, char *buffer, size_t len)
577 +size_t rrd_stats_one_json(RRD_STATS *st, char *options, char *buffer, size_t len)
578 {
579 size_t i = 0;
580 if(i + 200 > len) return(0);
581
571 - i += sprintf(&buffer[i], "\t<graph>\n");
572 - i += sprintf(&buffer[i], "\t\t<id>%s</id>\n", st->id);
573 - i += sprintf(&buffer[i], "\t\t<name>%s</name>\n", st->name);
574 - i += sprintf(&buffer[i], "\t\t<type>%s</type>\n", st->type);
575 - i += sprintf(&buffer[i], "\t\t<title>%s%s</title>\n", st->title, st->name);
576 - i += sprintf(&buffer[i], "\t\t<vtitle>%s</vtitle>\n", st->vtitle);
577 - i += sprintf(&buffer[i], "\t\t<dataurl>/data/%s/%s</dataurl>\n", st->name, options?options:"");
578 - i += sprintf(&buffer[i], "\t\t<entries>%ld</entries>\n", st->entries);
579 - i += sprintf(&buffer[i], "\t</graph>\n");
582 + i += sprintf(&buffer[i], "\t\t{\n");
583 + i += sprintf(&buffer[i], "\t\t\t\"id\" : \"%s\",\n", st->id);
584 + i += sprintf(&buffer[i], "\t\t\t\"name\" : \"%s\",\n", st->name);
585 + i += sprintf(&buffer[i], "\t\t\t\"type\" : \"%s\",\n", st->type);
586 + i += sprintf(&buffer[i], "\t\t\t\"title\" : \"%s %s\",\n", st->title, st->name);
587 + i += sprintf(&buffer[i], "\t\t\t\"vtitle\" : \"%s\",\n", st->vtitle);
588 + i += sprintf(&buffer[i], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
589 + i += sprintf(&buffer[i], "\t\t\t\"entries\" : %ld,\n", st->entries);
590 + i += sprintf(&buffer[i], "\t\t\t\"current\" : %ld,\n", st->current_entry);
591 + i += sprintf(&buffer[i], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
592 + i += sprintf(&buffer[i], "\t\t\t\"last_updated_secs_ago\" : %lu\n", time(NULL) - st->last_updated);
593 + i += sprintf(&buffer[i], "\t\t}");
594
595 return(i);
596 }
597
584 -#define RRD_GRAPH_XML_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"/all.xsl\"?>\n\n<catalog>\n"
585 -#define RRD_GRAPH_XML_FOOTER "</catalog>\n"
598 +#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
599 +#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
600
587 -size_t rrd_stats_graph_xml(RRD_STATS *st, char * options, char *buffer, size_t len)
601 +size_t rrd_stats_graph_json(RRD_STATS *st, char * options, char *buffer, size_t len)
602 {
603 size_t i = 0;
590 - i += sprintf(&buffer[i], RRD_GRAPH_XML_HEADER);
591 - i += rrd_stats_one_xml(st, options, &buffer[i], len - i);
592 - i += sprintf(&buffer[i], RRD_GRAPH_XML_FOOTER);
604 + i += sprintf(&buffer[i], RRD_GRAPH_JSON_HEADER);
605 + i += rrd_stats_one_json(st, options, &buffer[i], len - i);
606 + i += sprintf(&buffer[i], RRD_GRAPH_JSON_FOOTER);
607 return(i);
608 }
609
596 -size_t rrd_stats_all_xml(char *buffer, size_t len)
610 +size_t rrd_stats_all_json(char *buffer, size_t len)
611 {
598 - size_t i = 0;
612 + size_t i = 0, c;
613 RRD_STATS *st;
614
601 - i += sprintf(&buffer[i], RRD_GRAPH_XML_HEADER);
615 + i += sprintf(&buffer[i], RRD_GRAPH_JSON_HEADER);
616
603 - for(st = root; st ; st = st->next)
604 - i += rrd_stats_one_xml(st, NULL, &buffer[i], len - i);
617 + for(st = root, c = 0; st ; st = st->next, c++) {
618 + if(c) i += sprintf(&buffer[i], "%s", ",\n");
619 + i += rrd_stats_one_json(st, NULL, &buffer[i], len - i);
620 + }
621
606 - i += sprintf(&buffer[i], RRD_GRAPH_XML_FOOTER);
622 + i += sprintf(&buffer[i], RRD_GRAPH_JSON_FOOTER);
623 return(i);
624 }
625
@@ -831,6 +847,7 @@ void web_buffer_increase(struct web_buffer *b, size_t free_size_required)
847
848 struct web_client {
849 unsigned long long id;
850 + char client_ip[101];
851
852 int mode;
853 int keepalive;
@@ -879,7 +896,11 @@ struct web_client *web_client_create(int listener)
896 }
897 w->ofd = w->ifd;
898
882 - debug(D_WEB_CLIENT_ACCESS, "%llu: New web client from %s on socket %d.", w->id, inet_ntoa(w->clientaddr.sin_addr), w->ifd);
899 + strncpy(w->client_ip, inet_ntoa(w->clientaddr.sin_addr), 100);
900 + w->client_ip[100] = '\0';
901 +
902 + syslog(LOG_NOTICE, "%llu: New client from %s.", w->id, w->client_ip);
903 + debug(D_WEB_CLIENT_ACCESS, "%llu: New web client from %s on socket %d.", w->id, w->client_ip, w->ifd);
904
905 {
906 int flag = 1;
@@ -979,6 +1000,8 @@ int mysendfile(struct web_client *w, char *filename)
1000 }
1001 }
1002
1003 + syslog(LOG_NOTICE, "%llu: Sending file '%s' to client %s.", w->id, filename, w->client_ip);
1004 +
1005 // pick a Content-Type for the file
1006 if(strstr(filename, ".html") != NULL) w->data->contenttype = CT_TEXT_HTML;
1007 else if(strstr(filename, ".js") != NULL) w->data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
@@ -1141,9 +1164,9 @@ void web_client_process(struct web_client *w)
1164 }
1165 else {
1166 code = 200;
1144 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.xml of RRD_STATS...", w->id, st->name);
1145 - w->data->contenttype = CT_TEXT_XML;
1146 - w->data->bytes = rrd_stats_graph_xml(st, url, w->data->buffer, w->data->size);
1167 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1168 + w->data->contenttype = CT_APPLICATION_JSON;
1169 + w->data->bytes = rrd_stats_graph_json(st, url, w->data->buffer, w->data->size);
1170 }
1171 }
1172 else if(strcmp(tok, "mirror") == 0) {
@@ -1165,11 +1188,11 @@ void web_client_process(struct web_client *w)
1188 for ( ; st ; st = st->next )
1189 w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s\n", st->name);
1190 }
1168 - else if(strcmp(tok, "all.xml") == 0) {
1191 + else if(strcmp(tok, "all.json") == 0) {
1192 code = 200;
1170 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending all.xml of RRD_STATS...", w->id);
1171 - w->data->contenttype = CT_TEXT_XML;
1172 - w->data->bytes = rrd_stats_all_xml(w->data->buffer, w->data->size);
1193 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending all.json of RRD_STATS...", w->id);
1194 + w->data->contenttype = CT_APPLICATION_JSON;
1195 + w->data->bytes = rrd_stats_all_json(w->data->buffer, w->data->size);
1196 }
1197 else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
1198 tok = mystrsep(&url, "/?&");
@@ -1507,7 +1530,7 @@ void *new_client(void *ptr)
1530 retval = select(fdmax+1, &ifds, &ofds, &efds, &tv);
1531
1532 if(retval == -1)
1510 - fatal("LISTENER: select() failed.");
1533 + fatal("%llu: LISTENER: select() failed.", w->id);
1534 else if(!retval) {
1535 // timeout
1536 w->obsolete = 1;
@@ -1519,6 +1542,7 @@ void *new_client(void *ptr)
1542 w->obsolete = 1;
1543 return NULL;
1544 }
1545 +
1546 if(FD_ISSET(w->ofd, &efds)) {
1547 debug(D_WEB_CLIENT_ACCESS, "%llu: Received error on output socket (%s).", w->id, strerror(errno));
1548 w->obsolete = 1;
@@ -1545,6 +1569,7 @@ void *new_client(void *ptr)
1569 if(w->mode == WEB_CLIENT_MODE_NORMAL) web_client_process(w);
1570 }
1571 }
1572 + debug(D_WEB_CLIENT, "%llu: done...", w->id);
1573
1574 return NULL;
1575 }
@@ -1590,10 +1615,15 @@ void *socket_listen_main(void *ptr)
1615 if(FD_ISSET(listener, &ifds)) {
1616 w = web_client_create(listener);
1617
1593 - w->thread = pthread_create(&w->thread, NULL, new_client, w);
1618 + if(pthread_create(&w->thread, NULL, new_client, w) != 0)
1619 + error("%llu: failed to create new thread.");
1620 +
1621 + if(pthread_detach(w->thread) != 0)
1622 + error("%llu: Cannot request detach of newly created thread.", w->id);
1623 }
1624 + else debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");
1625 }
1596 - // else timeout
1626 + else debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
1627
1628 // cleanup unused clients
1629 for(w = web_clients; w ; w = w?w->next:NULL) {
@@ -1604,6 +1634,8 @@ void *socket_listen_main(void *ptr)
1634 }
1635 }
1636
1637 + error("LISTENER: exit!");
1638 +
1639 close(listener);
1640 exit(2);
1641
@@ -1794,7 +1826,7 @@ void *proc_main(void *ptr)
1826
1827 // calculate the time it took for a full loop
1828 usec = usecdiff(&now, &last);
1797 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: Last loop took %llu usec.", usec);
1829 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: Last full loop took %llu usec.", usec);
1830
1831 // BEGIN -- the job to be done
1832 do_proc_net_dev(usec);
@@ -1804,7 +1836,7 @@ void *proc_main(void *ptr)
1836 // find the time to sleep in order to wait exactly update_every seconds
1837 gettimeofday(&tmp, NULL);
1838 usec = usecdiff(&tmp, &now);
1807 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: This loop took %llu usec.", usec);
1839 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: This loop's work took %llu usec.", usec);
1840
1841 if(usec < (update_every * 1000000)) susec = (update_every * 1000000) - usec;
1842 else susec = 0;
@@ -2059,24 +2091,27 @@ void *tc_main(void *ptr)
2091
2092 void bye(void)
2093 {
2094 + error("bye...");
2095 if(tc_child_pid) kill(tc_child_pid, SIGTERM);
2096 tc_child_pid = 0;
2097 }
2098
2099 void sig_handler(int signo)
2100 {
2068 - error("Signal %d received.", signo);
2069 -
2101 switch(signo) {
2102 case SIGTERM:
2103 case SIGQUIT:
2104 case SIGINT:
2105 case SIGHUP:
2075 - error("Cleanup.");
2106 + error("Signaled cleanup (signal %d).", signo);
2107 if(tc_child_pid) kill(tc_child_pid, SIGTERM);
2108 tc_child_pid = 0;
2109 exit(1);
2110 break;
2111 +
2112 + default:
2113 + error("Signal %d received. Ignoring it.", signo);
2114 + break;
2115 }
2116 }
2117
@@ -2107,6 +2142,44 @@ int become_user(const char *username)
2142 return(0);
2143 }
2144
2145 +void become_daemon()
2146 +{
2147 + int i = fork();
2148 + if(i == -1) {
2149 + perror("cannot fork");
2150 + exit(1);
2151 + }
2152 + if(i != 0) {
2153 + exit(0); // the parent
2154 + }
2155 +
2156 + // become session leader
2157 + if (setsid() < 0)
2158 + exit(2);
2159 +
2160 + signal(SIGCHLD, SIG_IGN);
2161 + signal(SIGHUP, SIG_IGN);
2162 +
2163 + // fork() again
2164 + i = fork();
2165 + if(i == -1) {
2166 + perror("cannot fork");
2167 + exit(1);
2168 + }
2169 + if(i != 0) {
2170 + exit(0); // the parent
2171 + }
2172 +
2173 + // Set new file permissions
2174 + umask(0);
2175 +
2176 + // close all files
2177 + for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
2178 + close(i);
2179 +
2180 + silent = 1;
2181 +}
2182 +
2183 int main(int argc, char **argv)
2184 {
2185 int i, daemon = 0;
@@ -2177,28 +2250,18 @@ int main(int argc, char **argv)
2250 fprintf(stderr, "Cannot lower my CPU priority. Error %s.\n", strerror(errno));
2251 }
2252
2180 - if(daemon) {
2181 - i = fork();
2182 - if(i == -1) {
2183 - perror("cannot fork");
2184 - exit(1);
2185 - }
2186 - if(i != 0) {
2187 - fprintf(stderr, "Running in the background...\n");
2188 - exit(0); // the parent
2189 - }
2190 - close(0);
2191 - close(1);
2192 - close(2);
2193 - silent = 1;
2194 - }
2253 + if(daemon) become_daemon();
2254 +
2255 + // open syslog
2256 + openlog("netdata", LOG_PID, LOG_DAEMON);
2257 + syslog(LOG_NOTICE, "netdata started.");
2258
2259 // make sure we cleanup correctly
2260 atexit(bye);
2198 - if(signal(SIGINT, sig_handler) == SIG_ERR) error("Can't catch SIGINT.");
2199 - if(signal(SIGTERM, sig_handler) == SIG_ERR) error("Can't catch SIGTERM.");
2200 - if(signal(SIGQUIT, sig_handler) == SIG_ERR) error("Can't catch SIGQUIT.");
2201 - if(signal(SIGHUP, sig_handler) == SIG_ERR) error("Can't catch SIGHUP.");
2261 +
2262 + // catch all signals
2263 + for (i = 1 ; i < 65 ;i++) signal(i, sig_handler);
2264 +
2265
2266 pthread_t p_proc, p_tc;
2267 int r_proc, r_tc;
web/netdata.js
+189 -145
@@ -1,161 +1,205 @@
1 - // fix old IE bug with console
2 - if(!window.console){ window.console = {log: function(){} }; }
3 -
4 - // Load the Visualization API and the piechart package.
5 - google.load('visualization', '1', {'packages':['corechart']});
6 -
7 - var charts = new Array();
1 +// fix old IE bug with console
2 +if(!window.console){ window.console = {log: function(){} }; }
3
9 - function refreshChart(index) {
10 - if(index >= charts.length) return;
11 -
12 - charts[index].refreshCount++;
13 -
14 - if(charts[index].chart != null) {
15 - if(charts[index].chart.getSelection()[0]) return;
16 -
17 - if(charts[index].refreshCount >= 9999999) {
18 - charts[index].jsondata = null;
19 - charts[index].datatable = null;
20 - charts[index].chart.clearChart();
21 - charts[index].chart = null;
22 - charts[index].refreshCount = 1;
23 - }
24 - }
25 -
26 - charts[index].jsondata = $.ajax({
27 - url: charts[index].url,
28 - dataType:"json",
29 - async: false,
30 - cache: false
31 - }).responseText;
32 -
33 - if(!charts[index].jsondata || charts[index].jsondata.length == 0) return;
34 -
35 - // Create our data table out of JSON data loaded from server.
36 - charts[index].datatable = new google.visualization.DataTable(charts[index].jsondata);
37 -
38 - // Instantiate and draw our chart, passing in some options.
39 - if(!charts[index].chart) {
40 - console.log('Creating new chart for ' + charts[index].url);
41 - charts[index].chart = new google.visualization.AreaChart(document.getElementById(charts[index].div));
42 - }
43 -
44 - var width = charts[index].width;
45 - var height = charts[index].height;
4 +// Load the Visualization API and the piechart package.
5 +google.load('visualization', '1', {'packages':['corechart']});
6
47 - var hAxisTitle = null;
48 - var vAxisTitle = null;
49 - if(height >= 250) hAxisTitle = "Time of Day";
50 - if(width >= 450) vAxisTitle = charts[index].vtitle;
7 +function refreshChart(chart) {
8 + chart.refreshCount++;
9 +
10 + if(chart.chart != null) {
11 + if(chart.chart.getSelection()[0]) return;
12
52 - var title = charts[index].title;
53 -
54 - var isStacked = false;
55 - if(charts[index].name.substring(0, 3) == "tc.") {
56 - isStacked = true;
57 - title += " [stacked]";
13 + if(chart.refreshCount >= 9999999) {
14 + chart.jsondata = null;
15 + chart.datatable = null;
16 + chart.chart.clearChart();
17 + chart.chart = null;
18 + chart.refreshCount = 1;
19 }
20 + }
21 +
22 + chart.jsondata = $.ajax({
23 + url: chart.url,
24 + dataType:"json",
25 + async: false,
26 + cache: false
27 + }).responseText;
28 +
29 + if(!chart.jsondata || chart.jsondata.length == 0) return;
30 +
31 + // Create our data table out of JSON data loaded from server.
32 + chart.datatable = new google.visualization.DataTable(chart.jsondata);
33 +
34 + // Instantiate and draw our chart, passing in some options.
35 + if(!chart.chart) {
36 + console.log('Creating new chart for ' + chart.url);
37 + chart.chart = new google.visualization.AreaChart(document.getElementById(chart.div));
38 + }
39 +
40 + var width = chart.width;
41 + var height = chart.height;
42 +
43 + var hAxisTitle = null;
44 + var vAxisTitle = null;
45 + if(height >= 250) hAxisTitle = "Time of Day";
46 + if(width >= 450) vAxisTitle = chart.vtitle;
47 +
48 + var title = chart.title;
49
60 - var options = {
61 - width: width,
62 - height: height,
63 - title: title,
64 - isStacked: isStacked,
65 - hAxis: {title: hAxisTitle},
66 - vAxis: {title: vAxisTitle, minValue: 10},
67 - focusTarget: 'category',
68 - lineWidth: (isStacked)?1:2,
69 - areaOpacity: (isStacked)?1.0:0.3,
70 - // animation: {duration: 1000, easing: 'inAndOut'},
71 - };
72 -
73 - if(charts[index].chart) charts[index].chart.draw(charts[index].datatable, options);
74 - else console.log('Cannot create chart for ' + charts[index].url);
50 + var isStacked = false;
51 + if(chart.name.substring(0, 3) == "tc.") {
52 + isStacked = true;
53 + title += " [stacked]";
54 }
55 +
56 + var options = {
57 + width: width,
58 + height: height,
59 + title: title,
60 + isStacked: isStacked,
61 + hAxis: {title: hAxisTitle},
62 + vAxis: {title: vAxisTitle, minValue: 10},
63 + focusTarget: 'category',
64 + lineWidth: (isStacked)?1:2,
65 + areaOpacity: (isStacked)?1.0:0.3,
66 + // animation: {duration: 1000, easing: 'inAndOut'},
67 + };
68 +
69 + if(chart.chart) chart.chart.draw(chart.datatable, options);
70 + else console.log('Cannot create chart for ' + chart.url);
71 +}
72 +
73 +function cloneJSON(obj) {
74 + // basic type deep copy
75 + if (obj === null || obj === undefined || typeof obj !== 'object') {
76 + return obj
77 + }
78 + // array deep copy
79 + if (obj instanceof Array) {
80 + var cloneA = [];
81 + for (var i = 0; i < obj.length; ++i) {
82 + cloneA[i] = cloneJSON(obj[i]);
83 + }
84 + return cloneA;
85 + }
86 + // object deep copy
87 + var cloneO = {};
88 + for (var i in obj) {
89 + cloneO[i] = cloneJSON(obj[i]);
90 + }
91 + return cloneO;
92 +}
93 +
94 +function loadCharts() {
95 + var mycharts = new Array();
96 +
97 + $.getJSON('/all.json', function(json) {
98 + $.each(json.charts, function(i, value) {
99 + mycharts[i] = $.extend(true, {}, value);
100 +
101 + mycharts[i].div = mycharts[i].name.replace(/\./g,"_");
102 + mycharts[i].div = mycharts[i].div.replace(/\-/g,"_");
103 + mycharts[i].div = mycharts[i].div + "_div";
104 +
105 + mycharts[i].width = 0;
106 + mycharts[i].height = 0;
107 + mycharts[i].refreshCount = 0;
108 +
109 + mycharts[i].chart = null;
110 + mycharts[i].jsondata = null;
111 + mycharts[i].datatable = null;
112 + });
113 + });
114 +
115 + console.log("all: " + mycharts.length)
116 + console.log(mycharts);
117 + return mycharts;
118 +};
119 +
120 +var charts = new Array();
121 +function addChart(name, div, width, height, jsonurl, title, vtitle) {
122 + var i = charts.length;
123
77 - function addChart(name, div, width, height, jsonurl, title, vtitle) {
78 - var i = charts.length;
79 -
80 - console.log('Creating new objects for chart ' + name);
81 - charts[i] = [];
82 - charts[i].chart = null;
83 - charts[i].jsondata = null;
84 - charts[i].datatable = null;
85 - charts[i].name = name;
86 - charts[i].div = div;
87 - charts[i].url = jsonurl;
88 - charts[i].title = title;
89 - charts[i].vtitle = vtitle;
90 - charts[i].width = width;
91 - charts[i].height = height;
92 - charts[i].refreshCount = 0;
124 + console.log('Creating new objects for chart ' + name);
125 + charts[i] = [];
126 + charts[i].chart = null;
127 + charts[i].jsondata = null;
128 + charts[i].datatable = null;
129 + charts[i].name = name;
130 + charts[i].div = div;
131 + charts[i].url = jsonurl;
132 + charts[i].title = title;
133 + charts[i].vtitle = vtitle;
134 + charts[i].width = width;
135 + charts[i].height = height;
136 + charts[i].refreshCount = 0;
137 +}
138 +
139 +var charts_last_drawn = 999999999;
140 +function refreshCharts(howmany) {
141 +
142 + if(charts.length == 0) return;
143 +
144 + var h = howmany;
145 + if(h == 0) h = charts.length;
146 + if(h > charts.length) h = charts.length;
147 + //console.log('Will run for ' + h + ' charts');
148 +
149 + var width = Math.round(Math.sqrt(charts.length));
150 + var height = Math.round(Math.sqrt(charts.length));
151 + while((width * height) < charts.length) {
152 + if((height + 1) <= width) height++;
153 + else width++;
154 }
155 + // console.log('all: ' + charts.length + ', optimal: width = ' + width + ', height = ' + height);
156 +
157 + while(width > 1 && width >= height) {
158 + width--;
159 + height++;
160 + }
161 + if(width * height < charts.length) height++;
162 + // console.log('final: width = ' + width + ', height = ' + height);
163 +
164 + ww = (window.innerWidth < document.documentElement.clientWidth)?window.innerWidth:document.documentElement.clientWidth;
165 + wh = (window.innerHeight < document.documentElement.clientHeight)?window.innerHeight:document.documentElement.clientHeight;
166 +
167 + if(width == 0) width = (ww - 40) / 2;
168 + if(width <= 10) width = (ww - 40) / width;
169 + if(width < 200) width = 200;
170
95 - var charts_last_drawn = 999999999;
96 - function refreshCharts(howmany) {
97 -
98 - if(charts.length == 0) return;
99 -
100 - var h = howmany;
101 - if(h == 0) h = charts.length;
102 - if(h > charts.length) h = charts.length;
103 - //console.log('Will run for ' + h + ' charts');
171 + if(height == 0) height = (wh - 20) / 2;
172 + if(height <= 10) height = (wh - 20) / height;
173 + if(height < 100) height = 100;
174 +
175 + // console.log('width = ' + width + ', height = ' + height);
176 +
177 + var i;
178 + for(i = 0; i < h; i++) {
179 + var zeroDimensions = 0;
180 +
181 + charts_last_drawn++;
182 + if(charts_last_drawn >= charts.length) charts_last_drawn = 0;
183
105 - var width = Math.round(Math.sqrt(charts.length));
106 - var height = Math.round(Math.sqrt(charts.length));
107 - while((width * height) < charts.length) {
108 - if((height + 1) <= width) height++;
109 - else width++;
184 + if(charts[charts_last_drawn].width == 0 && charts[charts_last_drawn].height == 0) {
185 + charts[charts_last_drawn].width = width;
186 + charts[charts_last_drawn].height = height;
187 + zeroDimensions = 1;
188 }
111 - // console.log('all: ' + charts.length + ', optimal: width = ' + width + ', height = ' + height);
189
113 - while(width > 1 && width >= height) {
114 - width--;
115 - height++;
116 - }
117 - if(width * height < charts.length) height++;
118 - // console.log('final: width = ' + width + ', height = ' + height);
190 + try {
191
120 - ww = (window.innerWidth < document.documentElement.clientWidth)?window.innerWidth:document.documentElement.clientWidth;
121 - wh = (window.innerHeight < document.documentElement.clientHeight)?window.innerHeight:document.documentElement.clientHeight;
192 + console.log('Refreshing chart ' + charts[charts_last_drawn].name);
193 + refreshChart(charts[charts_last_drawn]);
194 + }
195 + catch(err) {
196 + console.log('Cannot refresh chart for ' + charts[charts_last_drawn].url);
197 + }
198
123 - if(width == 0) width = (ww - 40) / 2;
124 - if(width <= 10) width = (ww - 40) / width;
125 - if(width < 200) width = 200;
126 -
127 - if(height == 0) height = (wh - 20) / 2;
128 - if(height <= 10) height = (wh - 20) / height;
129 - if(height < 100) height = 100;
130 -
131 - // console.log('width = ' + width + ', height = ' + height);
132 -
133 - var i;
134 - for(i = 0; i < h; i++) {
135 - var zeroDimensions = 0;
136 -
137 - charts_last_drawn++;
138 - if(charts_last_drawn >= charts.length) charts_last_drawn = 0;
139 -
140 - if(charts[charts_last_drawn].width == 0 && charts[charts_last_drawn].height == 0) {
141 - charts[charts_last_drawn].width = width;
142 - charts[charts_last_drawn].height = height;
143 - zeroDimensions = 1;
144 - }
145 -
146 - try {
147 -
148 - console.log('Refreshing chart ' + charts[charts_last_drawn].name);
149 - refreshChart(charts_last_drawn);
150 - }
151 - catch(err) {
152 - console.log('Cannot refresh chart for ' + charts[charts_last_drawn].url);
153 - }
154 -
155 - if(zeroDimensions == 1) {
156 - charts[charts_last_drawn].width = 0;
157 - charts[charts_last_drawn].height = 0;
158 - }
199 + if(zeroDimensions == 1) {
200 + charts[charts_last_drawn].width = 0;
201 + charts[charts_last_drawn].height = 0;
202 }
160 - return 0;
203 }
204 + return 0;
205 +}