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');