]> arthur.barton.de Git - netdata.git/blob - node.d/node_modules/netdata.js
added more charts for bind
[netdata.git] / node.d / node_modules / netdata.js
1 'use strict';\r
2 \r
3 var url = require('url');\r
4 var http = require('http');\r
5 var util = require('util');\r
6 \r
7 /*\r
8 var netdata = require('netdata');\r
9 \r
10 var example_chart = {\r
11         id: 'id',                                               // the unique id of the chart\r
12         name: 'name',                                   // the name of the chart\r
13         title: 'title',                                 // the title of the chart\r
14         units: 'units',                                 // the units of the chart dimensions\r
15         family: 'family',                               // the family of the chart\r
16         category: 'category',                   // the category of the chart\r
17         type: netdata.chartTypes.line,  // the type of the chart\r
18         priority: 0,                                    // the priority relative to others in the same family and category\r
19         update_every: 1,                                // the expected update frequency of the chart\r
20         dimensions: {\r
21                 'dim1': {\r
22                         id: 'dim1',                             // the unique id of the dimension\r
23                         name: 'name',                   // the name of the dimension\r
24                         algorithm: netdata.chartAlgorithms.absolute,    // the id of the netdata algorithm\r
25                         multiplier: 1,                  // the multiplier\r
26                         divisor: 1,                             // the divisor\r
27                         hidden: false,                  // is hidden (boolean)\r
28                 },\r
29                 'dim2': {\r
30                         id: 'dim2',                             // the unique id of the dimension\r
31                         name: 'name',                   // the name of the dimension\r
32                         algorithm: 'absolute',  // the id of the netdata algorithm\r
33                         multiplier: 1,                  // the multiplier\r
34                         divisor: 1,                             // the divisor\r
35                         hidden: false,                  // is hidden (boolean)\r
36                 }\r
37                 // add as many dimensions as needed\r
38         }\r
39 };\r
40 */\r
41 \r
42 var netdata = {\r
43         options: {\r
44                 filename: __filename,\r
45                 DEBUG: false,\r
46                 update_every: 1000,\r
47         },\r
48 \r
49         chartAlgorithms: {\r
50                 incremental: 'incremental',\r
51                 absolute: 'absolute',\r
52                 percentage_of_absolute_row: 'percentage-of-absolute-row',\r
53                 percentage_of_incremental_row: 'percentage-of-incremental-row'\r
54         },\r
55 \r
56         chartTypes: {\r
57                 line: 'line',\r
58                 area: 'area',\r
59                 stacked: 'stacked'\r
60         },\r
61 \r
62         services: new Array(),\r
63         modules_configuring: 0,\r
64         charts: {},\r
65 \r
66         stringify: function(obj) {\r
67                 return util.inspect(obj, {depth: 10});\r
68         },\r
69 \r
70         // show debug info, if debug is enabled\r
71         debug: function(msg) {\r
72                 if(this.options.DEBUG === true) {\r
73                         var now = new Date();\r
74                         console.error(now.toString() + ': ' + netdata.options.filename + ': DEBUG: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString());\r
75                 }\r
76         },\r
77 \r
78         // log an error\r
79         error: function(msg) {\r
80                 var now = new Date();\r
81                 console.error(now.toString() + ': ' + netdata.options.filename + ': ERROR: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString());\r
82         },\r
83 \r
84         // send data to netdata\r
85         send: function(msg) {\r
86                 console.log(msg.toString());\r
87         },\r
88 \r
89         serviceAdd: function(service) {\r
90                 if(netdata.serviceIsInitialized(service) === false)\r
91                         netdata.serviceInit(service);\r
92 \r
93                 if(service.added !== true) {\r
94                         service.updates = 0;\r
95                         service.enabled = true;\r
96                         service.added = true;\r
97                         service.running = false;\r
98                         service.started = 0;\r
99                         service.ended = 0;\r
100                         service._current_chart = null; // the current chart we work on\r
101                         service._queue = '';\r
102                         service.queue = function(txt) {\r
103                                 this._queue += txt + '\n';\r
104                         };\r
105 \r
106                         service._send_chart_to_netdata = function(chart) {\r
107                                 // internal function to send a chart to netdata\r
108                                 this.queue('CHART "' + chart.id + '" "' + chart.name + '" "' + chart.title + '" "' + chart.units + '" "' + chart.family + '" "' + chart.category + '" "' + chart.type + '" ' + chart.priority.toString() + ' ' + chart.update_every.toString());\r
109                                 \r
110                                 for(var dim in chart.dimensions) {\r
111                                         var d = chart.dimensions[dim];\r
112 \r
113                                         this.queue('DIMENSION "' + d.id + '" "' + d.name + '" "' + d.algorithm + '" ' + d.multiplier.toString() + ' ' + d.divisor.toString() + ' ' + ((d.hidden === true)?'hidden':'').toString());\r
114                                         d._created = true;\r
115                                         d._updated = false;\r
116                                 }\r
117 \r
118                                 chart._created = true;\r
119                                 chart._updated = false;\r
120                         };\r
121 \r
122                         // begin data collection for a chart\r
123                         service.begin = function(chart) {\r
124                                 if(this._current_chart !== null && this._current_chart !== chart) {\r
125                                         netdata.serviceError(this, 'Called begin() for chart ' + chart.id + ' while chart ' + this._current_chart.id + ' is still open. Closing it.');\r
126                                         this.end();\r
127                                 }\r
128 \r
129                                 if(typeof(chart.id) === 'undefined' || netdata.charts[chart.id] != chart) {\r
130                                         netdata.serviceError(this, 'Called begin() for chart ' + chart.id + ' that is not mine. Where did you find it? Ignoring it.');\r
131                                         return false;\r
132                                 }\r
133 \r
134                                 if(netdata.options.DEBUG === true) netdata.debug('setting current chart to ' + chart.id);\r
135                                 this._current_chart = chart;\r
136                                 this._current_chart._began = true;\r
137 \r
138                                 if(this._current_chart._dimensions_count !== 0) {\r
139                                         if(this._current_chart._created === false || this._current_chart._updated === true)\r
140                                                 this._send_chart_to_netdata(this._current_chart);\r
141 \r
142                                         var now = this.ended;\r
143                                         this.queue('BEGIN ' + this._current_chart.id + ' ' + ((this._current_chart._last_updated > 0)?((now - this._current_chart._last_updated) * 1000):'').toString());\r
144                                 }\r
145                                 // else netdata.serviceError(this, 'Called begin() for chart ' + chart.id + ' which is empty.');\r
146 \r
147                                 this._current_chart._last_updated = now;\r
148                                 this._current_chart._began = true;\r
149                                 this._current_chart._counter++;\r
150 \r
151                                 return true;\r
152                         };\r
153 \r
154                         // set a collected value for a chart\r
155                         // we do most things on the first value we attempt to set\r
156                         service.set = function(dimension, value) {\r
157                                 if(this._current_chart === null) {\r
158                                         netdata.serviceError(this, 'Called set(' + dimension + ', ' + value + ') without an open chart.');\r
159                                         return false;\r
160                                 }\r
161 \r
162                                 if(typeof(this._current_chart.dimensions[dimension]) === 'undefined') {\r
163                                         netdata.serviceError(this, 'Called set(' + dimension + ', ' + value + ') but dimension "' + dimension + '" does not exist in chart "' + this._current_chart.id + '".');\r
164                                         return false;\r
165                                 }\r
166 \r
167                                 if(typeof value === 'undefined' || value === null)\r
168                                         return false;\r
169 \r
170                                 if(this._current_chart._dimensions_count !== 0)\r
171                                         this.queue('SET ' + dimension + ' = ' + value);\r
172 \r
173                                 return true;\r
174                         };\r
175 \r
176                         // end data collection for the current chart - after calling begin()\r
177                         service.end = function() {\r
178                                 if(this._current_chart !== null && this._current_chart._began === false) {\r
179                                         netdata.serviceError(this, 'Called end() without an open chart.');\r
180                                         return false;\r
181                                 }\r
182 \r
183                                 if(this._current_chart._dimensions_count !== 0) {\r
184                                         this.queue('END');\r
185                                         netdata.send(this._queue);\r
186                                 }\r
187 \r
188                                 this._queue = '';\r
189                                 this._current_chart._began = false;\r
190                                 if(netdata.options.DEBUG === true) netdata.debug('committed chart ' + this._current_chart.id);\r
191                                 this._current_chart = null;\r
192                                 return true;\r
193                         };\r
194 \r
195                         // discard the collected values for the current chart - after calling begin()\r
196                         service.flush = function() {\r
197                                 if(this._current_chart === null || this._current_chart._began === false) {\r
198                                         netdata.serviceError(this, 'Called flush() without an open chart.');\r
199                                         return false;\r
200                                 }\r
201 \r
202                                 this._queue = '';\r
203                                 this._current_chart._began = false;\r
204                                 this._current_chart = null;\r
205                                 return true;\r
206                         };\r
207 \r
208                         // create a netdata chart\r
209                         service.chart = function(id, chart) {\r
210                                 if(typeof(netdata.charts[id]) === 'undefined') {\r
211                                         netdata.charts[id] = {\r
212                                                 _created: false,\r
213                                                 _updated: false,\r
214                                                 _began: false,\r
215                                                 _counter: 0,\r
216                                                 _last_updated: 0,\r
217                                                 _dimensions_count: 0,\r
218                                                 id: id,\r
219                                                 name: id,\r
220                                                 title: 'untitled chart',\r
221                                                 units: 'a unit',\r
222                                                 family: id,\r
223                                                 category: id,\r
224                                                 type: netdata.chartTypes.line,\r
225                                                 priority: 0,\r
226                                                 update_every: netdata.options.update_every,\r
227                                                 dimensions: {}\r
228                                         };\r
229                                 }\r
230 \r
231                                 var c = netdata.charts[id];\r
232 \r
233                                 if(typeof(chart.name) !== 'undefined' && chart.name !== c.name) {\r
234                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its name');\r
235                                         c.name = chart.name;\r
236                                         c._updated = true;\r
237                                 }\r
238 \r
239                                 if(typeof(chart.title) !== 'undefined' && chart.title !== c.title) {\r
240                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its title');\r
241                                         c.title = chart.title;\r
242                                         c._updated = true;\r
243                                 }\r
244 \r
245                                 if(typeof(chart.units) !== 'undefined' && chart.units !== c.units) {\r
246                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its units');\r
247                                         c.units = chart.units;\r
248                                         c._updated = true;\r
249                                 }\r
250 \r
251                                 if(typeof(chart.family) !== 'undefined' && chart.family !== c.family) {\r
252                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its family');\r
253                                         c.family = chart.family;\r
254                                         c._updated = true;\r
255                                 }\r
256 \r
257                                 if(typeof(chart.category) !== 'undefined' && chart.category !== c.category) {\r
258                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its category');\r
259                                         c.category = chart.category;\r
260                                         c._updated = true;\r
261                                 }\r
262 \r
263                                 if(typeof(chart.type) !== 'undefined' && chart.type !== c.type) {\r
264                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its type');\r
265                                         c.type = chart.type;\r
266                                         c._updated = true;\r
267                                 }\r
268 \r
269                                 if(typeof(chart.priority) !== 'undefined' && chart.priority !== c.priority) {\r
270                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its priority');\r
271                                         c.priority = chart.priority;\r
272                                         c._updated = true;\r
273                                 }\r
274 \r
275                                 if(typeof(chart.update_every) !== 'undefined' && chart.update_every !== c.update_every) {\r
276                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its update_every');\r
277                                         c.update_every = chart.update_every;\r
278                                         c._updated = true;\r
279                                 }\r
280 \r
281                                 if(typeof(chart.dimensions) !== 'undefined') {\r
282                                         for(var x in chart.dimensions) {\r
283                                                 if(typeof(c.dimensions[x]) === 'undefined') {\r
284                                                         c._dimensions_count++;\r
285 \r
286                                                         c.dimensions[x] = {\r
287                                                                 _created: false,\r
288                                                                 _updated: false,\r
289                                                                 id: x,                                  // the unique id of the dimension\r
290                                                                 name: x,                                // the name of the dimension\r
291                                                                 algorithm: netdata.chartAlgorithms.absolute,    // the id of the netdata algorithm\r
292                                                                 multiplier: 1,                  // the multiplier\r
293                                                                 divisor: 1,                             // the divisor\r
294                                                                 hidden: false,                  // is hidden (boolean)\r
295                                                         };\r
296 \r
297                                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' created dimension ' + x);\r
298                                                         c._updated = true;\r
299                                                 }\r
300 \r
301                                                 var dim = chart.dimensions[x];\r
302                                                 var d = c.dimensions[x];\r
303 \r
304                                                 if(typeof(dim.name) !== 'undefined' && d.name !== dim.name) {\r
305                                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its name');\r
306                                                         d.name = dim.name;\r
307                                                         d._updated = true;\r
308                                                 }\r
309 \r
310                                                 if(typeof(dim.algorithm) !== 'undefined' && d.algorithm !== dim.algorithm) {\r
311                                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its algorithm from ' + d.algorithm + ' to ' + dim.algorithm);\r
312                                                         d.algorithm = dim.algorithm;\r
313                                                         d._updated = true;\r
314                                                 }\r
315 \r
316                                                 if(typeof(dim.multiplier) !== 'undefined' && d.multiplier !== dim.multiplier) {\r
317                                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its multiplier');\r
318                                                         d.multiplier = dim.multiplier;\r
319                                                         d._updated = true;\r
320                                                 }\r
321 \r
322                                                 if(typeof(dim.divisor) !== 'undefined' && d.divisor !== dim.divisor) {\r
323                                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its divisor');\r
324                                                         d.divisor = dim.divisor;\r
325                                                         d._updated = true;\r
326                                                 }\r
327 \r
328                                                 if(typeof(dim.hidden) !== 'undefined' && d.hidden !== dim.hidden) {\r
329                                                         if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its hidden status');\r
330                                                         d.hidden = dim.hidden;\r
331                                                         d._updated = true;\r
332                                                 }\r
333 \r
334                                                 if(d._updated) c._updated = true;\r
335                                         }\r
336                                 }\r
337 \r
338                                 if(netdata.options.DEBUG === true) netdata.debug(netdata.charts);\r
339                                 return netdata.charts[id];\r
340                         };\r
341 \r
342                         this.services.push(service);\r
343                         if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': service added.');\r
344                 }\r
345         },\r
346 \r
347         serviceRun: function(service) {\r
348                 if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': starting data collection...');\r
349                 service.running = true;\r
350                 service.started = new Date().getTime();\r
351                 service.updates++;\r
352 \r
353                 service.module.update(service, function() {\r
354                         service.ended = new Date().getTime();\r
355                         service.duration = service.ended - service.started;\r
356                         if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': data collection ended in ' + service.duration.toString() + ' ms.');\r
357                         service.running = false;\r
358                 });\r
359         },\r
360 \r
361         runAllServices: function() {\r
362                 if(netdata.options.DEBUG === true) netdata.debug('runAllServices()');\r
363 \r
364                 var now = new Date().getTime();\r
365                 var len = netdata.services.length;\r
366                 while(len--) {\r
367                         var service = netdata.services[len];\r
368 \r
369                         if(service.enabled === false || service.running === true) continue;\r
370                         if(now - service.ended < service.update_every) continue;\r
371 \r
372                         netdata.serviceRun(service);\r
373                 }\r
374 \r
375                 setTimeout(netdata.runAllServices, 100);\r
376         },\r
377 \r
378         start: function() {\r
379                 if(netdata.options.DEBUG === true) this.debug('started, services:');\r
380 \r
381                 if(this.services.length === 0) {\r
382                         this.disableNodePlugin();\r
383                         process.exit(1);\r
384                 }\r
385                 else this.runAllServices();\r
386         },\r
387 \r
388         // disable the whole node.js plugin\r
389         disableNodePlugin: function() {\r
390                 this.send('DISABLE');\r
391                 process.exit(1);\r
392         },\r
393 \r
394         requestFromParams: function(protocol, hostname, port, path, method) {\r
395                 return {\r
396                         protocol: protocol,\r
397                         hostname: hostname,\r
398                         port: port,\r
399                         path: path,\r
400                         //family: 4,\r
401                         method: method,\r
402                         headers: {\r
403                                 'Content-Type': 'application/x-www-form-urlencoded',\r
404                                 'Connection': 'keep-alive'\r
405                         },\r
406                         agent: new http.Agent({\r
407                                 keepAlive: true,\r
408                                 keepAliveMsecs: netdata.options.update_every,\r
409                                 maxSockets: 2, // it must be 2 to work\r
410                                 maxFreeSockets: 1\r
411                         })\r
412                 };\r
413         },\r
414 \r
415         requestFromURL: function(a_url) {\r
416                 var u = url.parse(a_url);\r
417                 return netdata.requestFromParams(u.protocol, u.hostname, u.port, u.path, 'GET');\r
418         },\r
419 \r
420         processResponse: function(service, data, callback) {\r
421                 if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': processing response...');\r
422 \r
423                 callback(service, data);\r
424 \r
425                 service.module.running--;\r
426                 if(service.module.running <= 0) {\r
427                         service.module.running = 0;\r
428 \r
429                         // check if we run under configure\r
430                         if(service.module.configure_callback !== null) {\r
431                                 if(netdata.options.DEBUG === true) this.debug(service.module.name + ': configuration finish callback called from processResponse().');\r
432                                 var ccallback = service.module.configure_callback;\r
433                                 service.module.configure_callback = null;\r
434                                 ccallback();\r
435                         }\r
436                 }\r
437         },\r
438 \r
439         serviceError: function(service, message) {\r
440                 if(service.error_reported === false) {\r
441                         netdata.error(service.module.name + ': ' + service.name + ': ' + message);\r
442                         service.error_reported = true;\r
443                 }\r
444                 else if(netdata.options.DEBUG === true)\r
445                         netdata.debug(service.module.name + ': ' + service.name + ': ' + message);\r
446         },\r
447 \r
448         serviceErrorClear: function(service) {\r
449                 service.error_reported = false;\r
450         },\r
451 \r
452         serviceInit: function(service) {\r
453                 service.error_reported = false;\r
454                 service.added = false;\r
455                 service.enabled = true;\r
456         },\r
457 \r
458         serviceIsInitialized: function(service) {\r
459                 if(typeof service.error_reported === 'undefined')\r
460                         return false;\r
461 \r
462                 return true;\r
463         },\r
464 \r
465         getResponse: function(service, response, callback) {\r
466                 if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': got response...');\r
467 \r
468                 var end = false;\r
469                 var data = '';\r
470                 response.setEncoding('utf8');\r
471 \r
472                 if(response.statusCode !== 200) {\r
473                         if(end === false) {\r
474                                 netdata.serviceError(service, ': got HTTP code ' + response.statusCode + ', failed to get data.');\r
475                                 end = true;\r
476                                 netdata.processResponse(service, null, callback);\r
477                         }\r
478                 }\r
479 \r
480                 response.on('data', function(chunk) {\r
481                         if(end === false) data += chunk;\r
482                 });\r
483 \r
484                 response.on('error', function() {\r
485                         if(end === false) {\r
486                                 netdata.serviceError(service, ': Read error, failed to get data.');\r
487                                 end = true;\r
488                                 netdata.processResponse(service, null, callback);\r
489                         }\r
490                 });\r
491 \r
492                 response.on('end', function() {\r
493                         if(end === false) {\r
494                                 netdata.serviceErrorClear(service);\r
495                                 if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': read completed.');\r
496                                 end = true;\r
497                                 netdata.processResponse(service, data, callback);\r
498                         }\r
499                 });\r
500         },\r
501 \r
502         serviceExecute: function(service, callback) {\r
503                 if(netdata.serviceIsInitialized(service) === false)\r
504                         netdata.serviceInit(service);\r
505 \r
506                 service.module.running++;\r
507 \r
508                 if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': making request: ' + netdata.stringify(service.request));\r
509                 var req = http.request(service.request, function(response) {\r
510                         if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': request done.');\r
511                         netdata.getResponse(service, response, callback);\r
512                 });\r
513 \r
514                 req.on('error', function(e) {\r
515                         netdata.serviceError(service, ': failed to make request: ' + netdata.stringify(service.request) + ', message: ' + e.message);\r
516                         netdata.processResponse(service, null, callback);\r
517                 });\r
518 \r
519                 // write data to request body\r
520                 if(typeof service.postData !== 'undefined' && service.request.method === 'POST') {\r
521                         if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': posting data: ' + service.postData);\r
522                         req.write(service.postData);\r
523                 }\r
524 \r
525                 req.end();\r
526         },\r
527 \r
528         configure: function(module, config, callback) {\r
529                 if(netdata.options.DEBUG === true) this.debug(module.name + ': configuring (update_every: ' + this.options.update_every + ')...');\r
530 \r
531                 module.running = 0;\r
532                 module.update_every = this.options.update_every;\r
533 \r
534                 if(typeof config.update_every !== 'undefined')\r
535                         module.update_every = config.update_every * 1000;\r
536 \r
537                 module.enable_autodetect = (config.enable_autodetect)?true:false;\r
538 \r
539                 if(typeof(callback) === 'function')\r
540                         module.configure_callback = callback;\r
541                 else\r
542                         module.configure_callback = null;\r
543 \r
544                 var added = module.configure(config);\r
545 \r
546                 if(netdata.options.DEBUG === true) this.debug(module.name + ': configured, reporting ' + added + ' eligible services.');\r
547 \r
548                 if(module.configure_callback !== null && added === 0) {\r
549                         if(netdata.options.DEBUG === true) this.debug(module.name + ': configuration finish callback called from configure().');\r
550                         module.configure_callback = null;\r
551                         callback();\r
552                 }\r
553 \r
554                 return added;\r
555         }\r
556 \r
557 };\r
558 \r
559 if(netdata.options.DEBUG === true) netdata.debug('loaded netdata from: ' + __filename);\r
560 module.exports = netdata;\r
561 \r
562 /*\r
563 var test1 = netdata.chart('test1', { name: 'test name', dimensions: { dim1: {}}});\r
564 netdata.begin(test1);\r
565 netdata.set('dim1', 1);\r
566 netdata.end();\r
567 netdata.begin(test1);\r
568 netdata.set('dim1', 2);\r
569 netdata.end();\r
570 netdata.begin(test1);\r
571 netdata.set('dim1', 3);\r
572 netdata.end();\r
573 netdata.begin(test1);\r
574 netdata.set('dim1', 4);\r
575 netdata.end();\r
576 */\r