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