@cryptotaxi247 / netdata-1 / commits / ccb789708

added command line arguments in node.d.plugin to enabled selected modules; refactored netdata.js for clearance

Costa Tsaousis (ktsaou) committed Feb 4, 2016 at 01:29 UTC ccb789708de8b8126ddd17cfaf8e2c3623e4c073
4 files changed +1003 -987
node.d/named.node.js
+588 -586
@@ -1,586 +1,588 @@
1 -'use strict';
2 -
3 -// collect statistics from bind (named) v9.10+
4 -//
5 -// bind statistics documentation at:
6 -// http://jpmens.net/2013/03/18/json-in-bind-9-s-statistics-server/
7 -// https://ftp.isc.org/isc/bind/9.10.3/doc/arm/Bv9ARM.ch06.html#statistics
8 -
9 -// example configuration in /etc/netdata/named.conf
10 -// the module supports auto-detection if bind is running in localhost
11 -
12 -/*
13 -{
14 - "enable_autodetect": true,
15 - "update_every": 5,
16 - "servers": [
17 - {
18 - "name": "bind1",
19 - "url": "http://127.0.0.1:8888/json/v1/server",
20 - "update_every": 1
21 - },
22 - {
23 - "name": "bind2",
24 - "url": "http://10.0.0.1:8888/xml/v3/server",
25 - "update_every": 2
26 - }
27 - ]
28 -}
29 -*/
30 -
31 -// the following is the bind named.conf configuration required
32 -
33 -/*
34 -statistics-channels {
35 - inet 127.0.0.1 port 8888 allow { 127.0.0.1; };
36 -};
37 -*/
38 -
39 -var url = require('url');
40 -var http = require('http');
41 -var XML = require('pixl-xml');
42 -var netdata = require('netdata');
43 -
44 -if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
45 -
46 -var named = {
47 - name: __filename,
48 - enable_autodetect: true,
49 - update_every: 1000,
50 -
51 - charts: {},
52 -
53 - chartFromMembersCreate: function(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor) {
54 - var chart = {
55 - id: id, // the unique id of the chart
56 - name: '', // the unique name of the chart
57 - title: service.name + ' ' + title_suffix, // the title of the chart
58 - units: units, // the units of the chart dimensions
59 - family: family_prefix + '_' + service.name, // the family of the chart
60 - category: category_prefix + '_' + service.name, // the category of the chart
61 - type: type, // the type of the chart
62 - priority: priority, // the priority relative to others in the same family and category
63 - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
64 - dimensions: {}
65 - }
66 -
67 - var found = 0;
68 - for(var x in obj) {
69 - if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
70 - found++;
71 - chart.dimensions[x] = {
72 - id: x, // the unique id of the dimension
73 - name: x, // the name of the dimension
74 - algorithm: algorithm, // the id of the netdata algorithm
75 - multiplier: multiplier, // the multiplier
76 - divisor: divisor, // the divisor
77 - hidden: false // is hidden (boolean)
78 - }
79 - }
80 - }
81 -
82 - if(found === false)
83 - return null;
84 -
85 - chart = service.chart(id, chart);
86 - this.charts[id] = chart;
87 - return chart;
88 - },
89 -
90 - chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor) {
91 - var id = 'named_' + service.name + '.' + id_suffix;
92 - var chart = this.charts[id];
93 -
94 - if(typeof chart === 'undefined') {
95 - chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor);
96 - if(chart === null) return false;
97 - }
98 - else {
99 - // check if we need to re-generate the chart
100 - for(var x in obj) {
101 - if(typeof(chart.dimensions[x]) === 'undefined') {
102 - chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor);
103 - if(chart === null) return false;
104 - break;
105 - }
106 - }
107 - }
108 -
109 - var found = 0;
110 - service.begin(chart);
111 - for(var x in obj) {
112 - if(typeof(chart.dimensions[x]) !== 'undefined') {
113 - found++;
114 - service.set(x, obj[x]);
115 - }
116 - }
117 - service.end();
118 -
119 - if(found > 0) return true;
120 - return false;
121 - },
122 -
123 - // an index to map values to different charts
124 - lookups: {
125 - nsstats: {},
126 - resolver_stats: {},
127 - numfetch: {}
128 - },
129 -
130 - // transform the XML response of bind
131 - // to the JSON response of bind
132 - xml2js: function(service, data_xml) {
133 - var d = XML.parse(data_xml);
134 - if(d === null) return null;
135 -
136 - var data = {};
137 - var len = d.server.counters.length;
138 - while(len--) {
139 - var a = d.server.counters[len];
140 - if(typeof a.counter === 'undefined') continue;
141 - if(a.type === 'opcode') a.type = 'opcodes';
142 - else if(a.type === 'qtype') a.type = 'qtypes';
143 - else if(a.type === 'nsstat') a.type = 'nsstats';
144 - var aa = data[a.type] = {};
145 - var alen = 0
146 - var alen2 = a.counter.length;
147 - while(alen < alen2) {
148 - aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
149 - alen++;
150 - }
151 - }
152 -
153 - data.views = {};
154 - var vlen = d.views.view.length;
155 - while(vlen--) {
156 - var vname = d.views.view[vlen].name;
157 - data.views[vname] = { resolver: {} };
158 - var len = d.views.view[vlen].counters.length;
159 - while(len--) {
160 - var a = d.views.view[vlen].counters[len];
161 - if(typeof a.counter === 'undefined') continue;
162 - if(a.type === 'resstats') a.type = 'stats';
163 - else if(a.type === 'resqtype') a.type = 'qtypes';
164 - else if(a.type === 'adbstat') a.type = 'adb';
165 - var aa = data.views[vname].resolver[a.type] = {};
166 - var alen = 0;
167 - var alen2 = a.counter.length;
168 - while(alen < alen2) {
169 - aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
170 - alen++;
171 - }
172 - }
173 - }
174 -
175 - return data;
176 - },
177 -
178 - processResponse: function(service, data) {
179 - if(data !== null) {
180 - var r;
181 -
182 - // parse XML or JSON
183 - // pepending on the URL given
184 - if(service.request.path.match(/^\/xml/) !== null)
185 - r = named.xml2js(service, data);
186 - else
187 - r = JSON.parse(data);
188 -
189 - if(typeof r === 'undefined' || r === null) {
190 - netdata.serviceError(service, "Cannot parse these data: " + data);
191 - return;
192 - }
193 -
194 - if(service.added !== true)
195 - netdata.serviceAdd(service);
196 -
197 - if(typeof r.nsstats !== 'undefined') {
198 - // we split the nsstats object to several others
199 - var global_requests = {}, global_requests_enable = false;
200 - var global_failures = {}, global_failures_enable = false;
201 - var global_failures_detail = {}, global_failures_detail_enable = false;
202 - var global_updates = {}, global_updates_enable = false;
203 - var protocol_queries = {}, protocol_queries_enable = false;
204 - var global_queries = {}, global_queries_enable = false;
205 - var global_queries_success = {}, global_queries_success_enable = false;
206 - var default_enable = false;
207 - var RecursClients = 0;
208 -
209 - // RecursClients is an absolute value
210 - if(typeof r.nsstats['RecursClients'] !== 'undefined') {
211 - RecursClients = r.nsstats['RecursClients'];
212 - delete r.nsstats['RecursClients'];
213 - }
214 -
215 - for( var x in r.nsstats ) {
216 - // we maintain an index of the values found
217 - // mapping them to objects splitted
218 -
219 - var look = named.lookups.nsstats[x];
220 - if(typeof look === 'undefined') {
221 - // a new value, not found in the index
222 - // index it:
223 - if(x === 'Requestv4') {
224 - named.lookups.nsstats[x] = {
225 - name: 'IPv4',
226 - type: 'global_requests'
227 - };
228 - }
229 - else if(x === 'Requestv6') {
230 - named.lookups.nsstats[x] = {
231 - name: 'IPv6',
232 - type: 'global_requests'
233 - };
234 - }
235 - else if(x === 'QryFailure') {
236 - named.lookups.nsstats[x] = {
237 - name: 'failures',
238 - type: 'global_failures'
239 - };
240 - }
241 - else if(x === 'QryUDP') {
242 - named.lookups.nsstats[x] = {
243 - name: 'UDP',
244 - type: 'protocol_queries'
245 - };
246 - }
247 - else if(x === 'QryTCP') {
248 - named.lookups.nsstats[x] = {
249 - name: 'TCP',
250 - type: 'protocol_queries'
251 - };
252 - }
253 - else if(x === 'QrySuccess') {
254 - named.lookups.nsstats[x] = {
255 - name: 'queries',
256 - type: 'global_queries_success'
257 - };
258 - }
259 - else if(x.match(/QryRej$/) !== null) {
260 - named.lookups.nsstats[x] = {
261 - name: x,
262 - type: 'global_failures_detail'
263 - };
264 - }
265 - else if(x.match(/^Qry/) !== null) {
266 - named.lookups.nsstats[x] = {
267 - name: x,
268 - type: 'global_queries'
269 - };
270 - }
271 - else if(x.match(/^Update/) !== null) {
272 - named.lookups.nsstats[x] = {
273 - name: x,
274 - type: 'global_updates'
275 - };
276 - }
277 - else {
278 - // values not mapped, will remain
279 - // in the default map
280 - named.lookups.nsstats[x] = {
281 - name: x,
282 - type: 'default'
283 - };
284 - }
285 -
286 - look = named.lookups.nsstats[x];
287 - // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);
288 - }
289 -
290 - switch(look.type) {
291 - case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;
292 - case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;
293 - case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;
294 - case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;
295 - case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;
296 - case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;
297 - case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;
298 - default: default_enable = true; break;
299 - }
300 - }
301 -
302 - if(global_requests_enable == true)
303 - service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 100, netdata.chartAlgorithms.incremental, 1, 1);
304 -
305 - if(global_queries_success_enable == true)
306 - service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'named', 'named', netdata.chartTypes.line, 150, netdata.chartAlgorithms.incremental, 1, 1);
307 -
308 - if(protocol_queries_enable == true)
309 - service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'named', 'named', netdata.chartTypes.stacked, 200, netdata.chartAlgorithms.incremental, 1, 1);
310 -
311 - if(global_queries_enable == true)
312 - service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'named', 'named', netdata.chartTypes.stacked, 300, netdata.chartAlgorithms.incremental, 1, 1);
313 -
314 - if(global_updates_enable == true)
315 - service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'named', 'named', netdata.chartTypes.stacked, 900, netdata.chartAlgorithms.incremental, 1, 1);
316 -
317 - if(global_failures_enable == true)
318 - service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'named', 'named', netdata.chartTypes.line, 950, netdata.chartAlgorithms.incremental, 1, 1);
319 -
320 - if(global_failures_detail_enable == true)
321 - service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'named', 'named', netdata.chartTypes.stacked, 960, netdata.chartAlgorithms.incremental, 1, 1);
322 -
323 - if(default_enable === true)
324 - service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'named', 'named', netdata.chartTypes.line, 999, netdata.chartAlgorithms.incremental, 1, 1);
325 -
326 - // RecursClients chart
327 - {
328 - var id = 'named_' + service.name + '.recursive_clients';
329 - var chart = named.charts[id];
330 -
331 - if(typeof chart === 'undefined') {
332 - chart = {
333 - id: id, // the unique id of the chart
334 - name: '', // the unique name of the chart
335 - title: service.name + ' Bind, Current Recursive Clients', // the title of the chart
336 - units: 'clients', // the units of the chart dimensions
337 - family: 'named', // the family of the chart
338 - category: 'named', // the category of the chart
339 - type: netdata.chartTypes.line, // the type of the chart
340 - priority: 150, // the priority relative to others in the same family and category
341 - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
342 - dimensions: {
343 - 'clients': {
344 - id: 'clients', // the unique id of the dimension
345 - name: '', // the name of the dimension
346 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
347 - multiplier: 1, // the multiplier
348 - divisor: 1, // the divisor
349 - hidden: false // is hidden (boolean)
350 - }
351 - }
352 - };
353 -
354 - chart = service.chart(id, chart);
355 - named.charts[id] = chart;
356 - }
357 -
358 - service.begin(chart);
359 - service.set('clients', RecursClients);
360 - service.end();
361 - }
362 - }
363 -
364 - if(typeof r.opcodes !== 'undefined')
365 - service.module.chartFromMembers(service, r.opcodes, 'in_opcodes', 'Bind, Global Incoming Requests by OpCode', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 1000, netdata.chartAlgorithms.incremental, 1, 1);
366 -
367 - if(typeof r.qtypes !== 'undefined')
368 - service.module.chartFromMembers(service, r.qtypes, 'in_qtypes', 'Bind, Global Incoming Requests by Query Type', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 2000, netdata.chartAlgorithms.incremental, 1, 1);
369 -
370 - if(typeof r.sockstats !== 'undefined')
371 - service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'named', 'named', netdata.chartTypes.line, 2500, netdata.chartAlgorithms.incremental, 1, 1);
372 -
373 - if(typeof r.views !== 'undefined') {
374 - for( var x in r.views ) {
375 - var resolver = r.views[x].resolver;
376 -
377 - if(typeof resolver !== 'undefined') {
378 - if(typeof resolver.stats !== 'undefined') {
379 - var NumFetch = 0;
380 - var key = service.name + '.' + x;
381 - var default_enable = false;
382 - var rtt = {}, rtt_enable = false;
383 -
384 - // NumFetch is an absolute value
385 - if(typeof resolver.stats['NumFetch'] !== 'undefined') {
386 - named.lookups.numfetch[key] = true;
387 - NumFetch = resolver.stats['NumFetch'];
388 - delete resolver.stats['NumFetch'];
389 - }
390 - if(typeof resolver.stats['BucketSize'] !== 'undefined') {
391 - delete resolver.stats['BucketSize'];
392 - }
393 -
394 - // split the QryRTT* from the main chart
395 - for( var y in resolver.stats ) {
396 - // we maintain an index of the values found
397 - // mapping them to objects splitted
398 -
399 - var look = named.lookups.resolver_stats[y];
400 - if(typeof look === 'undefined') {
401 - if(y.match(/^QryRTT/) !== null) {
402 - named.lookups.resolver_stats[y] = {
403 - name: y,
404 - type: 'rtt'
405 - };
406 - }
407 - else {
408 - named.lookups.resolver_stats[y] = {
409 - name: y,
410 - type: 'default'
411 - };
412 - }
413 -
414 - look = named.lookups.resolver_stats[y];
415 - // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);
416 - }
417 -
418 - switch(look.type) {
419 - case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;
420 - default: default_enable = true; break;
421 - }
422 - }
423 -
424 - if(rtt_enable)
425 - service.module.chartFromMembers(service, rtt, 'view_resolver_rtt_' + x, 'Bind, ' + x + ' View, Resolver Round Trip Timings', 'queries/s', 'named', 'named', netdata.chartTypes.stacked, 5600, netdata.chartAlgorithms.incremental, 1, 1);
426 -
427 - if(default_enable)
428 - service.module.chartFromMembers(service, resolver.stats, 'view_resolver_stats_' + x, 'Bind, ' + x + ' View, Resolver Statistics', 'operations/s', 'named', 'named', netdata.chartTypes.line, 5500, netdata.chartAlgorithms.incremental, 1, 1);
429 -
430 - // NumFetch chart
431 - if(typeof named.lookups.numfetch[key] !== 'undefined') {
432 - var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
433 - var chart = named.charts[id];
434 -
435 - if(typeof chart === 'undefined') {
436 - chart = {
437 - id: id, // the unique id of the chart
438 - name: '', // the unique name of the chart
439 - title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries', // the title of the chart
440 - units: 'queries', // the units of the chart dimensions
441 - family: 'named', // the family of the chart
442 - category: 'named', // the category of the chart
443 - type: netdata.chartTypes.line, // the type of the chart
444 - priority: 5000, // the priority relative to others in the same family and category
445 - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
446 - dimensions: {
447 - 'queries': {
448 - id: 'queries', // the unique id of the dimension
449 - name: '', // the name of the dimension
450 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
451 - multiplier: 1, // the multiplier
452 - divisor: 1, // the divisor
453 - hidden: false // is hidden (boolean)
454 - }
455 - }
456 - };
457 -
458 - chart = service.chart(id, chart);
459 - named.charts[id] = chart;
460 - }
461 -
462 - service.begin(chart);
463 - service.set('queries', NumFetch);
464 - service.end();
465 - }
466 - }
467 - }
468 -
469 - if(typeof resolver.qtypes !== 'undefined')
470 - service.module.chartFromMembers(service, resolver.qtypes, 'view_resolver_qtypes_' + x, 'Bind, ' + x + ' View, Requests by Query Type', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 6000, netdata.chartAlgorithms.incremental, 1, 1);
471 -
472 - //if(typeof resolver.cache !== 'undefined')
473 - // service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'named', 'named', netdata.chartTypes.stacked, 7000, netdata.chartAlgorithms.absolute, 1, 1);
474 -
475 - if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
476 - var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
477 - var chart = named.charts[id];
478 -
479 - if(typeof chart === 'undefined') {
480 - chart = {
481 - id: id, // the unique id of the chart
482 - name: '', // the unique name of the chart
483 - title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits', // the title of the chart
484 - units: 'operations/s', // the units of the chart dimensions
485 - family: 'named', // the family of the chart
486 - category: 'named', // the category of the chart
487 - type: netdata.chartTypes.area, // the type of the chart
488 - priority: 8000, // the priority relative to others in the same family and category
489 - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
490 - dimensions: {
491 - 'CacheHits': {
492 - id: 'CacheHits', // the unique id of the dimension
493 - name: 'hits', // the name of the dimension
494 - algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
495 - multiplier: 1, // the multiplier
496 - divisor: 1, // the divisor
497 - hidden: false // is hidden (boolean)
498 - },
499 - 'CacheMisses': {
500 - id: 'CacheMisses', // the unique id of the dimension
501 - name: 'misses', // the name of the dimension
502 - algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
503 - multiplier: -1, // the multiplier
504 - divisor: 1, // the divisor
505 - hidden: false // is hidden (boolean)
506 - }
507 - }
508 - };
509 -
510 - chart = service.chart(id, chart);
511 - named.charts[id] = chart;
512 - }
513 -
514 - service.begin(chart);
515 - service.set('CacheHits', resolver.cachestats['CacheHits']);
516 - service.set('CacheMisses', resolver.cachestats['CacheMisses']);
517 - service.end();
518 - }
519 -
520 - // this is wrong, it contains many types of info:
521 - // 1. CacheHits, CacheMisses - incremental (added above)
522 - // 2. QueryHits, QueryMisses - incremental
523 - // 3. DeleteLRU, DeleteTTL - incremental
524 - // 4. CacheNodes, CacheBuckets - absolute
525 - // 5. TreeMemTotal, TreeMemInUse - absolute
526 - // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute
527 - //if(typeof resolver.cachestats !== 'undefined')
528 - // service.module.chartFromMembers(service, resolver.cachestats, 'view_resolver_cachestats_' + x, 'Bind, ' + x + ' View, Cache Statistics', 'requests/s', 'named', 'named', netdata.chartTypes.line, 8000, netdata.chartAlgorithms.incremental, 1, 1);
529 -
530 - //if(typeof resolver.adb !== 'undefined')
531 - // service.module.chartFromMembers(service, resolver.adb, 'view_resolver_adb_' + x, 'Bind, ' + x + ' View, ADB Statistics', 'entries', 'named', 'named', netdata.chartTypes.line, 8500, netdata.chartAlgorithms.absolute, 1, 1);
532 - }
533 - }
534 - }
535 - },
536 -
537 - // module.serviceExecute()
538 - // this function is called only from this module
539 - // its purpose is to prepare the request and call
540 - // netdata.serviceExecute()
541 - serviceExecute: function(name, a_url, update_every) {
542 - if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);
543 - netdata.serviceExecute({
544 - name: name,
545 - request: netdata.requestFromURL(a_url),
546 - update_every: update_every,
547 - module: this
548 - }, this.processResponse);
549 - },
550 -
551 - configure: function(config) {
552 - var added = 0;
553 -
554 - if(this.enable_autodetect === true) {
555 - this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);
556 - added++;
557 - }
558 -
559 - if(typeof(config.servers) !== 'undefined') {
560 - var len = config.servers.length;
561 - while(len--) {
562 - if(typeof config.servers[len].update_every === 'undefined')
563 - config.servers[len].update_every = this.update_every;
564 - else
565 - config.servers[len].update_every = config.servers[len].update_every * 1000;
566 -
567 - this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);
568 - added++;
569 - }
570 - }
571 -
572 - return added;
573 - },
574 -
575 - // module.update()
576 - // this is called repeatidly to collect data, by calling
577 - // netdata.serviceExecute()
578 - update: function(service, callback) {
579 - netdata.serviceExecute(service, function(serv, data) {
580 - service.module.processResponse(serv, data);
581 - callback();
582 - });
583 - },
584 -};
585 -
586 -module.exports = named;
1 +'use strict';
2 +
3 +// collect statistics from bind (named) v9.10+
4 +//
5 +// bind statistics documentation at:
6 +// http://jpmens.net/2013/03/18/json-in-bind-9-s-statistics-server/
7 +// https://ftp.isc.org/isc/bind/9.10.3/doc/arm/Bv9ARM.ch06.html#statistics
8 +
9 +// example configuration in /etc/netdata/named.conf
10 +// the module supports auto-detection if bind is running in localhost
11 +
12 +/*
13 +{
14 + "enable_autodetect": true,
15 + "update_every": 5,
16 + "servers": [
17 + {
18 + "name": "bind1",
19 + "url": "http://127.0.0.1:8888/json/v1/server",
20 + "update_every": 1
21 + },
22 + {
23 + "name": "bind2",
24 + "url": "http://10.0.0.1:8888/xml/v3/server",
25 + "update_every": 2
26 + }
27 + ]
28 +}
29 +*/
30 +
31 +// the following is the bind named.conf configuration required
32 +
33 +/*
34 +statistics-channels {
35 + inet 127.0.0.1 port 8888 allow { 127.0.0.1; };
36 +};
37 +*/
38 +
39 +var url = require('url');
40 +var http = require('http');
41 +var XML = require('pixl-xml');
42 +var netdata = require('netdata');
43 +
44 +if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
45 +
46 +var named = {
47 + name: __filename,
48 + enable_autodetect: true,
49 + update_every: 1000,
50 +
51 + charts: {},
52 +
53 + chartFromMembersCreate: function(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor) {
54 + var chart = {
55 + id: id, // the unique id of the chart
56 + name: '', // the unique name of the chart
57 + title: service.name + ' ' + title_suffix, // the title of the chart
58 + units: units, // the units of the chart dimensions
59 + family: family_prefix + '_' + service.name, // the family of the chart
60 + category: category_prefix + '_' + service.name, // the category of the chart
61 + type: type, // the type of the chart
62 + priority: priority, // the priority relative to others in the same family and category
63 + update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
64 + dimensions: {}
65 + }
66 +
67 + var found = 0;
68 + for(var x in obj) {
69 + if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
70 + found++;
71 + chart.dimensions[x] = {
72 + id: x, // the unique id of the dimension
73 + name: x, // the name of the dimension
74 + algorithm: algorithm, // the id of the netdata algorithm
75 + multiplier: multiplier, // the multiplier
76 + divisor: divisor, // the divisor
77 + hidden: false // is hidden (boolean)
78 + }
79 + }
80 + }
81 +
82 + if(found === false)
83 + return null;
84 +
85 + chart = service.chart(id, chart);
86 + this.charts[id] = chart;
87 + return chart;
88 + },
89 +
90 + chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor) {
91 + var id = 'named_' + service.name + '.' + id_suffix;
92 + var chart = this.charts[id];
93 +
94 + if(typeof chart === 'undefined') {
95 + chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor);
96 + if(chart === null) return false;
97 + }
98 + else {
99 + // check if we need to re-generate the chart
100 + for(var x in obj) {
101 + if(typeof(chart.dimensions[x]) === 'undefined') {
102 + chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor);
103 + if(chart === null) return false;
104 + break;
105 + }
106 + }
107 + }
108 +
109 + var found = 0;
110 + service.begin(chart);
111 + for(var x in obj) {
112 + if(typeof(chart.dimensions[x]) !== 'undefined') {
113 + found++;
114 + service.set(x, obj[x]);
115 + }
116 + }
117 + service.end();
118 +
119 + if(found > 0) return true;
120 + return false;
121 + },
122 +
123 + // an index to map values to different charts
124 + lookups: {
125 + nsstats: {},
126 + resolver_stats: {},
127 + numfetch: {}
128 + },
129 +
130 + // transform the XML response of bind
131 + // to the JSON response of bind
132 + xml2js: function(service, data_xml) {
133 + var d = XML.parse(data_xml);
134 + if(d === null) return null;
135 +
136 + var data = {};
137 + var len = d.server.counters.length;
138 + while(len--) {
139 + var a = d.server.counters[len];
140 + if(typeof a.counter === 'undefined') continue;
141 + if(a.type === 'opcode') a.type = 'opcodes';
142 + else if(a.type === 'qtype') a.type = 'qtypes';
143 + else if(a.type === 'nsstat') a.type = 'nsstats';
144 + var aa = data[a.type] = {};
145 + var alen = 0
146 + var alen2 = a.counter.length;
147 + while(alen < alen2) {
148 + aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
149 + alen++;
150 + }
151 + }
152 +
153 + data.views = {};
154 + var vlen = d.views.view.length;
155 + while(vlen--) {
156 + var vname = d.views.view[vlen].name;
157 + data.views[vname] = { resolver: {} };
158 + var len = d.views.view[vlen].counters.length;
159 + while(len--) {
160 + var a = d.views.view[vlen].counters[len];
161 + if(typeof a.counter === 'undefined') continue;
162 + if(a.type === 'resstats') a.type = 'stats';
163 + else if(a.type === 'resqtype') a.type = 'qtypes';
164 + else if(a.type === 'adbstat') a.type = 'adb';
165 + var aa = data.views[vname].resolver[a.type] = {};
166 + var alen = 0;
167 + var alen2 = a.counter.length;
168 + while(alen < alen2) {
169 + aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
170 + alen++;
171 + }
172 + }
173 + }
174 +
175 + return data;
176 + },
177 +
178 + processResponse: function(service, data) {
179 + if(data !== null) {
180 + var r;
181 +
182 + // parse XML or JSON
183 + // pepending on the URL given
184 + if(service.request.path.match(/^\/xml/) !== null)
185 + r = named.xml2js(service, data);
186 + else
187 + r = JSON.parse(data);
188 +
189 + if(typeof r === 'undefined' || r === null) {
190 + netdata.serviceError(service, "Cannot parse these data: " + data);
191 + return;
192 + }
193 +
194 + if(service.added !== true)
195 + service.commit();
196 +
197 + if(typeof r.nsstats !== 'undefined') {
198 + // we split the nsstats object to several others
199 + var global_requests = {}, global_requests_enable = false;
200 + var global_failures = {}, global_failures_enable = false;
201 + var global_failures_detail = {}, global_failures_detail_enable = false;
202 + var global_updates = {}, global_updates_enable = false;
203 + var protocol_queries = {}, protocol_queries_enable = false;
204 + var global_queries = {}, global_queries_enable = false;
205 + var global_queries_success = {}, global_queries_success_enable = false;
206 + var default_enable = false;
207 + var RecursClients = 0;
208 +
209 + // RecursClients is an absolute value
210 + if(typeof r.nsstats['RecursClients'] !== 'undefined') {
211 + RecursClients = r.nsstats['RecursClients'];
212 + delete r.nsstats['RecursClients'];
213 + }
214 +
215 + for( var x in r.nsstats ) {
216 + // we maintain an index of the values found
217 + // mapping them to objects splitted
218 +
219 + var look = named.lookups.nsstats[x];
220 + if(typeof look === 'undefined') {
221 + // a new value, not found in the index
222 + // index it:
223 + if(x === 'Requestv4') {
224 + named.lookups.nsstats[x] = {
225 + name: 'IPv4',
226 + type: 'global_requests'
227 + };
228 + }
229 + else if(x === 'Requestv6') {
230 + named.lookups.nsstats[x] = {
231 + name: 'IPv6',
232 + type: 'global_requests'
233 + };
234 + }
235 + else if(x === 'QryFailure') {
236 + named.lookups.nsstats[x] = {
237 + name: 'failures',
238 + type: 'global_failures'
239 + };
240 + }
241 + else if(x === 'QryUDP') {
242 + named.lookups.nsstats[x] = {
243 + name: 'UDP',
244 + type: 'protocol_queries'
245 + };
246 + }
247 + else if(x === 'QryTCP') {
248 + named.lookups.nsstats[x] = {
249 + name: 'TCP',
250 + type: 'protocol_queries'
251 + };
252 + }
253 + else if(x === 'QrySuccess') {
254 + named.lookups.nsstats[x] = {
255 + name: 'queries',
256 + type: 'global_queries_success'
257 + };
258 + }
259 + else if(x.match(/QryRej$/) !== null) {
260 + named.lookups.nsstats[x] = {
261 + name: x,
262 + type: 'global_failures_detail'
263 + };
264 + }
265 + else if(x.match(/^Qry/) !== null) {
266 + named.lookups.nsstats[x] = {
267 + name: x,
268 + type: 'global_queries'
269 + };
270 + }
271 + else if(x.match(/^Update/) !== null) {
272 + named.lookups.nsstats[x] = {
273 + name: x,
274 + type: 'global_updates'
275 + };
276 + }
277 + else {
278 + // values not mapped, will remain
279 + // in the default map
280 + named.lookups.nsstats[x] = {
281 + name: x,
282 + type: 'default'
283 + };
284 + }
285 +
286 + look = named.lookups.nsstats[x];
287 + // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);
288 + }
289 +
290 + switch(look.type) {
291 + case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;
292 + case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;
293 + case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;
294 + case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;
295 + case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;
296 + case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;
297 + case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;
298 + default: default_enable = true; break;
299 + }
300 + }
301 +
302 + if(global_requests_enable == true)
303 + service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 100, netdata.chartAlgorithms.incremental, 1, 1);
304 +
305 + if(global_queries_success_enable == true)
306 + service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'named', 'named', netdata.chartTypes.line, 150, netdata.chartAlgorithms.incremental, 1, 1);
307 +
308 + if(protocol_queries_enable == true)
309 + service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'named', 'named', netdata.chartTypes.stacked, 200, netdata.chartAlgorithms.incremental, 1, 1);
310 +
311 + if(global_queries_enable == true)
312 + service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'named', 'named', netdata.chartTypes.stacked, 300, netdata.chartAlgorithms.incremental, 1, 1);
313 +
314 + if(global_updates_enable == true)
315 + service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'named', 'named', netdata.chartTypes.stacked, 900, netdata.chartAlgorithms.incremental, 1, 1);
316 +
317 + if(global_failures_enable == true)
318 + service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'named', 'named', netdata.chartTypes.line, 950, netdata.chartAlgorithms.incremental, 1, 1);
319 +
320 + if(global_failures_detail_enable == true)
321 + service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'named', 'named', netdata.chartTypes.stacked, 960, netdata.chartAlgorithms.incremental, 1, 1);
322 +
323 + if(default_enable === true)
324 + service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'named', 'named', netdata.chartTypes.line, 999, netdata.chartAlgorithms.incremental, 1, 1);
325 +
326 + // RecursClients chart
327 + {
328 + var id = 'named_' + service.name + '.recursive_clients';
329 + var chart = named.charts[id];
330 +
331 + if(typeof chart === 'undefined') {
332 + chart = {
333 + id: id, // the unique id of the chart
334 + name: '', // the unique name of the chart
335 + title: service.name + ' Bind, Current Recursive Clients', // the title of the chart
336 + units: 'clients', // the units of the chart dimensions
337 + family: 'named', // the family of the chart
338 + category: 'named', // the category of the chart
339 + type: netdata.chartTypes.line, // the type of the chart
340 + priority: 150, // the priority relative to others in the same family and category
341 + update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
342 + dimensions: {
343 + 'clients': {
344 + id: 'clients', // the unique id of the dimension
345 + name: '', // the name of the dimension
346 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
347 + multiplier: 1, // the multiplier
348 + divisor: 1, // the divisor
349 + hidden: false // is hidden (boolean)
350 + }
351 + }
352 + };
353 +
354 + chart = service.chart(id, chart);
355 + named.charts[id] = chart;
356 + }
357 +
358 + service.begin(chart);
359 + service.set('clients', RecursClients);
360 + service.end();
361 + }
362 + }
363 +
364 + if(typeof r.opcodes !== 'undefined')
365 + service.module.chartFromMembers(service, r.opcodes, 'in_opcodes', 'Bind, Global Incoming Requests by OpCode', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 1000, netdata.chartAlgorithms.incremental, 1, 1);
366 +
367 + if(typeof r.qtypes !== 'undefined')
368 + service.module.chartFromMembers(service, r.qtypes, 'in_qtypes', 'Bind, Global Incoming Requests by Query Type', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 2000, netdata.chartAlgorithms.incremental, 1, 1);
369 +
370 + if(typeof r.sockstats !== 'undefined')
371 + service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'named', 'named', netdata.chartTypes.line, 2500, netdata.chartAlgorithms.incremental, 1, 1);
372 +
373 + if(typeof r.views !== 'undefined') {
374 + for( var x in r.views ) {
375 + var resolver = r.views[x].resolver;
376 +
377 + if(typeof resolver !== 'undefined') {
378 + if(typeof resolver.stats !== 'undefined') {
379 + var NumFetch = 0;
380 + var key = service.name + '.' + x;
381 + var default_enable = false;
382 + var rtt = {}, rtt_enable = false;
383 +
384 + // NumFetch is an absolute value
385 + if(typeof resolver.stats['NumFetch'] !== 'undefined') {
386 + named.lookups.numfetch[key] = true;
387 + NumFetch = resolver.stats['NumFetch'];
388 + delete resolver.stats['NumFetch'];
389 + }
390 + if(typeof resolver.stats['BucketSize'] !== 'undefined') {
391 + delete resolver.stats['BucketSize'];
392 + }
393 +
394 + // split the QryRTT* from the main chart
395 + for( var y in resolver.stats ) {
396 + // we maintain an index of the values found
397 + // mapping them to objects splitted
398 +
399 + var look = named.lookups.resolver_stats[y];
400 + if(typeof look === 'undefined') {
401 + if(y.match(/^QryRTT/) !== null) {
402 + named.lookups.resolver_stats[y] = {
403 + name: y,
404 + type: 'rtt'
405 + };
406 + }
407 + else {
408 + named.lookups.resolver_stats[y] = {
409 + name: y,
410 + type: 'default'
411 + };
412 + }
413 +
414 + look = named.lookups.resolver_stats[y];
415 + // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);
416 + }
417 +
418 + switch(look.type) {
419 + case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;
420 + default: default_enable = true; break;
421 + }
422 + }
423 +
424 + if(rtt_enable)
425 + service.module.chartFromMembers(service, rtt, 'view_resolver_rtt_' + x, 'Bind, ' + x + ' View, Resolver Round Trip Timings', 'queries/s', 'named', 'named', netdata.chartTypes.stacked, 5600, netdata.chartAlgorithms.incremental, 1, 1);
426 +
427 + if(default_enable)
428 + service.module.chartFromMembers(service, resolver.stats, 'view_resolver_stats_' + x, 'Bind, ' + x + ' View, Resolver Statistics', 'operations/s', 'named', 'named', netdata.chartTypes.line, 5500, netdata.chartAlgorithms.incremental, 1, 1);
429 +
430 + // NumFetch chart
431 + if(typeof named.lookups.numfetch[key] !== 'undefined') {
432 + var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
433 + var chart = named.charts[id];
434 +
435 + if(typeof chart === 'undefined') {
436 + chart = {
437 + id: id, // the unique id of the chart
438 + name: '', // the unique name of the chart
439 + title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries', // the title of the chart
440 + units: 'queries', // the units of the chart dimensions
441 + family: 'named', // the family of the chart
442 + category: 'named', // the category of the chart
443 + type: netdata.chartTypes.line, // the type of the chart
444 + priority: 5000, // the priority relative to others in the same family and category
445 + update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
446 + dimensions: {
447 + 'queries': {
448 + id: 'queries', // the unique id of the dimension
449 + name: '', // the name of the dimension
450 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
451 + multiplier: 1, // the multiplier
452 + divisor: 1, // the divisor
453 + hidden: false // is hidden (boolean)
454 + }
455 + }
456 + };
457 +
458 + chart = service.chart(id, chart);
459 + named.charts[id] = chart;
460 + }
461 +
462 + service.begin(chart);
463 + service.set('queries', NumFetch);
464 + service.end();
465 + }
466 + }
467 + }
468 +
469 + if(typeof resolver.qtypes !== 'undefined')
470 + service.module.chartFromMembers(service, resolver.qtypes, 'view_resolver_qtypes_' + x, 'Bind, ' + x + ' View, Requests by Query Type', 'requests/s', 'named', 'named', netdata.chartTypes.stacked, 6000, netdata.chartAlgorithms.incremental, 1, 1);
471 +
472 + //if(typeof resolver.cache !== 'undefined')
473 + // service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'named', 'named', netdata.chartTypes.stacked, 7000, netdata.chartAlgorithms.absolute, 1, 1);
474 +
475 + if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
476 + var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
477 + var chart = named.charts[id];
478 +
479 + if(typeof chart === 'undefined') {
480 + chart = {
481 + id: id, // the unique id of the chart
482 + name: '', // the unique name of the chart
483 + title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits', // the title of the chart
484 + units: 'operations/s', // the units of the chart dimensions
485 + family: 'named', // the family of the chart
486 + category: 'named', // the category of the chart
487 + type: netdata.chartTypes.area, // the type of the chart
488 + priority: 8000, // the priority relative to others in the same family and category
489 + update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart
490 + dimensions: {
491 + 'CacheHits': {
492 + id: 'CacheHits', // the unique id of the dimension
493 + name: 'hits', // the name of the dimension
494 + algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
495 + multiplier: 1, // the multiplier
496 + divisor: 1, // the divisor
497 + hidden: false // is hidden (boolean)
498 + },
499 + 'CacheMisses': {
500 + id: 'CacheMisses', // the unique id of the dimension
501 + name: 'misses', // the name of the dimension
502 + algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
503 + multiplier: -1, // the multiplier
504 + divisor: 1, // the divisor
505 + hidden: false // is hidden (boolean)
506 + }
507 + }
508 + };
509 +
510 + chart = service.chart(id, chart);
511 + named.charts[id] = chart;
512 + }
513 +
514 + service.begin(chart);
515 + service.set('CacheHits', resolver.cachestats['CacheHits']);
516 + service.set('CacheMisses', resolver.cachestats['CacheMisses']);
517 + service.end();
518 + }
519 +
520 + // this is wrong, it contains many types of info:
521 + // 1. CacheHits, CacheMisses - incremental (added above)
522 + // 2. QueryHits, QueryMisses - incremental
523 + // 3. DeleteLRU, DeleteTTL - incremental
524 + // 4. CacheNodes, CacheBuckets - absolute
525 + // 5. TreeMemTotal, TreeMemInUse - absolute
526 + // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute
527 + //if(typeof resolver.cachestats !== 'undefined')
528 + // service.module.chartFromMembers(service, resolver.cachestats, 'view_resolver_cachestats_' + x, 'Bind, ' + x + ' View, Cache Statistics', 'requests/s', 'named', 'named', netdata.chartTypes.line, 8000, netdata.chartAlgorithms.incremental, 1, 1);
529 +
530 + //if(typeof resolver.adb !== 'undefined')
531 + // service.module.chartFromMembers(service, resolver.adb, 'view_resolver_adb_' + x, 'Bind, ' + x + ' View, ADB Statistics', 'entries', 'named', 'named', netdata.chartTypes.line, 8500, netdata.chartAlgorithms.absolute, 1, 1);
532 + }
533 + }
534 + }
535 + },
536 +
537 + // module.serviceExecute()
538 + // this function is called only from this module
539 + // its purpose is to prepare the request and call
540 + // netdata.serviceExecute()
541 + serviceExecute: function(name, a_url, update_every) {
542 + if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);
543 + var service = netdata.service({
544 + name: name,
545 + request: netdata.requestFromURL(a_url),
546 + update_every: update_every,
547 + module: this
548 + });
549 +
550 + service.execute(this.processResponse);
551 + },
552 +
553 + configure: function(config) {
554 + var added = 0;
555 +
556 + if(this.enable_autodetect === true) {
557 + this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);
558 + added++;
559 + }
560 +
561 + if(typeof(config.servers) !== 'undefined') {
562 + var len = config.servers.length;
563 + while(len--) {
564 + if(typeof config.servers[len].update_every === 'undefined')
565 + config.servers[len].update_every = this.update_every;
566 + else
567 + config.servers[len].update_every = config.servers[len].update_every * 1000;
568 +
569 + this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);
570 + added++;
571 + }
572 + }
573 +
574 + return added;
575 + },
576 +
577 + // module.update()
578 + // this is called repeatidly to collect data, by calling
579 + // netdata.serviceExecute()
580 + update: function(service, callback) {
581 + service.execute(function(serv, data) {
582 + service.module.processResponse(serv, data);
583 + callback();
584 + });
585 + },
586 +};
587 +
588 +module.exports = named;
node.d/node_modules/netdata.js
+358 -364
@@ -63,6 +63,13 @@ var netdata = {
63 modules_configuring: 0,
64 charts: {},
65
66 +
67 + processors: {
68 + http: {
69 +
70 + },
71 + },
72 +
73 stringify: function(obj) {
74 return util.inspect(obj, {depth: 10});
75 },
@@ -86,276 +93,388 @@ var netdata = {
93 console.log(msg.toString());
94 },
95
89 - serviceAdd: function(service) {
90 - if(netdata.serviceIsInitialized(service) === false)
91 - netdata.serviceInit(service);
92 -
93 - if(service.added !== true) {
94 - service.updates = 0;
95 - service.enabled = true;
96 - service.added = true;
97 - service.running = false;
98 - service.started = 0;
99 - service.ended = 0;
100 - service._current_chart = null; // the current chart we work on
101 - service._queue = '';
102 - service.queue = function(txt) {
103 - this._queue += txt + '\n';
104 - };
105 -
106 - service._send_chart_to_netdata = function(chart) {
107 - // internal function to send a chart to netdata
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());
109 -
110 - for(var dim in chart.dimensions) {
111 - var d = chart.dimensions[dim];
112 -
113 - this.queue('DIMENSION "' + d.id + '" "' + d.name + '" "' + d.algorithm + '" ' + d.multiplier.toString() + ' ' + d.divisor.toString() + ' ' + ((d.hidden === true)?'hidden':'').toString());
114 - d._created = true;
115 - d._updated = false;
116 - }
96 + service: function(service) {
97 + if(typeof service === 'undefined')
98 + service = {};
99
118 - chart._created = true;
119 - chart._updated = false;
120 - };
100 + service._current_chart = null; // the current chart we work on
101 + service._queue = ''; // data to be sent to netdata
102
122 - // begin data collection for a chart
123 - service.begin = function(chart) {
124 - if(this._current_chart !== null && this._current_chart !== chart) {
125 - netdata.serviceError(this, 'Called begin() for chart ' + chart.id + ' while chart ' + this._current_chart.id + ' is still open. Closing it.');
126 - this.end();
127 - }
103 + service.error_reported = false; // error log flood control
104
129 - if(typeof(chart.id) === 'undefined' || netdata.charts[chart.id] != chart) {
130 - netdata.serviceError(this, 'Called begin() for chart ' + chart.id + ' that is not mine. Where did you find it? Ignoring it.');
131 - return false;
132 - }
105 + service.added = false; // added to netdata.services
106 + service.enabled = true;
107 + service.updates = 0;
108 + service.running = false;
109 + service.started = 0;
110 + service.ended = 0;
111
134 - if(netdata.options.DEBUG === true) netdata.debug('setting current chart to ' + chart.id);
135 - this._current_chart = chart;
136 - this._current_chart._began = true;
112 + if(typeof service.update_every === 'undefined')
113 + service.update_every = service.module.update_every;
114
138 - if(this._current_chart._dimensions_count !== 0) {
139 - if(this._current_chart._created === false || this._current_chart._updated === true)
140 - this._send_chart_to_netdata(this._current_chart);
115 + if(typeof service.update_every === 'undefined')
116 + service.update_every = netdata.options.update_every;
117
142 - var now = this.ended;
143 - this.queue('BEGIN ' + this._current_chart.id + ' ' + ((this._current_chart._last_updated > 0)?((now - this._current_chart._last_updated) * 1000):'').toString());
144 - }
145 - // else netdata.serviceError(this, 'Called begin() for chart ' + chart.id + ' which is empty.');
118 + if(typeof service.processor === 'undefined')
119 + service.processor = netdata.processors.http;
120
147 - this._current_chart._last_updated = now;
148 - this._current_chart._began = true;
149 - this._current_chart._counter++;
121 + service.commit = function() {
122 + if(this.added !== true) {
123 + this.added = true;
124 + netdata.services.push(this);
125 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': service committed.');
126 + }
127 + };
128
151 - return true;
152 - };
129 + service._processResponse = function(response, callback) {
130 + this.running = false;
131 + this.ended = new Date().getTime();
132
154 - // set a collected value for a chart
155 - // we do most things on the first value we attempt to set
156 - service.set = function(dimension, value) {
157 - if(this._current_chart === null) {
158 - netdata.serviceError(this, 'Called set(' + dimension + ', ' + value + ') without an open chart.');
159 - return false;
160 - }
133 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': processing response (received it in ' + (this.ended - this.started).toString() + ' ms)');
134
162 - if(typeof(this._current_chart.dimensions[dimension]) === 'undefined') {
163 - netdata.serviceError(this, 'Called set(' + dimension + ', ' + value + ') but dimension "' + dimension + '" does not exist in chart "' + this._current_chart.id + '".');
164 - return false;
135 + callback(this, response);
136 +
137 + this.module.active--;
138 + if(this.module.active < 0) {
139 + this.module.active = 0;
140 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': active module counter below zero.');
141 + }
142 +
143 + if(this.module.active === 0) {
144 + // check if we run under configure
145 + if(this.module.configure_callback !== null) {
146 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': configuration finish callback called from processResponse().');
147 + var ccallback = this.module.configure_callback;
148 + this.module.configure_callback = null;
149 + ccallback();
150 }
151 + }
152 + };
153
167 - if(typeof value === 'undefined' || value === null)
168 - return false;
154 + service.execute = function(callback) {
155 + this.module.active++;
156 + this.running = true;
157 + this.started = new Date().getTime();
158 + this.updates++;
159
170 - if(this._current_chart._dimensions_count !== 0)
171 - this.queue('SET ' + dimension + ' = ' + value);
160 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': making request: ' + netdata.stringify(this.request));
161
173 - return true;
174 - };
162 + var req = http.request(this.request, function(response) {
163 + if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': got server response...');
164
176 - // end data collection for the current chart - after calling begin()
177 - service.end = function() {
178 - if(this._current_chart !== null && this._current_chart._began === false) {
179 - netdata.serviceError(this, 'Called end() without an open chart.');
180 - return false;
181 - }
165 + var end = false;
166 + var data = '';
167 + response.setEncoding('utf8');
168
183 - if(this._current_chart._dimensions_count !== 0) {
184 - this.queue('END');
185 - netdata.send(this._queue);
169 + if(response.statusCode !== 200) {
170 + if(end === false) {
171 + service.error('Got HTTP code ' + response.statusCode + ', failed to get data.');
172 + end = true;
173 + service._processResponse(null, callback);
174 + }
175 }
176
188 - this._queue = '';
189 - this._current_chart._began = false;
190 - if(netdata.options.DEBUG === true) netdata.debug('committed chart ' + this._current_chart.id);
191 - this._current_chart = null;
192 - return true;
193 - };
194 -
195 - // discard the collected values for the current chart - after calling begin()
196 - service.flush = function() {
197 - if(this._current_chart === null || this._current_chart._began === false) {
198 - netdata.serviceError(this, 'Called flush() without an open chart.');
199 - return false;
200 - }
177 + response.on('data', function(chunk) {
178 + if(end === false) data += chunk;
179 + });
180
202 - this._queue = '';
203 - this._current_chart._began = false;
204 - this._current_chart = null;
205 - return true;
206 - };
207 -
208 - // create a netdata chart
209 - service.chart = function(id, chart) {
210 - if(typeof(netdata.charts[id]) === 'undefined') {
211 - netdata.charts[id] = {
212 - _created: false,
213 - _updated: false,
214 - _began: false,
215 - _counter: 0,
216 - _last_updated: 0,
217 - _dimensions_count: 0,
218 - id: id,
219 - name: id,
220 - title: 'untitled chart',
221 - units: 'a unit',
222 - family: id,
223 - category: id,
224 - type: netdata.chartTypes.line,
225 - priority: 0,
226 - update_every: netdata.options.update_every,
227 - dimensions: {}
228 - };
229 - }
181 + response.on('error', function() {
182 + if(end === false) {
183 + service.error(': Read error, failed to get data.');
184 + end = true;
185 + service._processResponse(null, callback);
186 + }
187 + });
188 +
189 + response.on('end', function() {
190 + if(end === false) {
191 + service.errorClear();
192 + if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': read completed.');
193 + end = true;
194 + service._processResponse(data, callback);
195 + }
196 + });
197 + });
198 +
199 + req.on('error', function(e) {
200 + service.error('Failed to make request: ' + netdata.stringify(service.request) + ', message: ' + e.message);
201 + service._processResponse(null, callback);
202 + });
203 +
204 + // write data to request body
205 + if(typeof this.postData !== 'undefined' && this.request.method === 'POST') {
206 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': posting data: ' + this.postData);
207 + req.write(this.postData);
208 + }
209
231 - var c = netdata.charts[id];
210 + req.end();
211 + };
212
233 - if(typeof(chart.name) !== 'undefined' && chart.name !== c.name) {
234 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its name');
235 - c.name = chart.name;
236 - c._updated = true;
237 - }
213 + service.update = function() {
214 + if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': starting data collection...');
215
239 - if(typeof(chart.title) !== 'undefined' && chart.title !== c.title) {
240 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its title');
241 - c.title = chart.title;
242 - c._updated = true;
243 - }
216 + this.module.update(this, function() {
217 + service.ended = new Date().getTime();
218 + service.duration = service.ended - service.started;
219 + if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': data collection ended in ' + service.duration.toString() + ' ms.');
220 + service.running = false;
221 + });
222 + };
223
245 - if(typeof(chart.units) !== 'undefined' && chart.units !== c.units) {
246 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its units');
247 - c.units = chart.units;
248 - c._updated = true;
249 - }
224 + service.error = function(message) {
225 + if(this.error_reported === false) {
226 + netdata.error(this.module.name + ': ' + this.name + ': ' + message);
227 + this.error_reported = true;
228 + }
229 + else if(netdata.options.DEBUG === true)
230 + netdata.debug(this.module.name + ': ' + this.name + ': ' + message);
231 + };
232
251 - if(typeof(chart.family) !== 'undefined' && chart.family !== c.family) {
252 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its family');
253 - c.family = chart.family;
254 - c._updated = true;
255 - }
233 + service.errorClear = function() {
234 + this.error_reported = false;
235 + };
236
257 - if(typeof(chart.category) !== 'undefined' && chart.category !== c.category) {
258 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its category');
259 - c.category = chart.category;
260 - c._updated = true;
261 - }
237 + service.queue = function(txt) {
238 + this._queue += txt + '\n';
239 + };
240
263 - if(typeof(chart.type) !== 'undefined' && chart.type !== c.type) {
264 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its type');
265 - c.type = chart.type;
266 - c._updated = true;
267 - }
241 + service._send_chart_to_netdata = function(chart) {
242 + // internal function to send a chart to netdata
243 + this.queue('CHART "' + chart.id + '" "' + chart.name + '" "' + chart.title + '" "' + chart.units + '" "' + chart.family + '" "' + chart.category + '" "' + chart.type + '" ' + chart.priority.toString() + ' ' + chart.update_every.toString());
244 +
245 + for(var dim in chart.dimensions) {
246 + var d = chart.dimensions[dim];
247
269 - if(typeof(chart.priority) !== 'undefined' && chart.priority !== c.priority) {
270 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its priority');
271 - c.priority = chart.priority;
272 - c._updated = true;
273 - }
248 + this.queue('DIMENSION "' + d.id + '" "' + d.name + '" "' + d.algorithm + '" ' + d.multiplier.toString() + ' ' + d.divisor.toString() + ' ' + ((d.hidden === true)?'hidden':'').toString());
249 + d._created = true;
250 + d._updated = false;
251 + }
252
275 - if(typeof(chart.update_every) !== 'undefined' && chart.update_every !== c.update_every) {
276 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its update_every');
277 - c.update_every = chart.update_every;
278 - c._updated = true;
279 - }
253 + chart._created = true;
254 + chart._updated = false;
255 + };
256 +
257 + // begin data collection for a chart
258 + service.begin = function(chart) {
259 + if(this._current_chart !== null && this._current_chart !== chart) {
260 + this.error('Called begin() for chart ' + chart.id + ' while chart ' + this._current_chart.id + ' is still open. Closing it.');
261 + this.end();
262 + }
263 +
264 + if(typeof(chart.id) === 'undefined' || netdata.charts[chart.id] != chart) {
265 + this.error('Called begin() for chart ' + chart.id + ' that is not mine. Where did you find it? Ignoring it.');
266 + return false;
267 + }
268 +
269 + if(netdata.options.DEBUG === true) netdata.debug('setting current chart to ' + chart.id);
270 + this._current_chart = chart;
271 + this._current_chart._began = true;
272 +
273 + if(this._current_chart._dimensions_count !== 0) {
274 + if(this._current_chart._created === false || this._current_chart._updated === true)
275 + this._send_chart_to_netdata(this._current_chart);
276 +
277 + var now = this.ended;
278 + this.queue('BEGIN ' + this._current_chart.id + ' ' + ((this._current_chart._last_updated > 0)?((now - this._current_chart._last_updated) * 1000):'').toString());
279 + }
280 + // else this.error('Called begin() for chart ' + chart.id + ' which is empty.');
281 +
282 + this._current_chart._last_updated = now;
283 + this._current_chart._began = true;
284 + this._current_chart._counter++;
285 +
286 + return true;
287 + };
288 +
289 + // set a collected value for a chart
290 + // we do most things on the first value we attempt to set
291 + service.set = function(dimension, value) {
292 + if(this._current_chart === null) {
293 + this.error('Called set(' + dimension + ', ' + value + ') without an open chart.');
294 + return false;
295 + }
296 +
297 + if(typeof(this._current_chart.dimensions[dimension]) === 'undefined') {
298 + this.error('Called set(' + dimension + ', ' + value + ') but dimension "' + dimension + '" does not exist in chart "' + this._current_chart.id + '".');
299 + return false;
300 + }
301 +
302 + if(typeof value === 'undefined' || value === null)
303 + return false;
304 +
305 + if(this._current_chart._dimensions_count !== 0)
306 + this.queue('SET ' + dimension + ' = ' + value);
307 +
308 + return true;
309 + };
310 +
311 + // end data collection for the current chart - after calling begin()
312 + service.end = function() {
313 + if(this._current_chart !== null && this._current_chart._began === false) {
314 + this.error('Called end() without an open chart.');
315 + return false;
316 + }
317 +
318 + if(this._current_chart._dimensions_count !== 0) {
319 + this.queue('END');
320 + netdata.send(this._queue);
321 + }
322 +
323 + this._queue = '';
324 + this._current_chart._began = false;
325 + if(netdata.options.DEBUG === true) netdata.debug('sent chart ' + this._current_chart.id);
326 + this._current_chart = null;
327 + return true;
328 + };
329 +
330 + // discard the collected values for the current chart - after calling begin()
331 + service.flush = function() {
332 + if(this._current_chart === null || this._current_chart._began === false) {
333 + this.error('Called flush() without an open chart.');
334 + return false;
335 + }
336 +
337 + this._queue = '';
338 + this._current_chart._began = false;
339 + this._current_chart = null;
340 + return true;
341 + };
342 +
343 + // create a netdata chart
344 + service.chart = function(id, chart) {
345 + if(typeof(netdata.charts[id]) === 'undefined') {
346 + netdata.charts[id] = {
347 + _created: false,
348 + _updated: false,
349 + _began: false,
350 + _counter: 0,
351 + _last_updated: 0,
352 + _dimensions_count: 0,
353 + id: id,
354 + name: id,
355 + title: 'untitled chart',
356 + units: 'a unit',
357 + family: id,
358 + category: id,
359 + type: netdata.chartTypes.line,
360 + priority: 0,
361 + update_every: netdata.options.update_every,
362 + dimensions: {}
363 + };
364 + }
365 +
366 + var c = netdata.charts[id];
367
281 - if(typeof(chart.dimensions) !== 'undefined') {
282 - for(var x in chart.dimensions) {
283 - if(typeof(c.dimensions[x]) === 'undefined') {
284 - c._dimensions_count++;
285 -
286 - c.dimensions[x] = {
287 - _created: false,
288 - _updated: false,
289 - id: x, // the unique id of the dimension
290 - name: x, // the name of the dimension
291 - algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm
292 - multiplier: 1, // the multiplier
293 - divisor: 1, // the divisor
294 - hidden: false, // is hidden (boolean)
295 - };
296 -
297 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' created dimension ' + x);
298 - c._updated = true;
299 - }
300 -
301 - var dim = chart.dimensions[x];
302 - var d = c.dimensions[x];
303 -
304 - if(typeof(dim.name) !== 'undefined' && d.name !== dim.name) {
305 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its name');
306 - d.name = dim.name;
307 - d._updated = true;
308 - }
309 -
310 - if(typeof(dim.algorithm) !== 'undefined' && d.algorithm !== dim.algorithm) {
311 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its algorithm from ' + d.algorithm + ' to ' + dim.algorithm);
312 - d.algorithm = dim.algorithm;
313 - d._updated = true;
314 - }
315 -
316 - if(typeof(dim.multiplier) !== 'undefined' && d.multiplier !== dim.multiplier) {
317 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its multiplier');
318 - d.multiplier = dim.multiplier;
319 - d._updated = true;
320 - }
321 -
322 - if(typeof(dim.divisor) !== 'undefined' && d.divisor !== dim.divisor) {
323 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its divisor');
324 - d.divisor = dim.divisor;
325 - d._updated = true;
326 - }
327 -
328 - if(typeof(dim.hidden) !== 'undefined' && d.hidden !== dim.hidden) {
329 - if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its hidden status');
330 - d.hidden = dim.hidden;
331 - d._updated = true;
332 - }
333 -
334 - if(d._updated) c._updated = true;
368 + if(typeof(chart.name) !== 'undefined' && chart.name !== c.name) {
369 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its name');
370 + c.name = chart.name;
371 + c._updated = true;
372 + }
373 +
374 + if(typeof(chart.title) !== 'undefined' && chart.title !== c.title) {
375 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its title');
376 + c.title = chart.title;
377 + c._updated = true;
378 + }
379 +
380 + if(typeof(chart.units) !== 'undefined' && chart.units !== c.units) {
381 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its units');
382 + c.units = chart.units;
383 + c._updated = true;
384 + }
385 +
386 + if(typeof(chart.family) !== 'undefined' && chart.family !== c.family) {
387 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its family');
388 + c.family = chart.family;
389 + c._updated = true;
390 + }
391 +
392 + if(typeof(chart.category) !== 'undefined' && chart.category !== c.category) {
393 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its category');
394 + c.category = chart.category;
395 + c._updated = true;
396 + }
397 +
398 + if(typeof(chart.type) !== 'undefined' && chart.type !== c.type) {
399 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its type');
400 + c.type = chart.type;
401 + c._updated = true;
402 + }
403 +
404 + if(typeof(chart.priority) !== 'undefined' && chart.priority !== c.priority) {
405 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its priority');
406 + c.priority = chart.priority;
407 + c._updated = true;
408 + }
409 +
410 + if(typeof(chart.update_every) !== 'undefined' && chart.update_every !== c.update_every) {
411 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its update_every');
412 + c.update_every = chart.update_every;
413 + c._updated = true;
414 + }
415 +
416 + if(typeof(chart.dimensions) !== 'undefined') {
417 + for(var x in chart.dimensions) {
418 + if(typeof(c.dimensions[x]) === 'undefined') {
419 + c._dimensions_count++;
420 +
421 + c.dimensions[x] = {
422 + _created: false,
423 + _updated: false,
424 + id: x, // the unique id of the dimension
425 + name: x, // the name of the dimension
426 + algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm
427 + multiplier: 1, // the multiplier
428 + divisor: 1, // the divisor
429 + hidden: false, // is hidden (boolean)
430 + };
431 +
432 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' created dimension ' + x);
433 + c._updated = true;
434 }
336 - }
435
338 - if(netdata.options.DEBUG === true) netdata.debug(netdata.charts);
339 - return netdata.charts[id];
340 - };
436 + var dim = chart.dimensions[x];
437 + var d = c.dimensions[x];
438
342 - this.services.push(service);
343 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': service added.');
344 - }
345 - },
439 + if(typeof(dim.name) !== 'undefined' && d.name !== dim.name) {
440 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its name');
441 + d.name = dim.name;
442 + d._updated = true;
443 + }
444 +
445 + if(typeof(dim.algorithm) !== 'undefined' && d.algorithm !== dim.algorithm) {
446 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its algorithm from ' + d.algorithm + ' to ' + dim.algorithm);
447 + d.algorithm = dim.algorithm;
448 + d._updated = true;
449 + }
450 +
451 + if(typeof(dim.multiplier) !== 'undefined' && d.multiplier !== dim.multiplier) {
452 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its multiplier');
453 + d.multiplier = dim.multiplier;
454 + d._updated = true;
455 + }
456 +
457 + if(typeof(dim.divisor) !== 'undefined' && d.divisor !== dim.divisor) {
458 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its divisor');
459 + d.divisor = dim.divisor;
460 + d._updated = true;
461 + }
462 +
463 + if(typeof(dim.hidden) !== 'undefined' && d.hidden !== dim.hidden) {
464 + if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its hidden status');
465 + d.hidden = dim.hidden;
466 + d._updated = true;
467 + }
468
347 - serviceRun: function(service) {
348 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': starting data collection...');
349 - service.running = true;
350 - service.started = new Date().getTime();
351 - service.updates++;
352 -
353 - service.module.update(service, function() {
354 - service.ended = new Date().getTime();
355 - service.duration = service.ended - service.started;
356 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': data collection ended in ' + service.duration.toString() + ' ms.');
357 - service.running = false;
358 - });
469 + if(d._updated) c._updated = true;
470 + }
471 + }
472 +
473 + //if(netdata.options.DEBUG === true) netdata.debug(netdata.charts);
474 + return netdata.charts[id];
475 + };
476 +
477 + return service;
478 },
479
480 runAllServices: function() {
@@ -369,7 +488,7 @@ var netdata = {
488 if(service.enabled === false || service.running === true) continue;
489 if(now - service.ended < service.update_every) continue;
490
372 - netdata.serviceRun(service);
491 + service.update();
492 }
493
494 setTimeout(netdata.runAllServices, 100);
@@ -417,118 +536,10 @@ var netdata = {
536 return netdata.requestFromParams(u.protocol, u.hostname, u.port, u.path, 'GET');
537 },
538
420 - processResponse: function(service, data, callback) {
421 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': processing response...');
422 -
423 - callback(service, data);
424 -
425 - service.module.running--;
426 - if(service.module.running <= 0) {
427 - service.module.running = 0;
428 -
429 - // check if we run under configure
430 - if(service.module.configure_callback !== null) {
431 - if(netdata.options.DEBUG === true) this.debug(service.module.name + ': configuration finish callback called from processResponse().');
432 - var ccallback = service.module.configure_callback;
433 - service.module.configure_callback = null;
434 - ccallback();
435 - }
436 - }
437 - },
438 -
439 - serviceError: function(service, message) {
440 - if(service.error_reported === false) {
441 - netdata.error(service.module.name + ': ' + service.name + ': ' + message);
442 - service.error_reported = true;
443 - }
444 - else if(netdata.options.DEBUG === true)
445 - netdata.debug(service.module.name + ': ' + service.name + ': ' + message);
446 - },
447 -
448 - serviceErrorClear: function(service) {
449 - service.error_reported = false;
450 - },
451 -
452 - serviceInit: function(service) {
453 - service.error_reported = false;
454 - service.added = false;
455 - service.enabled = true;
456 - },
457 -
458 - serviceIsInitialized: function(service) {
459 - if(typeof service.error_reported === 'undefined')
460 - return false;
461 -
462 - return true;
463 - },
464 -
465 - getResponse: function(service, response, callback) {
466 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': got response...');
467 -
468 - var end = false;
469 - var data = '';
470 - response.setEncoding('utf8');
471 -
472 - if(response.statusCode !== 200) {
473 - if(end === false) {
474 - netdata.serviceError(service, ': got HTTP code ' + response.statusCode + ', failed to get data.');
475 - end = true;
476 - netdata.processResponse(service, null, callback);
477 - }
478 - }
479 -
480 - response.on('data', function(chunk) {
481 - if(end === false) data += chunk;
482 - });
483 -
484 - response.on('error', function() {
485 - if(end === false) {
486 - netdata.serviceError(service, ': Read error, failed to get data.');
487 - end = true;
488 - netdata.processResponse(service, null, callback);
489 - }
490 - });
491 -
492 - response.on('end', function() {
493 - if(end === false) {
494 - netdata.serviceErrorClear(service);
495 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': read completed.');
496 - end = true;
497 - netdata.processResponse(service, data, callback);
498 - }
499 - });
500 - },
501 -
502 - serviceExecute: function(service, callback) {
503 - if(netdata.serviceIsInitialized(service) === false)
504 - netdata.serviceInit(service);
505 -
506 - service.module.running++;
507 -
508 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': making request: ' + netdata.stringify(service.request));
509 - var req = http.request(service.request, function(response) {
510 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': request done.');
511 - netdata.getResponse(service, response, callback);
512 - });
513 -
514 - req.on('error', function(e) {
515 - netdata.serviceError(service, ': failed to make request: ' + netdata.stringify(service.request) + ', message: ' + e.message);
516 - netdata.processResponse(service, null, callback);
517 - });
518 -
519 - // write data to request body
520 - if(typeof service.postData !== 'undefined' && service.request.method === 'POST') {
521 - if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': posting data: ' + service.postData);
522 - req.write(service.postData);
523 - }
524 -
525 - req.end();
526 - },
527 -
539 configure: function(module, config, callback) {
540 if(netdata.options.DEBUG === true) this.debug(module.name + ': configuring (update_every: ' + this.options.update_every + ')...');
541
531 - module.running = 0;
542 + module.active = 0;
543 module.update_every = this.options.update_every;
544
545 if(typeof config.update_every !== 'undefined')
@@ -553,24 +564,7 @@ var netdata = {
564
565 return added;
566 }
556 -
567 };
568
569 if(netdata.options.DEBUG === true) netdata.debug('loaded netdata from: ' + __filename);
570 module.exports = netdata;
561 -
562 -/*
563 -var test1 = netdata.chart('test1', { name: 'test name', dimensions: { dim1: {}}});
564 -netdata.begin(test1);
565 -netdata.set('dim1', 1);
566 -netdata.end();
567 -netdata.begin(test1);
568 -netdata.set('dim1', 2);
569 -netdata.end();
570 -netdata.begin(test1);
571 -netdata.set('dim1', 3);
572 -netdata.end();
573 -netdata.begin(test1);
574 -netdata.set('dim1', 4);
575 -netdata.end();
576 -*/
node.d/sma_webbox.node.js
+5 -5
@@ -70,7 +70,7 @@ var webbox = {
70
71 // add the service
72 if(found > 0 && service.added !== true)
73 - netdata.serviceAdd(service);
73 + service.commit();
74
75 // Grid Current Power Chart
76 if(d['GriPwr'].value !== null) {
@@ -190,17 +190,17 @@ var webbox = {
190 serviceExecute: function(name, hostname, update_every) {
191 if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': hostname: ' + hostname + ', update_every: ' + update_every);
192
193 - var service = {
193 + var service = netdata.service({
194 name: name,
195 request: netdata.requestFromURL('http://' + hostname + '/rpc'),
196 update_every: update_every,
197 module: this
198 - };
198 + });
199 service.postData = 'RPC={"proc":"GetPlantOverview","format":"JSON","version":"1.0","id":"1"}';
200 service.request.method = 'POST';
201 service.request.headers['Content-Length'] = service.postData.length;
202
203 - netdata.serviceExecute(service, this.processResponse);
203 + service.execute(this.processResponse);
204 },
205
206 configure: function(config) {
@@ -229,7 +229,7 @@ var webbox = {
229 // this is called repeatidly to collect data, by calling
230 // netdata.serviceExecute()
231 update: function(service, callback) {
232 - netdata.serviceExecute(service, function(serv, data) {
232 + service.execute(function(serv, data) {
233 service.module.processResponse(serv, data);
234 callback();
235 });
plugins.d/node.d.plugin
+52 -32
@@ -97,43 +97,63 @@ function dumpError(err) {
97
98 // --------------------------------------------------------------------------------------------------------------------
99 // get command line arguments
100 +{
101 + var found_myself = false;
102 + var found_number = false;
103 + var found_modules = false;
104 + process.argv.forEach(function (val, index, array) {
105 + netdata.debug('PARAM: ' + val);
106 +
107 + if(!found_myself) {
108 + if(val === __filename)
109 + found_myself = true;
110 + }
111 + else {
112 + switch(val) {
113 + case 'debug':
114 + netdata.options.DEBUG = true;
115 + netdata.debug('DEBUG enabled');
116 + break;
117 +
118 + default:
119 + if(found_number === true) {
120 + if(found_modules === false) {
121 + for(var i in netdata.options.modules)
122 + netdata.options.modules[i].enabled = false;
123 + }
124
101 -var found_myself = false;
102 -process.argv.forEach(function (val, index, array) {
103 - netdata.debug('PARAM: ' + val);
125 + if(typeof netdata.options.modules[val] === 'undefined')
126 + netdata.options.modules[val] = {};
127
105 - if(!found_myself) {
106 - if(val === __filename)
107 - found_myself = true;
108 - }
109 - else {
110 - switch(val) {
111 - case 'debug':
112 - netdata.options.DEBUG = true;
113 - netdata.debug('DEBUG enabled');
114 - break;
115 -
116 - default:
117 - try {
118 - var x = parseInt(val);
119 - if(x > 0) {
120 - netdata.options.update_every = x * 1000;
121 - if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
122 - netdata.options.update_every = NETDATA_UPDATE_EVERY;
123 - netdata.debug('Update frequency ' + x + 's is too low');
128 + netdata.options.modules[val].enabled = true;
129 + netdata.options.modules_enable_all = false;
130 + netdata.debug('enabled module ' + val);
131 + }
132 + else {
133 + try {
134 + var x = parseInt(val);
135 + if(x > 0) {
136 + netdata.options.update_every = x * 1000;
137 + if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
138 + netdata.options.update_every = NETDATA_UPDATE_EVERY;
139 + netdata.debug('Update frequency ' + x + 's is too low');
140 + }
141 +
142 + found_number = true;
143 + netdata.debug('Update frequency set to ' + netdata.options.update_every + ' ms');
144 + }
145 + else netdata.error('Ignoring parameter: ' + val);
146 + }
147 + catch(e) {
148 + netdata.error('Cannot get value of parameter: ' + val);
149 + dumpError(e);
150 }
125 -
126 - netdata.debug('Update frequency set to ' + netdata.options.update_every + ' ms');
151 }
128 - else netdata.error('Ignoring parameter: ' + val);
129 - }
130 - catch(e) {
131 - netdata.error('Cannot get value of parameter: ' + val);
132 - dumpError(e);
133 - }
152 + break;
153 + }
154 }
135 - }
136 -});
155 + });
156 +}
157
158 if(netdata.options.update_every < 1000) {
159 netdata.debug('Adjusting update frequency to 1 second');