@cryptotaxi247 / netdata-1 / commits / f39384e8f

minor code cleanups; updated the dashboard to fix inline charts

Costa Tsaousis (ktsaou) committed Dec 1, 2015 at 01:36 UTC f39384e8f93cd395b5c48c406f4ca53753abf7e8
10 files changed +423 -269
src/daemon.c
+2 -21
@@ -25,19 +25,6 @@
25 #include "main.h"
26 #include "daemon.h"
27
28 -#define BACKTRACE_SIZE 4096
29 -
30 -void print_backtrace()
31 -{
32 - void *buffer[BACKTRACE_SIZE];
33 - int nptrs;
34 -
35 - nptrs = backtrace(buffer, BACKTRACE_SIZE);
36 - fprintf(stderr, "\n\nSTACK TRACE (%d addresses):\n\n", nptrs);
37 - backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
38 - fprintf(stderr, "\n\n");
39 -}
40 -
28 void sig_handler(int signo)
29 {
30 switch(signo) {
@@ -51,7 +38,6 @@ void sig_handler(int signo)
38 case SIGXCPU:
39 case SIGXFSZ:
40 info("Death signaled exit (signal %d). Errno: %d (%s)", signo, errno, strerror(errno));
54 - print_backtrace();
41 signal(signo, SIG_DFL);
42 break;
43
@@ -63,18 +49,13 @@ void sig_handler(int signo)
49 case SIGUSR1:
50 case SIGUSR2:
51 info("Signaled exit (signal %d). Errno: %d (%s)", signo, errno, strerror(errno));
66 - print_backtrace();
52 signal(SIGPIPE, SIG_IGN);
53 signal(SIGTERM, SIG_IGN);
54 signal(SIGQUIT, SIG_IGN);
55 signal(SIGHUP, SIG_IGN);
56 signal(SIGINT, SIG_IGN);
57 signal(SIGCHLD, SIG_IGN);
73 - kill_childs();
74 - rrdset_free_all();
75 - //unlink("/var/run/netdata.pid");
76 - info("NetData exiting. Bye bye...");
77 - exit(1);
58 + netdata_cleanup_and_exit(1);
59 break;
60
61 case SIGPIPE:
@@ -263,7 +244,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
244 // close all files
245 if(close_all_files) {
246 int i;
266 - for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
247 + for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--)
248 if(
249 ((access_fd && i != *access_fd) || !access_fd)
250 && i != dev_null
src/daemon.h
+2
@@ -9,4 +9,6 @@ extern int become_user(const char *username);
9
10 extern int become_daemon(int dont_fork, int close_all_files, const char *user, const char *input, const char *output, const char *error, const char *access, int *access_fd, FILE **access_fp);
11
12 +extern void netdata_cleanup_and_exit(int i);
13 +
14 #endif /* NETDATA_DAEMON_H */
src/main.c
+22 -1
@@ -35,6 +35,17 @@
35
36 #include "main.h"
37
38 +int netdata_exit = 0;
39 +
40 +void netdata_cleanup_and_exit(int ret)
41 +{
42 + kill_childs();
43 + rrdset_free_all();
44 + //unlink("/var/run/netdata.pid");
45 + info("NetData exiting. Bye bye...");
46 + exit(ret);
47 +}
48 +
49 struct netdata_static_thread {
50 char *name;
51
@@ -445,7 +456,17 @@ int main(int argc, char **argv)
456 }
457
458 // for future use - the main thread
448 - while(1) sleep(60);
459 + while(1) {
460 + if(netdata_exit != 0) {
461 + netdata_exit++;
462 +
463 + if(netdata_exit > 5) {
464 + netdata_cleanup_and_exit(0);
465 + exit(0);
466 + }
467 + }
468 + sleep(2);
469 + }
470
471 exit(0);
472 }
src/main.h
+3
@@ -1,7 +1,10 @@
1 #ifndef NETDATA_MAIN_H
2 #define NETDATA_MAIN_H 1
3
4 +extern int netdata_exit;
5 +
6 extern void kill_childs(void);
7 extern int killpid(pid_t pid, int signal);
8 +extern void netdata_cleanup_and_exit(int ret);
9
10 #endif /* NETDATA_MAIN_H */
src/popen.c
+1 -1
@@ -78,7 +78,7 @@ FILE *mypopen(const char *command, pid_t *pidptr)
78
79 // close all files
80 int i;
81 - for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
81 + for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--)
82 if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
83
84 // move the pipe to stdout
src/web_client.c
+12 -1
@@ -34,6 +34,8 @@
34 int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS;
35 int web_enable_gzip = 1;
36
37 +extern int netdata_exit;
38 +
39 struct web_client *web_clients = NULL;
40 unsigned long long web_clients_count = 0;
41
@@ -975,7 +977,7 @@ void web_client_process(struct web_client *w) {
977 //if(strstr(w->response.data->buffer, "X-DataSource-Auth"))
978 // datasource_type = DATASOURCE_GOOGLE_JSON;
979
978 - char *buf = w->response.data->buffer;
980 + char *buf = (char *)buffer_tostring(w->response.data);
981 char *tok = strsep(&buf, " \r\n");
982 char *url = NULL;
983 char *pointer_to_free = NULL; // keep url_decode() allocated buffer
@@ -1007,6 +1009,15 @@ void web_client_process(struct web_client *w) {
1009 datasource_type = DATASOURCE_JSON;
1010 code = web_client_api_request(w, url);
1011 }
1012 +#ifdef WEB_EXIT
1013 + else if(strcmp(tok, "exit") == 0) {
1014 + netdata_exit = 1;
1015 + code = 200;
1016 + w->response.data->contenttype = CT_TEXT_PLAIN;
1017 + buffer_flush(w->response.data);
1018 + buffer_strcat(w->response.data, "will do");
1019 + }
1020 +#endif
1021 else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1022 // the client is requesting rrd data
1023 datasource_type = DATASOURCE_JSON;
web/Makefile.am
+1
@@ -25,4 +25,5 @@ dist_weblib_DATA = \
25 lib/jquery.sparkline.min.js \
26 lib/morris.min.js \
27 lib/raphael-min.js \
28 + lib/visible.js \
29 $(NULL)
web/dashboard.html
+54 -57
@@ -19,7 +19,7 @@ This is a template for building custom dashboards. To build a dashboard you just
19 data-width="600"
20 data-height="200"
21 data-after="-600"
22 - </div>
22 + ></div>
23 </body>
24 &lt;script type="text/javascript" src="http://netdata.server:19999/dashboard.js"></script>
25 &lt;/html>
@@ -47,15 +47,15 @@ This is a template for building custom dashboards. To build a dashboard you just
47 System CPU - Stacked Area Chart
48 </th>
49 </tr>
50 - <tr><td colspan="3" align="center">&nbsp;</td></tr>
51 - <tr><th colspan="3" align="center"><hr>Peity Charts</th></tr>
52 - <tr><td colspan="3" align="center">
50 + <tr><td colspan="3">&nbsp;</td></tr>
51 + <tr><th colspan="3"><hr>Peity Charts</th></tr>
52 + <tr><td colspan="3">
53 Peity charts do not support 'NULL' values, so the charts cannot indicate that values are missing.
54 Peity charts cannot have multiple dimensions on the charts - so netdata will use 'min2max' to show
55 the total of all dimensions.
56 </td></tr>
57 <tr>
58 - <td width="600" align="center">
58 + <td width="600">
59 <div data-netdata="system.processes"
60 data-chart-library="peity"
61 data-width="600"
@@ -64,7 +64,7 @@ This is a template for building custom dashboards. To build a dashboard you just
64 data-dt-element-name="time11"
65 </div>
66 </td>
67 - <td width="600" align="center">
67 + <td width="600">
68 <div data-netdata="system.ipv4"
69 data-chart-library="peity"
70 data-width="600"
@@ -73,7 +73,7 @@ This is a template for building custom dashboards. To build a dashboard you just
73 data-dt-element-name="time12"
74 </div>
75 </td>
76 - <td width="600" align="center">
76 + <td width="600">
77 <div data-netdata="system.cpu"
78 data-chart-library="peity"
79 data-width="600"
@@ -88,67 +88,64 @@ This is a template for building custom dashboards. To build a dashboard you just
88 <td>rendered in <span id="time12">X</span> ms</td>
89 <td>rendered in <span id="time13">X</span> ms</td>
90 </tr>
91 - <tr><td colspan="3" align="center">&nbsp;</td></tr>
92 - <tr><th colspan="3" align="center"><hr>Sparkline Charts</th></tr>
93 - <tr><td colspan="3" align="center">
91 + <tr><td colspan="3">&nbsp;</td></tr>
92 + <tr><th colspan="3"><hr>Sparkline Charts</th></tr>
93 + <tr><td colspan="3">
94 Sparkline charts support 'NULL' values, so the charts can indicate that values are missing.
95 Sparkline charts stretch the values to show the variations between values in more detail.
96 They also have mouse-hover support.
97 <br/>
98 Sparklines are fantastic. You can inline charts in text. For example this
99 - <div style="display: inline; position: relative;"
100 - data-netdata="system.cpu"
99 + <div data-netdata="system.cpu"
100 data-chart-library="sparkline"
101 data-width="60"
103 - data-height="15"
102 + data-height="20"
103 data-after="-30"
105 - </div> is my current cpu usage,
104 + ></div> is my current cpu usage,
105 <br/>
106 while this
108 - <div style="display: inline; position: relative;"
109 - data-netdata="netdata.net"
107 + <div data-netdata="netdata.net"
108 data-dimensions="out"
109 data-chart-library="sparkline"
110 data-width="60"
113 - data-height="15"
111 + data-height="20"
112 data-after="-30"
115 - </div> is the bandwidth my netdata server is currently transmitting and this
113 + ></div> is the bandwidth my netdata server is currently transmitting and this
114
117 - <div style="display: inline; position: relative;"
118 - data-netdata="netdata.requests"
115 + <div data-netdata="netdata.requests"
116 data-chart-library="sparkline"
120 - data-width="60"
121 - data-height="15"
122 - data-after="-30"
123 - </div> is the requests/sec it serves.
117 + data-width="360"
118 + data-height="20"
119 + data-after="-180"
120 + ></div> is the requests/sec it serves.
121 </td></tr>
122 <tr>
126 - <td width="600" align="center">
123 + <td width="600">
124 <div data-netdata="system.processes"
125 data-chart-library="sparkline"
126 data-width="600"
127 data-height="30"
128 data-after="-600"
129 data-dt-element-name="time21"
133 - </div>
130 + ></div>
131 </td>
135 - <td width="600" align="center">
132 + <td width="600">
133 <div data-netdata="system.ipv4"
134 data-chart-library="sparkline"
135 data-width="600"
136 data-height="30"
137 data-after="-600"
138 data-dt-element-name="time22"
142 - </div>
139 + ></div>
140 </td>
144 - <td width="600" align="center">
141 + <td width="600">
142 <div data-netdata="system.cpu"
143 data-chart-library="sparkline"
144 data-width="600"
145 data-height="30"
146 data-after="-600"
147 data-dt-element-name="time23"
151 - </div>
148 + ></div>
149 </td>
150 </tr>
151 <tr>
@@ -156,40 +153,40 @@ This is a template for building custom dashboards. To build a dashboard you just
153 <td>rendered in <span id="time22">X</span> ms</td>
154 <td>rendered in <span id="time23">X</span> ms</td>
155 </tr>
159 - <tr><td colspan="3" align="center">&nbsp;</td></tr>
160 - <tr><th colspan="3" align="center"><hr>Dygraph Charts</th></tr>
161 - <tr><td colspan="3" align="center">
156 + <tr><td colspan="3">&nbsp;</td></tr>
157 + <tr><th colspan="3"><hr>Dygraph Charts</th></tr>
158 + <tr><td colspan="3">
159 The fastest charting engine that can chart complete charts (not just sparklines).
160 The charts are zoomable (drag their contents to zoom-in, double click to zoom-out).
161 For the moment zooming is just on the presentation layer (the data do not become more detailed when you zoom).
162 </td></tr>
163 <tr>
167 - <td width="600" align="center">
164 + <td width="600">
165 <div data-netdata="system.processes"
166 data-chart-library="dygraph"
167 data-width="600"
168 data-height="200"
169 data-after="-600"
170 data-dt-element-name="time31"
174 - </div>
171 + ></div>
172 </td>
176 - <td width="600" align="center">
173 + <td width="600">
174 <div data-netdata="system.ipv4"
175 data-chart-library="dygraph"
176 data-width="600"
177 data-height="200"
178 data-after="-600"
179 data-dt-element-name="time32"
183 - </div>
180 + ></div>
181 </td>
185 - <td width="600" align="center">
182 + <td width="600">
183 <div data-netdata="system.cpu"
184 data-chart-library="dygraph"
185 data-width="600"
186 data-height="200"
187 data-after="-600"
188 data-dt-element-name="time33"
192 - </div>
189 + ></div>
190 </td>
191 </tr>
192 <tr>
@@ -197,39 +194,39 @@ This is a template for building custom dashboards. To build a dashboard you just
194 <td>rendered in <span id="time32">X</span> ms</td>
195 <td>rendered in <span id="time33">X</span> ms</td>
196 </tr>
200 - <tr><td colspan="3" align="center">&nbsp;</td></tr>
201 - <tr><th colspan="3" align="center"><hr>Google Charts</th></tr>
202 - <tr><td colspan="3" align="center">
197 + <tr><td colspan="3">&nbsp;</td></tr>
198 + <tr><th colspan="3"><hr>Google Charts</th></tr>
199 + <tr><td colspan="3">
200 NetData was originaly developed with Google Charts.
201 NetData is a complete Google Visualization API provider.
202 </td></tr>
203 <tr>
207 - <td width="600" align="center">
204 + <td width="600">
205 <div data-netdata="system.processes"
206 data-chart-library="google"
207 data-width="600"
208 data-height="200"
209 data-after="-600"
210 data-dt-element-name="time51"
214 - </div>
211 + ></div>
212 </td>
216 - <td width="600" align="center">
213 + <td width="600">
214 <div data-netdata="system.ipv4"
215 data-chart-library="google"
216 data-width="600"
217 data-height="200"
218 data-after="-600"
219 data-dt-element-name="time52"
223 - </div>
220 + ></div>
221 </td>
225 - <td width="600" align="center">
222 + <td width="600">
223 <div data-netdata="system.cpu"
224 data-chart-library="google"
225 data-width="600"
226 data-height="200"
227 data-after="-600"
228 data-dt-element-name="time53"
232 - </div>
229 + ></div>
230 </td>
231 </tr>
232 <tr>
@@ -237,39 +234,39 @@ This is a template for building custom dashboards. To build a dashboard you just
234 <td>rendered in <span id="time52">X</span> ms</td>
235 <td>rendered in <span id="time53">X</span> ms</td>
236 </tr>
240 - <tr><td colspan="3" align="center">&nbsp;</td></tr>
241 - <tr><th colspan="3" align="center"><hr>Morris Charts</th></tr>
242 - <tr><td colspan="3" align="center">
237 + <tr><td colspan="3">&nbsp;</td></tr>
238 + <tr><th colspan="3"><hr>Morris Charts</th></tr>
239 + <tr><td colspan="3">
240 Unfortunatelly, Morris Charts are veeeeeeeeeeeeeeeery slow! We force them to lower their detail to get acceptable results.
241 And they have issues with negative numbers in area charts...
242 </td></tr>
243 <tr>
247 - <td width="600" align="center">
244 + <td width="600">
245 <div data-netdata="system.processes"
246 data-chart-library="morris"
247 data-width="600"
248 data-height="200"
249 data-after="-600"
250 data-dt-element-name="time41"
254 - </div>
251 + ></div>
252 </td>
256 - <td width="600" align="center">
253 + <td width="600">
254 <div data-netdata="system.ipv4"
255 data-chart-library="morris"
256 data-width="600"
257 data-height="200"
258 data-after="-600"
259 data-dt-element-name="time42"
263 - </div>
260 + ></div>
261 </td>
265 - <td width="600" align="center">
262 + <td width="600">
263 <div data-netdata="system.cpu"
264 data-chart-library="morris"
265 data-width="600"
266 data-height="200"
267 data-after="-600"
268 data-dt-element-name="time43"
272 - </div>
269 + ></div>
270 </td>
271 </tr>
272 <tr>
web/dashboard.js
+300 -188
@@ -67,9 +67,9 @@
67 NETDATA.morris_js = NETDATA.serverDefault + 'lib/morris.min.js';
68 NETDATA.morris_css = NETDATA.serverDefault + 'css/morris.css';
69 NETDATA.google_js = 'https://www.google.com/jsapi';
70 - NETDATA.colors = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6', '#DD4477',
71 - '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11', '#6633CC', '#E67300', '#8B0707',
72 - '#329262', '#5574A6', '#3B3EAC' ];
70 + NETDATA.colors = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6',
71 + '#DD4477', '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11',
72 + '#6633CC', '#E67300', '#8B0707', '#329262', '#5574A6', '#3B3EAC' ];
73
74 // ----------------------------------------------------------------------------------------------------------------
75 // the defaults for all charts
@@ -82,15 +82,23 @@
82 method: 'average', // the grouping method
83 before: 0, // panning
84 after: -600, // panning
85 - point_width: 1, // the detail of the chart
85 + pixels_per_point: 1, // the detail of the chart
86 }
87
88 - NETDATA.all_url = 'all2.js';
89 - NETDATA.idle_between_charts = 50;
90 - NETDATA.idle_between_loops = 100;
91 - NETDATA.debug = 1;
88 + NETDATA.options = {
89 + targets: null,
90 + updated_dom: 1,
91 + debug: 1,
92
93 - if(NETDATA.debug) console.log('welcome to NETDATA');
93 + current: {
94 + pixels_per_point: 1,
95 + idle_between_charts: 50,
96 + idle_between_loops: 100,
97 + debug: 1
98 + }
99 + }
100 +
101 + if(NETDATA.options.debug) console.log('welcome to NETDATA');
102
103
104 // ----------------------------------------------------------------------------------------------------------------
@@ -125,11 +133,19 @@
133 NETDATA.errorLast.datetime = 0;
134 }
135
128 - NETDATA.messageInABox = function(div, width, height, message) {
129 - div.innerHTML = '<table border="0"><tr><td width="' + width + '" height="' + height
130 - + '" valign="middle" align="center">'
136 + NETDATA.chartContainer = function(element, width, height) {
137 + self = $(element);
138 + self.css('width', width)
139 + .css('height', height)
140 + .css('display', 'inline-block')
141 + .css('overflow', 'hidden');
142 + }
143 +
144 + NETDATA.messageInABox = function(element, width, height, message) {
145 + NETDATA.chartContainer(element, width, height);
146 + element.innerHTML = '<div style="overflow: hidden; border: 0px; background-color: lightgrey; width: ' + width + '; height: ' + height + ';"><small>'
147 + message
132 - + '</td></tr></table>';
148 + + '</small></div>';
149 }
150
151 // ----------------------------------------------------------------------------------------------------------------
@@ -155,58 +171,63 @@
171 callback();
172 }
173
158 - NETDATA.generateDataURL = function(args) {
174 + NETDATA.generateChartDataURL = function(options) {
175 // build the data URL
160 - var url = args.host + args.url;
176 + var url = options.host + options.url;
177 url += "&points=";
162 - url += args.points.toString();
178 + url += options.points.toString();
179 url += "&group=";
164 - url += args.method;
180 + url += options.method;
181 url += "&after=";
166 - url += args.after || "0";
182 + url += options.after || "0";
183 url += "&before=";
168 - url += args.before || "0";
169 - url += "&options=" + NETDATA.chartLibraries[args.library].options + '|';
170 - url += (args.non_zero)?"nonzero":"";
171 - url += "&format=" + NETDATA.chartLibraries[args.library].format;
184 + url += options.before || "0";
185 + url += "&options=" + NETDATA.chartLibraries[options.library].options + '|';
186 + url += (options.non_zero)?"nonzero":"";
187 + url += "&format=" + NETDATA.chartLibraries[options.library].format;
188
173 - if(args.dimensions)
174 - url += "&dimensions=" + args.dimensions;
189 + if(options.dimensions)
190 + url += "&dimensions=" + options.dimensions;
191
176 - if(NETDATA.debug) console.log('generateDataURL(' + args + ') = ' + url );
192 + if(NETDATA.options.debug) console.log('generateChartDataURL(' + options + ') = ' + url );
193 return url;
194 }
195
180 - NETDATA.loadCharts = function(targets, index, callback) {
181 - if(NETDATA.debug) console.log('loadCharts(<targets, ' + index + ')');
196 + NETDATA.parseDomCharts = function(targets, index, callback) {
197 + if(NETDATA.options.debug) console.log('parseDomCharts() working on ' + index);
198
199 var target = targets.get(index);
184 -
200 if(target == null) {
186 - console.log('loaded all charts');
187 - callback();
201 + if(NETDATA.options.debug) console.log('parseDomCharts(): all ' + (index - 1) + ' charts parsed.');
202 + if(typeof callback == 'function') callback();
203 }
204 else {
205 var self = $(target);
206 + if(!self.data('prepared')) {
207 + self.data('prepared', true);
208
192 - if(!self.data('loaded')) {
209 var id = self.data('netdata');
194 -
210 var host = self.data('host') || NETDATA.chartDefaults.host;
211 var width = self.data('width') || NETDATA.chartDefaults.width;
212 var height = self.data('height') || NETDATA.chartDefaults.height;
213 var method = self.data('method') || NETDATA.chartDefaults.method;
214 var after = self.data('after') || NETDATA.chartDefaults.after;
215 var before = self.data('before') || NETDATA.chartDefaults.before;
201 - var host = self.data('host') || NETDATA.chartDefaults.host;
216 var library = self.data('chart-library') || NETDATA.chartDefaults.library;
217 var dimensions = self.data('dimensions') || null;
218
219 + NETDATA.chartContainer(target, width, height);
220 + if(NETDATA.options.debug) console.log('parseDomCharts() parsing ' + id + ' of type ' + library);
221 +
222 if(typeof NETDATA.chartLibraries[library] == 'undefined') {
223 + self.data('created', false)
224 + .data('updated', 0)
225 + .data('enabled', false);
226 +
227 NETDATA.error(402, library);
228 NETDATA.messageInABox(target, width, height, 'chart library "' + library + '" is not found');
208 - self.data('enabled', false);
209 - NETDATA.loadCharts(targets, ++index, callback);
229 +
230 + NETDATA.parseDomCharts(targets, ++index, callback);
231 }
232 else {
233 var url = host + "/api/v1/chart?chart=" + id;
@@ -216,11 +237,10 @@
237 crossDomain: true
238 })
239 .done(function(chart) {
240 + var pixels_per_point = self.data('point-width') || NETDATA.chartLibraries[library].pixels_per_point;
241 + var points = self.data('points') || Math.round(width / pixels_per_point);
242
220 - var point_width = self.data('point-width') || NETDATA.chartLibraries[library].pixels;
221 - var points = self.data('points') || Math.round(width / point_width);
222 -
223 - var url = NETDATA.generateDataURL({
243 + var url = NETDATA.generateChartDataURL({
244 host: host,
245 url: chart.data_url,
246 dimensions: dimensions,
@@ -235,74 +255,77 @@
255 // done processing of this DIV
256 // store the processing result, in
257 // 'data' sections in the DIV
238 - self
239 - .data('chart', chart)
258 + self.data('chart', chart)
259 .data('chart-url', url)
241 - .data('last-updated', 0)
260 .data('update-every', chart.update_every * 1000)
243 - .data('enabled', true);
261 + .data('created', false)
262 + .data('updated', 0)
263 + .data('enabled', true)
264 + .data('host', host)
265 + .data('width', width)
266 + .data('height', height)
267 + .data('method', method)
268 + .data('after', after)
269 + .data('before', before)
270 + .data('chart-library', library)
271 + .data('dimensions', dimensions)
272 + ;
273 +
274 + NETDATA.messageInABox(target, width, height, 'chart "' + id + '" is loading...');
275 })
276 .fail(function() {
277 + self.data('created', false)
278 + .data('enabled', false);
279 +
280 NETDATA.error(404, url);
281 NETDATA.messageInABox(target, width, height, 'chart "' + id + '" not found on url "' + url + '"');
248 - self.data('enabled', false);
282 })
283 .always(function() {
251 - NETDATA.loadCharts(targets, ++index, callback);
284 + self.data('updated', 0);
285 + NETDATA.parseDomCharts(targets, ++index, callback);
286 });
287 }
288 }
289 }
290 }
291
258 - function netdataParsePageCharts() {
259 - if(NETDATA.debug) console.log('processing web page defined charts');
292 + NETDATA.domUpdated = function(callback) {
293 + NETDATA.options.updated_dom = 0;
294
261 - // targets
262 - // a list of all DIVs containing netdata charts
263 -
264 - var targets = $('div[data-netdata]')
265 - .bind('create', function(event, data) {
266 - var self = $(this);
267 - var lib = self.data('chart-library') || 'dygraph';
268 - var method = lib + 'ChartCreate';
295 + NETDATA.options.targets = $('div[data-netdata]') // .filter(':visible')
296 + .bind('create', function(event, data) {
297 + var self = $(this);
298 + try {
299 + NETDATA.chartLibraries[self.data('chart-library')].create(this, data);
300 + }
301 + catch(err) {
302 + NETDATA.messageInABox(this, self.data('width'), self.data('height'), 'chart "' + id + '" failed to be created as ' + self.data('chart-library'));
303 + }
304 + })
305 + .bind('update', function(event, data) {
306 + var self = $(this);
307 + try {
308 + NETDATA.chartLibraries[self.data('chart-library')].update(this, data);
309 + }
310 + catch(err) {
311 + NETDATA.messageInABox(this, self.data('width'), self.data('height'), 'chart "' + id + '" failed to be updated as ' + self.data('chart-library'));
312 + }
313 + });
314
270 - console.log('Calling ' + method + '()');
271 - NETDATA[method].apply(this, arguments);
272 - })
273 - .bind('update', function() {
274 - var self = $(this);
275 - var lib = self.data('chart-library') || 'dygraph';
276 - var method = lib + 'ChartUpdate';
315 + if(NETDATA.options.debug)
316 + console.log('DOM updated - there are ' + NETDATA.options.targets.length + ' charts on page.');
317
278 - console.log('Calling ' + method + '()');
279 - NETDATA[method].apply(this, arguments);
280 - });
318 + NETDATA.parseDomCharts(NETDATA.options.targets, 0, callback);
319 + }
320
282 - NETDATA.loadCharts(targets, 0, function() {
321 + NETDATA.init = function() {
322 + NETDATA.domUpdated(function() {
323 // done processing all netdata DIVs in this page
324 // call the refresh handler
285 - netdataRefreshTargets(targets, 0);
286 - });
287 - }
325
289 - // ----------------------------------------------------------------------------------------------------------------
290 - // Charts Libraries Registration
291 -
292 - NETDATA.chartLibraries = {};
293 -
294 - NETDATA.registerChartLibrary = function(library, url, format, options, min_pixels_per_point) {
295 - console.log("registering chart library: " + library);
296 -
297 - NETDATA.chartLibraries[library] = {
298 - initialized: new Date().getTime(),
299 - url: url,
300 - format: format,
301 - options: options,
302 - pixels: min_pixels_per_point
303 - };
304 -
305 - console.log(NETDATA.chartLibraries);
326 + // FIXME
327 + NETDATA.chartRefresher(0);
328 + });
329 }
330
331 // ----------------------------------------------------------------------------------------------------------------
@@ -317,50 +340,48 @@
340 //var c = new chart();
341 //c.color();
342
320 - function netdataDownloadChartData(callback) {
321 - var self = $(this);
322 - var last = self.data('last-updated') || 0;
343 + NETDATA.chartValuesDownloader = function(element, callback) {
344 + var self = $(element);
345 + var last = self.data('updated') || 0;
346 var every = self.data('update-every') || 1;
347
348 // check if this chart has to be refreshed now
349 var now = new Date().getTime();
350 if(last + every > now) {
328 - if(typeof callback == 'function')
329 - callback();
351 + console.log(self.data('netdata') + ' too soon - skipping.');
352 + if(typeof callback == 'function') callback();
353 + }
354 + else if(!self.visible(true)) {
355 + console.log(self.data('netdata') + ' is NOT visible.');
356 + if(typeof callback == 'function') callback();
357 }
358 else {
332 - var url = self.data('chart-url');
333 -
334 - if(NETDATA.debug) console.log('netdataDownloadChartData(): downloading ' + url);
335 -
359 + console.log(self.data('netdata') + ' is visible, downloading data...');
360 $.ajax( {
337 - url: url,
361 + url: self.data('chart-url'),
362 crossDomain: true
363 })
364 .then(function(data) {
341 - //var result = $.map(data.rows, function(item) {
342 - // get from the 3rd column the 'v' member
343 - //return item.c[3].v;
344 - //});
345 -
346 - // since we downloaded the data
347 - // update the last-updated time to prevent
348 - // another download too soon
349 - self.data('last-updated', new Date().getTime());
350 -
351 - // render it
352 - var created = self.data('created');
353 - self.trigger((created ? 'update' : 'create'), [data]).data('created', true)
354 - })
355 - .fail(function() {
356 - console.log('failed to download chart data');
357 - })
358 - .always(function() {
359 - var last = self.data('last-updated');
360 - var now = new Date().getTime();
361 - var dt = now - last;
362 - self.data('refresh-dt', dt);
365 + var started = new Date().getTime();
366 +
367 + if(self.data('created')) {
368 + console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
369 + self.trigger('update', [data]);
370 + // NETDATA.chartLibraries[self.data('chart-library')].update(element, data);
371 + }
372 + else {
373 + console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
374 + self.trigger('create', [data]);
375 + //NETDATA.chartLibraries[self.data('chart-library')].create(element, data);
376 + self.data('created', true);
377 + }
378
379 + var ended = new Date().getTime();
380 + self.data('updated', ended);
381 +
382 + var dt = ended - started;
383 +
384 + self.data('refresh-dt', dt);
385 var element_name = self.data('dt-element-name') || null;
386 if(element_name) {
387 var element = document.getElementById(element_name) || null;
@@ -368,38 +389,46 @@
389 element.innerHTML = dt.toString();
390 }
391 }
371 -
372 - if(typeof callback == 'function')
373 - callback();
392 + })
393 + .fail(function() {
394 + NETDATA.messageInABox(element, width, height, 'chart "' + id + '" not found on url "' + url + '"');
395 + })
396 + .always(function() {
397 + if(typeof callback == 'function') callback();
398 });
399 }
400 };
401
378 - function netdataRefreshTargets(targets, index) {
379 - // if(NETDATA.debug) console.log('netdataRefreshTargets(<targets, ' + index + ')');
380 -
381 - var target = targets.get(index);
382 -
383 - if(target == null) {
384 - console.log('restart');
402 + NETDATA.chartRefresher = function(index) {
403 + // if(NETDATA.options.debug) console.log('NETDATA.chartRefresher(<targets, ' + index + ')');
404
386 - // finished, restart
387 - setTimeout(function() {
388 - netdataRefreshTargets(targets, 0);
389 - }, NETDATA.idle_between_loops);
405 + if(NETDATA.options.updated_dom) {
406 + NETDATA.domUpdated(function() {
407 + NETDATA.chartRefresher(0);
408 + });
409 }
410 else {
392 - var self = $(target);
411 + var target = NETDATA.options.targets.get(index);
412 + if(target == null) {
413 + console.log('waiting to restart main loop...');
414
394 - if(!self.data('enabled')) {
395 - netdataRefreshTargets(targets, ++index);
415 + // finished, restart
416 + setTimeout(function() {
417 + NETDATA.chartRefresher(0);
418 + }, NETDATA.options.current.idle_between_loops);
419 }
420 else {
398 - setTimeout(function() {
399 - netdataDownloadChartData.call(target, function() {
400 - netdataRefreshTargets(targets, ++index);
401 - });
402 - }, NETDATA.idle_between_charts);
421 + var self = $(target);
422 + if(!self.data('enabled')) {
423 + NETDATA.chartRefresher(++index);
424 + }
425 + else {
426 + setTimeout(function() {
427 + NETDATA.chartValuesDownloader(target, function() {
428 + NETDATA.chartRefresher(++index);
429 + });
430 + }, NETDATA.options.current.idle_between_charts);
431 + }
432 }
433 }
434 }
@@ -421,7 +450,7 @@
450 if(typeof netdataStopPeity == 'undefined') {
451 $.getScript(NETDATA.peity_js)
452 .done(function() {
424 - NETDATA.registerChartLibrary('peity', NETDATA.peity_js, 'ssvcomma', 'null2zero|flip|min2max', 2);
453 + NETDATA.registerChartLibrary('peity', NETDATA.peity_js);
454 })
455 .fail(function() {
456 NETDATA.error(100, NETDATA.peity_js);
@@ -435,14 +464,14 @@
464 callback();
465 };
466
438 - NETDATA.peityChartUpdate = function(event, data) {
439 - var self = $(this);
467 + NETDATA.peityChartUpdate = function(element, data) {
468 + var self = $(element);
469 var instance = self.html(data).not('[data-created]');
470 instance.change();
471 }
472
444 - NETDATA.peityChartCreate = function(event, data) {
445 - var self = $(this);
473 + NETDATA.peityChartCreate = function(element, data) {
474 + var self = $(element);
475 var width = self.data('width') || NETDATA.chartDefaults.width;
476 var height = self.data('height') || NETDATA.chartDefaults.height;
477 var instance = self.html(data).not('[data-created]');
@@ -461,7 +490,7 @@
490 if(typeof netdataStopSparkline == 'undefined') {
491 $.getScript(NETDATA.sparkline_js)
492 .done(function() {
464 - NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js, 'array', 'flip|min2max', 2);
493 + NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js);
494 })
495 .fail(function() {
496 NETDATA.error(100, NETDATA.sparkline_js);
@@ -475,14 +504,14 @@
504 callback();
505 };
506
478 - NETDATA.sparklineChartUpdate = function(event, data) {
479 - var self = $(this);
507 + NETDATA.sparklineChartUpdate = function(element, data) {
508 + var self = $(element);
509 var options = self.data('sparkline-options');
510 self.sparkline(data, options);
511 }
512
484 - NETDATA.sparklineChartCreate = function(event, data) {
485 - var self = $(this);
513 + NETDATA.sparklineChartCreate = function(element, data) {
514 + var self = $(element);
515 var chart = self.data('chart');
516 var width = self.data('width') || NETDATA.chartDefaults.width;
517 var height = self.data('height') || NETDATA.chartDefaults.height;
@@ -585,7 +614,7 @@
614 };
615
616 var uuid = NETDATA.guid();
588 - this.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
617 + element.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
618 var div = document.getElementById(uuid);
619
620 self.sparkline(data, options);
@@ -623,7 +652,7 @@
652 if(typeof netdataStopDygraph == 'undefined') {
653 $.getScript(NETDATA.dygraph_js)
654 .done(function() {
626 - NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js, 'json', 'ms|flip', 2);
655 + NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js);
656 })
657 .fail(function() {
658 NETDATA.error(100, NETDATA.dygraph_js);
@@ -636,8 +665,8 @@
665 callback();
666 };
667
639 - NETDATA.dygraphChartUpdate = function(event, data) {
640 - var self = $(this);
668 + NETDATA.dygraphChartUpdate = function(element, data) {
669 + var self = $(element);
670 var dygraph = self.data('dygraph-instance');
671
672 if(typeof data.update_every != 'undefined')
@@ -651,8 +680,8 @@
680 console.log('not updating dygraphs');
681 };
682
654 - NETDATA.dygraphChartCreate = function(event, data) {
655 - var self = $(this);
683 + NETDATA.dygraphChartCreate = function(element, data) {
684 + var self = $(element);
685 var width = self.data('width') || NETDATA.chartDefaults.width;
686 var height = self.data('height') || NETDATA.chartDefaults.height;
687 var chart = self.data('chart');
@@ -803,7 +832,7 @@
832
833 $.getScript(NETDATA.morris_js)
834 .done(function() {
806 - NETDATA.registerChartLibrary('morris', NETDATA.morris_js, 'json', 'objectrows|ms', 10);
835 + NETDATA.registerChartLibrary('morris', NETDATA.morris_js);
836 })
837 .fail(function() {
838 NETDATA.error(100, NETDATA.morris_js);
@@ -817,8 +846,8 @@
846 callback();
847 };
848
820 - NETDATA.morrisChartUpdate = function(event, data) {
821 - var self = $(this);
849 + NETDATA.morrisChartUpdate = function(element, data) {
850 + var self = $(element);
851 var width = self.data('width') || NETDATA.chartDefaults.width;
852 var height = self.data('height') || NETDATA.chartDefaults.height;
853 var morris = self.data('morris-instance');
@@ -834,8 +863,8 @@
863 console.log('not updating morris');
864 };
865
837 - NETDATA.morrisChartCreate = function(event, data) {
838 - var self = $(this);
866 + NETDATA.morrisChartCreate = function(element, data) {
867 + var self = $(element);
868 var width = self.data('width') || NETDATA.chartDefaults.width;
869 var height = self.data('height') || NETDATA.chartDefaults.height;
870 var chart = self.data('chart');
@@ -884,7 +913,7 @@
913 if(typeof netdataStopRaphael == 'undefined') {
914 $.getScript(NETDATA.raphael_js)
915 .done(function() {
887 - NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js, 'json', 'flip|min2max', 1);
916 + NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js);
917 })
918 .fail(function() {
919 NETDATA.error(100, NETDATA.raphael_js);
@@ -898,8 +927,8 @@
927 callback();
928 };
929
901 - NETDATA.raphaelChartUpdate = function(event, data) {
902 - var self = $(this);
930 + NETDATA.raphaelChartUpdate = function(element, data) {
931 + var self = $(element);
932 var width = self.data('width') || NETDATA.chartDefaults.width;
933 var height = self.data('height') || NETDATA.chartDefaults.height;
934
@@ -909,8 +938,8 @@
938 })
939 };
940
912 - NETDATA.raphaelChartCreate = function(event, data) {
913 - var self = $(this);
941 + NETDATA.raphaelChartCreate = function(element, data) {
942 + var self = $(element);
943 var width = self.data('width') || NETDATA.chartDefaults.width;
944 var height = self.data('height') || NETDATA.chartDefaults.height;
945
@@ -926,7 +955,7 @@
955
956 NETDATA.googleInitialize = function(callback) {
957 if(typeof netdataStopGoogleCharts == 'undefined' && typeof google != 'undefined') {
929 - NETDATA.registerChartLibrary('google', NETDATA.google_js, 'datatable', '', 3);
958 + NETDATA.registerChartLibrary('google', NETDATA.google_js);
959 if(typeof callback == "function")
960 callback();
961 }
@@ -934,8 +963,8 @@
963 callback();
964 };
965
937 - NETDATA.googleChartUpdate = function(event, data) {
938 - var self = $(this);
966 + NETDATA.googleChartUpdate = function(element, data) {
967 + var self = $(element);
968 var width = self.data('width') || NETDATA.chartDefaults.width;
969 var height = self.data('height') || NETDATA.chartDefaults.height;
970 var gchart = self.data('google-instance');
@@ -949,8 +978,8 @@
978 gchart.draw(datatable, options);
979 };
980
952 - NETDATA.googleChartCreate = function(event, data) {
953 - var self = $(this);
981 + NETDATA.googleChartCreate = function(element, data) {
982 + var self = $(element);
983 var width = self.data('width') || NETDATA.chartDefaults.width;
984 var height = self.data('height') || NETDATA.chartDefaults.height;
985 var chart = self.data('chart');
@@ -1020,7 +1049,7 @@
1049 switch(chart.chart_type) {
1050 case "area":
1051 options.vAxis.viewWindowMode = 'maximized';
1023 - gchart = new google.visualization.AreaChart(this);
1052 + gchart = new google.visualization.AreaChart(element);
1053 break;
1054
1055 case "stacked":
@@ -1029,13 +1058,13 @@
1058 options.vAxis.viewWindowMode = 'maximized';
1059 options.vAxis.minValue = null;
1060 options.vAxis.maxValue = null;
1032 - gchart = new google.visualization.AreaChart(this);
1061 + gchart = new google.visualization.AreaChart(element);
1062 break;
1063
1064 default:
1065 case "line":
1066 options.lineWidth = 2;
1038 - gchart = new google.visualization.LineChart(this);
1067 + gchart = new google.visualization.LineChart(element);
1068 break;
1069 }
1070
@@ -1046,26 +1075,109 @@
1075 .data('created', true);
1076 };
1077
1078 + // ----------------------------------------------------------------------------------------------------------------
1079 + // Charts Libraries Registration
1080 +
1081 + NETDATA.chartLibraries = {
1082 + "dygraph": {
1083 + initialize: NETDATA.dygraphInitialize,
1084 + create: NETDATA.dygraphChartCreate,
1085 + update: NETDATA.dygraphChartUpdate,
1086 + initialized: false,
1087 + enabled: true,
1088 + format: 'json',
1089 + options: 'ms|flip',
1090 + pixels_per_point: 2,
1091 + detects_dimensions_on_update: false
1092 + },
1093 + "sparkline": {
1094 + initialize: NETDATA.sparklineInitialize,
1095 + create: NETDATA.sparklineChartCreate,
1096 + update: NETDATA.sparklineChartUpdate,
1097 + initialized: false,
1098 + enabled: true,
1099 + format: 'array',
1100 + options: 'flip|min2max',
1101 + pixels_per_point: 2,
1102 + detects_dimensions_on_update: false
1103 + },
1104 + "peity": {
1105 + initialize: NETDATA.peityInitialize,
1106 + create: NETDATA.peityChartCreate,
1107 + update: NETDATA.peityChartUpdate,
1108 + initialized: false,
1109 + enabled: true,
1110 + format: 'ssvcomma',
1111 + options: 'null2zero|flip|min2max',
1112 + pixels_per_point: 2,
1113 + detects_dimensions_on_update: false
1114 + },
1115 + "morris": {
1116 + initialize: NETDATA.morrisInitialize,
1117 + create: NETDATA.morrisChartCreate,
1118 + update: NETDATA.morrisChartUpdate,
1119 + initialized: false,
1120 + enabled: true,
1121 + format: 'json',
1122 + options: 'objectrows|ms',
1123 + pixels_per_point: 10,
1124 + detects_dimensions_on_update: false
1125 + },
1126 + "google": {
1127 + initialize: NETDATA.googleInitialize,
1128 + create: NETDATA.googleChartCreate,
1129 + update: NETDATA.googleChartUpdate,
1130 + initialized: false,
1131 + enabled: true,
1132 + format: 'datatable',
1133 + options: '',
1134 + pixels_per_point: 2,
1135 + detects_dimensions_on_update: true
1136 + },
1137 + "raphael": {
1138 + initialize: NETDATA.raphaelInitialize,
1139 + create: NETDATA.raphaelChartCreate,
1140 + update: NETDATA.raphaelChartUpdate,
1141 + initialized: false,
1142 + enabled: true,
1143 + format: 'json',
1144 + options: '',
1145 + pixels_per_point: 1,
1146 + detects_dimensions_on_update: false
1147 + }
1148 + };
1149 +
1150 + NETDATA.registerChartLibrary = function(library, url) {
1151 + console.log("registering chart library: " + library);
1152 +
1153 + NETDATA.chartLibraries[library]
1154 + .url = url
1155 + .initialized = new Date().getTime();
1156 +
1157 + console.log(NETDATA.chartLibraries);
1158 + }
1159 +
1160 // ----------------------------------------------------------------------------------------------------------------
1161 // load all libraries and initialize
1162
1163 NETDATA.errorReset();
1164
1165 NETDATA._loadjQuery(function() {
1055 - NETDATA.raphaelInitialize(function() {
1056 - NETDATA.morrisInitialize(function() {
1057 - NETDATA.peityInitialize(function() {
1058 - NETDATA.sparklineInitialize(function() {
1059 - NETDATA.dygraphInitialize(function() {
1060 - NETDATA.googleInitialize(function() {
1061 - netdataParsePageCharts();
1062 - }) // google
1063 - }) // dygraph.js
1064 - }) // sparkline.js
1065 - }) // piety.js
1066 - }) // morris.js
1067 - }) // raphael.js
1166 + $.getScript(NETDATA.serverDefault + 'lib/visible.js').then(function() {
1167 + NETDATA.raphaelInitialize(function() {
1168 + NETDATA.morrisInitialize(function() {
1169 + NETDATA.peityInitialize(function() {
1170 + NETDATA.sparklineInitialize(function() {
1171 + NETDATA.dygraphInitialize(function() {
1172 + NETDATA.googleInitialize(function() {
1173 + NETDATA.init();
1174 + }) // google
1175 + }) // dygraph.js
1176 + }) // sparkline.js
1177 + }) // piety.js
1178 + }) // morris.js
1179 + }) // raphael.js
1180 + })
1181 });
1182
1183 })(window);
1071 -
web/lib/visible.js new
+26
@@ -0,0 +1,26 @@
1 +(function($){
2 +
3 + /**
4 + * Copyright 2012, Digital Fusion
5 + * Licensed under the MIT license.
6 + * http://teamdf.com/jquery-plugins/license/
7 + *
8 + * @author Sam Sehnert
9 + * @desc A small plugin that checks whether elements are within
10 + * the user visible viewport of a web browser.
11 + * only accounts for vertical position, not horizontal.
12 + */
13 + $.fn.visible = function(partial){
14 +
15 + var $t = $(this),
16 + $w = $(window),
17 + viewTop = $w.scrollTop(),
18 + viewBottom = viewTop + $w.height(),
19 + _top = $t.offset().top,
20 + _bottom = _top + $t.height(),
21 + compareTop = partial === true ? _bottom : _top,
22 + compareBottom = partial === true ? _top : _bottom;
23 +
24 + return ((compareBottom <= viewBottom) && (compareTop >= viewTop));
25 + };
26 +})(jQuery);