]> arthur.barton.de Git - netdata.git/blob - node.d/named.node.js
bind collector can now also accept XML input
[netdata.git] / node.d / named.node.js
1 'use strict';\r
2 \r
3 // collect statistics from bind (named) v9.10+\r
4 //\r
5 // bind statistics documentation at:\r
6 // http://jpmens.net/2013/03/18/json-in-bind-9-s-statistics-server/\r
7 // https://ftp.isc.org/isc/bind/9.10.3/doc/arm/Bv9ARM.ch06.html#statistics\r
8 \r
9 // example configuration in /etc/netdata/named.conf\r
10 // the module supports auto-detection if bind is running in localhost\r
11 \r
12 /*\r
13 {\r
14         "enable_autodetect": true,\r
15         "update_every": 5,\r
16         "servers": [\r
17                 {\r
18                         "name": "bind1",\r
19                         "url": "http://127.0.0.1:8888/json/v1/server",\r
20                         "update_every": 1\r
21                 },\r
22                 {\r
23                         "name": "bind2",\r
24                         "url": "http://10.0.0.1:8888/xml/v3/server",\r
25                         "update_every": 2\r
26                 }\r
27         ]\r
28 }\r
29 */\r
30 \r
31 // the following is the bind named.conf configuration required\r
32 \r
33 /*\r
34 statistics-channels {\r
35         inet 127.0.0.1 port 8888 allow { 127.0.0.1; };\r
36 };\r
37 */\r
38 \r
39 var url = require('url');\r
40 var http = require('http');\r
41 var XML = require('pixl-xml');\r
42 var netdata = require('netdata');\r
43 \r
44 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');\r
45 \r
46 var named = {\r
47         name: __filename,\r
48         enable_autodetect: true,\r
49         update_every: 1000,\r
50 \r
51         charts: {},\r
52 \r
53         chartFromMembersCreate: function(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor) {\r
54                 var chart = {\r
55                         id: id,                                                                                 // the unique id of the chart\r
56                         name: '',                                                                               // the unique name of the chart\r
57                         title: service.name + ' ' + title_suffix,               // the title of the chart\r
58                         units: units,                                                                   // the units of the chart dimensions\r
59                         family: family_prefix + '_' + service.name,             // the family of the chart\r
60                         category: category_prefix + '_' + service.name, // the category of the chart\r
61                         type: type,                                                                             // the type of the chart\r
62                         priority: priority,                                                             // the priority relative to others in the same family and category\r
63                         update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart\r
64                         dimensions: {}\r
65                 }\r
66 \r
67                 var found = 0;\r
68                 for(var x in obj) {\r
69                         if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {\r
70                                 found++;\r
71                                 chart.dimensions[x] = {\r
72                                         id: x,                                  // the unique id of the dimension\r
73                                         name: x,                                // the name of the dimension\r
74                                         algorithm: algorithm,   // the id of the netdata algorithm\r
75                                         multiplier: multiplier, // the multiplier\r
76                                         divisor: divisor,               // the divisor\r
77                                         hidden: false                   // is hidden (boolean)\r
78                                 }\r
79                         }\r
80                 }\r
81 \r
82                 if(found === false)\r
83                         return null;\r
84 \r
85                 chart = service.chart(id, chart);\r
86                 this.charts[id] = chart;\r
87                 return chart;\r
88         },\r
89 \r
90         chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor) {\r
91                 var id = 'named_' + service.name + '.' + id_suffix;\r
92                 var chart = this.charts[id];\r
93 \r
94                 if(typeof chart === 'undefined') {\r
95                         chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor);\r
96                         if(chart === null) return false;\r
97                 }\r
98                 else {\r
99                         // check if we need to re-generate the chart\r
100                         for(var x in obj) {\r
101                                 if(typeof(chart.dimensions[x]) === 'undefined') {\r
102                                         chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family_prefix, category_prefix, type, priority, algorithm, multiplier, divisor);\r
103                                         if(chart === null) return false;\r
104                                         break;\r
105                                 }\r
106                         }\r
107                 }\r
108 \r
109                 var found = 0;\r
110                 service.begin(chart);\r
111                 for(var x in obj) {\r
112                         if(typeof(chart.dimensions[x]) !== 'undefined') {\r
113                                 found++;\r
114                                 service.set(x, obj[x]);\r
115                         }\r
116                 }\r
117                 service.end();\r
118 \r
119                 if(found > 0) return true;\r
120                 return false;\r
121         },\r
122 \r
123         // an index to map values to different charts\r
124         lookups: {\r
125                 nsstats: {},\r
126                 resolver_stats: {},\r
127                 numfetch: {}\r
128         },\r
129 \r
130         // transform the XML response of bind\r
131         // to the JSON response of bind\r
132         xml2js: function(service, data_xml) {\r
133                 var d = XML.parse(data_xml);\r
134                 if(d === null) return null;\r
135 \r
136                 var data = {};\r
137                 var len = d.server.counters.length;\r
138                 while(len--) {\r
139                         var a = d.server.counters[len];\r
140                         if(typeof a.counter === 'undefined') continue;\r
141                         if(a.type === 'opcode') a.type = 'opcodes';\r
142                         else if(a.type === 'qtype') a.type = 'qtypes';\r
143                         else if(a.type === 'nsstat') a.type = 'nsstats';\r
144                         var aa = data[a.type] = {};\r
145                         var alen = 0\r
146                         var alen2 = a.counter.length;\r
147                         while(alen < alen2) {\r
148                                 aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);\r
149                                 alen++;\r
150                         }\r
151                 }\r
152 \r
153                 data.views = {};\r
154                 var vlen = d.views.view.length;\r
155                 while(vlen--) {\r
156                         var vname = d.views.view[vlen].name;\r
157                         data.views[vname] = { resolver: {} };\r
158                         var len = d.views.view[vlen].counters.length;\r
159                         while(len--) {\r
160                                 var a = d.views.view[vlen].counters[len];\r
161                                 if(typeof a.counter === 'undefined') continue;\r
162                                 if(a.type === 'resstats') a.type = 'stats';\r
163                                 else if(a.type === 'resqtype') a.type = 'qtypes';\r
164                                 else if(a.type === 'adbstat') a.type = 'adb';\r
165                                 var aa = data.views[vname].resolver[a.type] = {};\r
166                                 var alen = 0;\r
167                                 var alen2 = a.counter.length;\r
168                                 while(alen < alen2) {\r
169                                         aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);\r
170                                         alen++;\r
171                                 }\r
172                         }\r
173                 }\r
174 \r
175                 return data;\r
176         },\r
177 \r
178         processResponse: function(service, data) {\r
179                 if(data !== null) {\r
180                         var r;\r
181 \r
182                         // parse XML or JSON\r
183                         // pepending on the URL given\r
184                         if(service.request.path.match(/^\/xml/) !== null)\r
185                                 r = named.xml2js(service, data);\r
186                         else\r
187                                 r = JSON.parse(data);\r
188 \r
189                         if(typeof r === 'undefined' || r === null) {\r
190                                 netdata.serviceError(service, "Cannot parse these data: " + data);\r
191                                 return;\r
192                         }\r
193 \r
194                         if(service.added !== true)\r
195                                 netdata.serviceAdd(service);\r
196 \r
197                         if(typeof r.nsstats !== 'undefined') {\r
198                                 // we split the nsstats object to several others\r
199                                 var global_requests = {}, global_requests_enable = false;\r
200                                 var global_failures = {}, global_failures_enable = false;\r
201                                 var global_failures_detail = {}, global_failures_detail_enable = false;\r
202                                 var global_updates = {}, global_updates_enable = false;\r
203                                 var protocol_queries = {}, protocol_queries_enable = false;\r
204                                 var global_queries = {}, global_queries_enable = false;\r
205                                 var global_queries_success = {}, global_queries_success_enable = false;\r
206                                 var default_enable = false;\r
207                                 var RecursClients = 0;\r
208 \r
209                                 // RecursClients is an absolute value\r
210                                 if(typeof r.nsstats['RecursClients'] !== 'undefined') {\r
211                                         RecursClients = r.nsstats['RecursClients'];\r
212                                         delete r.nsstats['RecursClients'];\r
213                                 }\r
214 \r
215                                 for( var x in r.nsstats ) {\r
216                                         // we maintain an index of the values found\r
217                                         // mapping them to objects splitted\r
218 \r
219                                         var look = named.lookups.nsstats[x];\r
220                                         if(typeof look === 'undefined') {\r
221                                                 // a new value, not found in the index\r
222                                                 // index it:\r
223                                                 if(x === 'Requestv4') {\r
224                                                         named.lookups.nsstats[x] = {\r
225                                                                 name: 'IPv4',\r
226                                                                 type: 'global_requests'\r
227                                                         };\r
228                                                 }\r
229                                                 else if(x === 'Requestv6') {\r
230                                                         named.lookups.nsstats[x] = {\r
231                                                                 name: 'IPv6',\r
232                                                                 type: 'global_requests'\r
233                                                         };\r
234                                                 }\r
235                                                 else if(x === 'QryFailure') {\r
236                                                         named.lookups.nsstats[x] = {\r
237                                                                 name: 'failures',\r
238                                                                 type: 'global_failures'\r
239                                                         };\r
240                                                 }\r
241                                                 else if(x === 'QryUDP') {\r
242                                                         named.lookups.nsstats[x] = {\r
243                                                                 name: 'UDP',\r
244                                                                 type: 'protocol_queries'\r
245                                                         };\r
246                                                 }\r
247                                                 else if(x === 'QryTCP') {\r
248                                                         named.lookups.nsstats[x] = {\r
249                                                                 name: 'TCP',\r
250                                                                 type: 'protocol_queries'\r
251                                                         };\r
252                                                 }\r
253                                                 else if(x === 'QrySuccess') {\r
254                                                         named.lookups.nsstats[x] = {\r
255                                                                 name: 'queries',\r
256                                                                 type: 'global_queries_success'\r
257                                                         };\r
258                                                 }\r
259                                                 else if(x.match(/QryRej$/) !== null) {\r
260                                                         named.lookups.nsstats[x] = {\r
261                                                                 name: x,\r
262                                                                 type: 'global_failures_detail'\r
263                                                         };\r
264                                                 }\r
265                                                 else if(x.match(/^Qry/) !== null) {\r
266                                                         named.lookups.nsstats[x] = {\r
267                                                                 name: x,\r
268                                                                 type: 'global_queries'\r
269                                                         };\r
270                                                 }\r
271                                                 else if(x.match(/^Update/) !== null) {\r
272                                                         named.lookups.nsstats[x] = {\r
273                                                                 name: x,\r
274                                                                 type: 'global_updates'\r
275                                                         };\r
276                                                 }\r
277                                                 else {\r
278                                                         // values not mapped, will remain\r
279                                                         // in the default map\r
280                                                         named.lookups.nsstats[x] = {\r
281                                                                 name: x,\r
282                                                                 type: 'default'\r
283                                                         };\r
284                                                 }\r
285 \r
286                                                 look = named.lookups.nsstats[x];\r
287                                                 // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);\r
288                                         }\r
289 \r
290                                         switch(look.type) {\r
291                                                 case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;\r
292                                                 case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;\r
293                                                 case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;\r
294                                                 case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;\r
295                                                 case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;\r
296                                                 case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;\r
297                                                 case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;\r
298                                                 default: default_enable = true; break;\r
299                                         }\r
300                                 }\r
301 \r
302                                 if(global_requests_enable == true)\r
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);\r
304 \r
305                                 if(global_queries_success_enable == true)\r
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);\r
307 \r
308                                 if(protocol_queries_enable == true)\r
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);\r
310 \r
311                                 if(global_queries_enable == true)\r
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);\r
313 \r
314                                 if(global_updates_enable == true)\r
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);\r
316 \r
317                                 if(global_failures_enable == true)\r
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);\r
319 \r
320                                 if(global_failures_detail_enable == true)\r
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);\r
322 \r
323                                 if(default_enable === true)\r
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);\r
325 \r
326                                 // RecursClients chart\r
327                                 {\r
328                                         var id = 'named_' + service.name + '.recursive_clients';\r
329                                         var chart = named.charts[id];\r
330 \r
331                                         if(typeof chart === 'undefined') {\r
332                                                 chart = {\r
333                                                         id: id,                                                                                 // the unique id of the chart\r
334                                                         name: '',                                                                               // the unique name of the chart\r
335                                                         title: service.name + ' Bind, Current Recursive Clients',               // the title of the chart\r
336                                                         units: 'clients',                                                               // the units of the chart dimensions\r
337                                                         family: 'named',                                                                // the family of the chart\r
338                                                         category: 'named',                                                              // the category of the chart\r
339                                                         type: netdata.chartTypes.line,                                  // the type of the chart\r
340                                                         priority: 150,                                                                  // the priority relative to others in the same family and category\r
341                                                         update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart\r
342                                                         dimensions: {\r
343                                                                 'clients': {\r
344                                                                         id: 'clients',                                                          // the unique id of the dimension\r
345                                                                         name: '',                                                                       // the name of the dimension\r
346                                                                         algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm\r
347                                                                         multiplier: 1,                                                          // the multiplier\r
348                                                                         divisor: 1,                                                                     // the divisor\r
349                                                                         hidden: false                                                           // is hidden (boolean)\r
350                                                                 }\r
351                                                         }\r
352                                                 };\r
353 \r
354                                                 chart = service.chart(id, chart);\r
355                                                 named.charts[id] = chart;\r
356                                         }\r
357 \r
358                                         service.begin(chart);\r
359                                         service.set('clients', RecursClients);\r
360                                         service.end();\r
361                                 }\r
362                         }\r
363 \r
364                         if(typeof r.opcodes !== 'undefined')\r
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);\r
366 \r
367                         if(typeof r.qtypes !== 'undefined')\r
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);\r
369 \r
370                         if(typeof r.sockstats !== 'undefined')\r
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);\r
372 \r
373                         if(typeof r.views !== 'undefined') {\r
374                                 for( var x in r.views ) {\r
375                                         var resolver = r.views[x].resolver;\r
376 \r
377                                         if(typeof resolver !== 'undefined') {\r
378                                                 if(typeof resolver.stats !== 'undefined') {\r
379                                                         var NumFetch = 0;\r
380                                                         var key = service.name + '.' + x;\r
381                                                         var default_enable = false;\r
382                                                         var rtt = {}, rtt_enable = false;\r
383 \r
384                                                         // NumFetch is an absolute value\r
385                                                         if(typeof resolver.stats['NumFetch'] !== 'undefined') {\r
386                                                                 named.lookups.numfetch[key] = true;\r
387                                                                 NumFetch = resolver.stats['NumFetch'];\r
388                                                                 delete resolver.stats['NumFetch'];\r
389                                                         }\r
390                                                         if(typeof resolver.stats['BucketSize'] !== 'undefined') {\r
391                                                                 delete resolver.stats['BucketSize'];\r
392                                                         }\r
393 \r
394                                                         // split the QryRTT* from the main chart\r
395                                                         for( var y in resolver.stats ) {\r
396                                                                 // we maintain an index of the values found\r
397                                                                 // mapping them to objects splitted\r
398 \r
399                                                                 var look = named.lookups.resolver_stats[y];\r
400                                                                 if(typeof look === 'undefined') {\r
401                                                                         if(y.match(/^QryRTT/) !== null) {\r
402                                                                                 named.lookups.resolver_stats[y] = {\r
403                                                                                         name: y,\r
404                                                                                         type: 'rtt'\r
405                                                                                 };\r
406                                                                         }\r
407                                                                         else {\r
408                                                                                 named.lookups.resolver_stats[y] = {\r
409                                                                                         name: y,\r
410                                                                                         type: 'default'\r
411                                                                                 };\r
412                                                                         }\r
413 \r
414                                                                         look = named.lookups.resolver_stats[y];\r
415                                                                         // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);\r
416                                                                 }\r
417 \r
418                                                                 switch(look.type) {\r
419                                                                         case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;\r
420                                                                         default: default_enable = true; break;\r
421                                                                 }\r
422                                                         }\r
423 \r
424                                                         if(rtt_enable)\r
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);\r
426 \r
427                                                         if(default_enable)\r
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);\r
429 \r
430                                                         // NumFetch chart\r
431                                                         if(typeof named.lookups.numfetch[key] !== 'undefined') {\r
432                                                                 var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;\r
433                                                                 var chart = named.charts[id];\r
434 \r
435                                                                 if(typeof chart === 'undefined') {\r
436                                                                         chart = {\r
437                                                                                 id: id,                                                                                 // the unique id of the chart\r
438                                                                                 name: '',                                                                               // the unique name of the chart\r
439                                                                                 title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries',         // the title of the chart\r
440                                                                                 units: 'queries',                                                               // the units of the chart dimensions\r
441                                                                                 family: 'named',                                                                // the family of the chart\r
442                                                                                 category: 'named',                                                              // the category of the chart\r
443                                                                                 type: netdata.chartTypes.line,                                  // the type of the chart\r
444                                                                                 priority: 5000,                                                                 // the priority relative to others in the same family and category\r
445                                                                                 update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart\r
446                                                                                 dimensions: {\r
447                                                                                         'queries': {\r
448                                                                                                 id: 'queries',                                                          // the unique id of the dimension\r
449                                                                                                 name: '',                                                                       // the name of the dimension\r
450                                                                                                 algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm\r
451                                                                                                 multiplier: 1,                                                          // the multiplier\r
452                                                                                                 divisor: 1,                                                                     // the divisor\r
453                                                                                                 hidden: false                                                           // is hidden (boolean)\r
454                                                                                         }\r
455                                                                                 }\r
456                                                                         };\r
457 \r
458                                                                         chart = service.chart(id, chart);\r
459                                                                         named.charts[id] = chart;\r
460                                                                 }\r
461 \r
462                                                                 service.begin(chart);\r
463                                                                 service.set('queries', NumFetch);\r
464                                                                 service.end();\r
465                                                         }\r
466                                                 }\r
467                                         }\r
468 \r
469                                         if(typeof resolver.qtypes !== 'undefined')\r
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);\r
471 \r
472                                         //if(typeof resolver.cache !== 'undefined')\r
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);\r
474 \r
475                                         if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {\r
476                                                 var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;\r
477                                                 var chart = named.charts[id];\r
478 \r
479                                                 if(typeof chart === 'undefined') {\r
480                                                         chart = {\r
481                                                                 id: id,                                                                                 // the unique id of the chart\r
482                                                                 name: '',                                                                               // the unique name of the chart\r
483                                                                 title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits',             // the title of the chart\r
484                                                                 units: 'operations/s',                                                          // the units of the chart dimensions\r
485                                                                 family: 'named',                                                                // the family of the chart\r
486                                                                 category: 'named',                                                              // the category of the chart\r
487                                                                 type: netdata.chartTypes.area,                                  // the type of the chart\r
488                                                                 priority: 8000,                                                                 // the priority relative to others in the same family and category\r
489                                                                 update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart\r
490                                                                 dimensions: {\r
491                                                                         'CacheHits': {\r
492                                                                                 id: 'CacheHits',                                                        // the unique id of the dimension\r
493                                                                                 name: 'hits',                                                           // the name of the dimension\r
494                                                                                 algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm\r
495                                                                                 multiplier: 1,                                                          // the multiplier\r
496                                                                                 divisor: 1,                                                                     // the divisor\r
497                                                                                 hidden: false                                                           // is hidden (boolean)\r
498                                                                         },\r
499                                                                         'CacheMisses': {\r
500                                                                                 id: 'CacheMisses',                                                      // the unique id of the dimension\r
501                                                                                 name: 'misses',                                                         // the name of the dimension\r
502                                                                                 algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm\r
503                                                                                 multiplier: -1,                                                         // the multiplier\r
504                                                                                 divisor: 1,                                                                     // the divisor\r
505                                                                                 hidden: false                                                           // is hidden (boolean)\r
506                                                                         }\r
507                                                                 }\r
508                                                         };\r
509 \r
510                                                         chart = service.chart(id, chart);\r
511                                                         named.charts[id] = chart;\r
512                                                 }\r
513 \r
514                                                 service.begin(chart);\r
515                                                 service.set('CacheHits', resolver.cachestats['CacheHits']);\r
516                                                 service.set('CacheMisses', resolver.cachestats['CacheMisses']);\r
517                                                 service.end();\r
518                                         }\r
519 \r
520                                         // this is wrong, it contains many types of info:\r
521                                         // 1. CacheHits, CacheMisses - incremental (added above)\r
522                                         // 2. QueryHits, QueryMisses - incremental\r
523                                         // 3. DeleteLRU, DeleteTTL - incremental\r
524                                         // 4. CacheNodes, CacheBuckets - absolute\r
525                                         // 5. TreeMemTotal, TreeMemInUse - absolute\r
526                                         // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute\r
527                                         //if(typeof resolver.cachestats !== 'undefined')\r
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);\r
529 \r
530                                         //if(typeof resolver.adb !== 'undefined')\r
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);\r
532                                 }\r
533                         }\r
534                 }\r
535         },\r
536 \r
537         // module.serviceExecute()\r
538         // this function is called only from this module\r
539         // its purpose is to prepare the request and call\r
540         // netdata.serviceExecute()\r
541         serviceExecute: function(name, a_url, update_every) {\r
542                 if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);\r
543                 netdata.serviceExecute({\r
544                         name: name,\r
545                         request: netdata.requestFromURL(a_url),\r
546                         update_every: update_every,\r
547                         module: this\r
548                 }, this.processResponse);\r
549         },\r
550 \r
551         configure: function(config) {\r
552                 var added = 0;\r
553 \r
554                 if(this.enable_autodetect === true) {\r
555                         this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);\r
556                         added++;\r
557                 }\r
558                 \r
559                 if(typeof(config.servers) !== 'undefined') {\r
560                         var len = config.servers.length;\r
561                         while(len--) {\r
562                                 if(typeof config.servers[len].update_every === 'undefined')\r
563                                         config.servers[len].update_every = this.update_every;\r
564                                 else\r
565                                         config.servers[len].update_every = config.servers[len].update_every * 1000;\r
566 \r
567                                 this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);\r
568                                 added++;\r
569                         }\r
570                 }\r
571 \r
572                 return added;\r
573         },\r
574 \r
575         // module.update()\r
576         // this is called repeatidly to collect data, by calling\r
577         // netdata.serviceExecute()\r
578         update: function(service, callback) {\r
579                 netdata.serviceExecute(service, function(serv, data) {\r
580                         service.module.processResponse(serv, data);\r
581                         callback();\r
582                 });\r
583         },\r
584 };\r
585 \r
586 module.exports = named;\r