summaryrefslogtreecommitdiffstats
path: root/node.d
diff options
context:
space:
mode:
authorLennart Weller <lhw@ring0.de>2017-01-24 15:21:09 +0000
committerLennart Weller <lhw@ring0.de>2017-01-24 15:21:09 +0000
commit3ed3b02ed96ddab1c084811f3579b3a2aec83e04 (patch)
tree7a61ab288ae47800c4f11be5677d6ad8288dcd98 /node.d
parentNew upstream version 1.4.0+dfsg (diff)
downloadnetdata-upstream/1.5.0+dfsg.tar.xz
netdata-upstream/1.5.0+dfsg.zip
New upstream version 1.5.0+dfsgupstream/1.5.0+dfsg
Diffstat (limited to 'node.d')
-rw-r--r--node.d/Makefile.in27
-rw-r--r--node.d/named.node.js167
-rw-r--r--node.d/node_modules/netdata.js1235
-rw-r--r--node.d/sma_webbox.node.js2
-rw-r--r--node.d/snmp.node.js145
5 files changed, 846 insertions, 730 deletions
diff --git a/node.d/Makefile.in b/node.d/Makefile.in
index b338c0bdc..66803fc02 100644
--- a/node.d/Makefile.in
+++ b/node.d/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
@SET_MAKE@
VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -79,19 +89,20 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = node.d
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
- $(dist_node_DATA) $(dist_nodemodules_DATA) \
- $(dist_nodemodulesber_DATA)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/ax_c__generic.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_node_DATA) \
+ $(dist_nodemodules_DATA) $(dist_nodemodulesber_DATA) \
+ $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
@@ -147,6 +158,7 @@ am__installdirs = "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" \
DATA = $(dist_node_DATA) $(dist_nodemodules_DATA) \
$(dist_nodemodulesber_DATA)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -325,7 +337,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu node.d/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu node.d/Makefile
-.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -566,6 +577,8 @@ uninstall-am: uninstall-dist_nodeDATA uninstall-dist_nodemodulesDATA \
uninstall-dist_nodemodulesDATA \
uninstall-dist_nodemodulesberDATA
+.PRECIOUS: Makefile
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/node.d/named.node.js b/node.d/named.node.js
index 19b8ce29b..3d7946557 100644
--- a/node.d/named.node.js
+++ b/node.d/named.node.js
@@ -6,8 +6,8 @@
// http://jpmens.net/2013/03/18/json-in-bind-9-s-statistics-server/
// https://ftp.isc.org/isc/bind/9.10.3/doc/arm/Bv9ARM.ch06.html#statistics
-// example configuration in /etc/netdata/named.conf
-// the module supports auto-detection if bind is running in localhost
+// example configuration in /etc/netdata/node.d/named.conf
+// the module supports auto-detection if bind is running at localhost
/*
{
@@ -41,7 +41,7 @@ var http = require('http');
var XML = require('pixl-xml');
var netdata = require('netdata');
-if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
+if(netdata.options.DEBUG === true) netdata.debug('loaded', __filename, 'plugin');
var named = {
name: __filename,
@@ -62,10 +62,14 @@ var named = {
priority: priority, // the priority relative to others in the same family
update_every: service.update_every, // the expected update frequency of the chart
dimensions: {}
- }
+ };
var found = 0;
- for(var x in obj) {
+ var dims = Object.keys(obj);
+ var len = dims.length;
+ for(var i = 0; i < len ;i++) {
+ var x = dims[i];
+
if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
found++;
chart.dimensions[x] = {
@@ -90,6 +94,7 @@ var named = {
chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
var id = 'named_' + service.name + '.' + id_suffix;
var chart = this.charts[id];
+ var dims, len, x, i;
if(typeof chart === 'undefined') {
chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
@@ -97,7 +102,10 @@ var named = {
}
else {
// check if we need to re-generate the chart
- for(var x in obj) {
+ dims = Object.keys(obj);
+ len = dims.length;
+ for(i = 0; i < len ;i++) {
+ x = dims[i];
if(typeof(chart.dimensions[x]) === 'undefined') {
chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
if(chart === null) return false;
@@ -106,18 +114,22 @@ var named = {
}
}
- var found = 0;
service.begin(chart);
- for(var x in obj) {
+
+ var found = 0;
+ dims = Object.keys(obj);
+ len = dims.length;
+ for(i = 0; i < len ;i++) {
+ x = dims[i];
if(typeof(chart.dimensions[x]) !== 'undefined') {
found++;
service.set(x, obj[x]);
}
}
+
service.end();
- if(found > 0) return true;
- return false;
+ return (found > 0);
},
// an index to map values to different charts
@@ -133,19 +145,21 @@ var named = {
var d = XML.parse(data_xml);
if(d === null) return null;
+ var a, aa, alen, alen2;
+
var data = {};
var len = d.server.counters.length;
while(len--) {
- var a = d.server.counters[len];
+ a = d.server.counters[len];
if(typeof a.counter === 'undefined') continue;
if(a.type === 'opcode') a.type = 'opcodes';
else if(a.type === 'qtype') a.type = 'qtypes';
else if(a.type === 'nsstat') a.type = 'nsstats';
- var aa = data[a.type] = {};
- var alen = 0
- var alen2 = a.counter.length;
+ aa = data[a.type] = {};
+ alen = 0;
+ alen2 = a.counter.length;
while(alen < alen2) {
- aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
+ aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data, 10);
alen++;
}
}
@@ -155,18 +169,18 @@ var named = {
while(vlen--) {
var vname = d.views.view[vlen].name;
data.views[vname] = { resolver: {} };
- var len = d.views.view[vlen].counters.length;
+ len = d.views.view[vlen].counters.length;
while(len--) {
- var a = d.views.view[vlen].counters[len];
+ a = d.views.view[vlen].counters[len];
if(typeof a.counter === 'undefined') continue;
if(a.type === 'resstats') a.type = 'stats';
else if(a.type === 'resqtype') a.type = 'qtypes';
else if(a.type === 'adbstat') a.type = 'adb';
- var aa = data.views[vname].resolver[a.type] = {};
- var alen = 0;
- var alen2 = a.counter.length;
+ aa = data.views[vname].resolver[a.type] = {};
+ alen = 0;
+ alen2 = a.counter.length;
while(alen < alen2) {
- aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
+ aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data, 10);
alen++;
}
}
@@ -177,7 +191,7 @@ var named = {
processResponse: function(service, data) {
if(data !== null) {
- var r;
+ var r, x, look, id, chart, keys, len;
// parse XML or JSON
// pepending on the URL given
@@ -212,11 +226,15 @@ var named = {
delete r.nsstats['RecursClients'];
}
- for( var x in r.nsstats ) {
+ keys = Object.keys(r.nsstats);
+ len = keys.length;
+ while(len--) {
+ x = keys[len];
+
// we maintain an index of the values found
// mapping them to objects splitted
- var look = named.lookups.nsstats[x];
+ look = named.lookups.nsstats[x];
if(typeof look === 'undefined') {
// a new value, not found in the index
// index it:
@@ -299,66 +317,64 @@ var named = {
}
}
- if(global_requests_enable == true)
+ if(global_requests_enable === true)
service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'requests', 'named.requests', netdata.chartTypes.stacked, named.base_priority + 1, netdata.chartAlgorithms.incremental, 1, 1);
- if(global_queries_success_enable == true)
+ if(global_queries_success_enable === true)
service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'queries', 'named.queries_succcess', netdata.chartTypes.line, named.base_priority + 2, netdata.chartAlgorithms.incremental, 1, 1);
- if(protocol_queries_enable == true)
+ if(protocol_queries_enable === true)
service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'queries', 'named.protocol_queries', netdata.chartTypes.stacked, named.base_priority + 3, netdata.chartAlgorithms.incremental, 1, 1);
- if(global_queries_enable == true)
+ if(global_queries_enable === true)
service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'queries', 'named.global_queries', netdata.chartTypes.stacked, named.base_priority + 4, netdata.chartAlgorithms.incremental, 1, 1);
- if(global_updates_enable == true)
+ if(global_updates_enable === true)
service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'updates', 'named.global_updates', netdata.chartTypes.stacked, named.base_priority + 5, netdata.chartAlgorithms.incremental, 1, 1);
- if(global_failures_enable == true)
+ if(global_failures_enable === true)
service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'failures', 'named.global_failures', netdata.chartTypes.line, named.base_priority + 6, netdata.chartAlgorithms.incremental, 1, 1);
- if(global_failures_detail_enable == true)
+ if(global_failures_detail_enable === true)
service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'failures', 'named.global_failures_detail', netdata.chartTypes.stacked, named.base_priority + 7, netdata.chartAlgorithms.incremental, 1, 1);
if(default_enable === true)
service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'other', 'named.nsstats', netdata.chartTypes.line, named.base_priority + 8, netdata.chartAlgorithms.incremental, 1, 1);
// RecursClients chart
- {
- var id = 'named_' + service.name + '.recursive_clients';
- var chart = named.charts[id];
-
- if(typeof chart === 'undefined') {
- chart = {
- id: id, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Bind, Current Recursive Clients', // the title of the chart
- units: 'clients', // the units of the chart dimensions
- family: 'clients', // the family of the chart
- context: 'named.recursive_clients', // the context of the chart
- type: netdata.chartTypes.line, // the type of the chart
- priority: named.base_priority + 1, // the priority relative to others in the same family
- update_every: service.update_every, // the expected update frequency of the chart
- dimensions: {
- 'clients': {
- id: 'clients', // the unique id of the dimension
- name: '', // the name of the dimension
- algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
- multiplier: 1, // the multiplier
- divisor: 1, // the divisor
- hidden: false // is hidden (boolean)
- }
+ id = 'named_' + service.name + '.recursive_clients';
+ chart = named.charts[id];
+
+ if(typeof chart === 'undefined') {
+ chart = {
+ id: id, // the unique id of the chart
+ name: '', // the unique name of the chart
+ title: service.name + ' Bind, Current Recursive Clients', // the title of the chart
+ units: 'clients', // the units of the chart dimensions
+ family: 'clients', // the family of the chart
+ context: 'named.recursive_clients', // the context of the chart
+ type: netdata.chartTypes.line, // the type of the chart
+ priority: named.base_priority + 1, // the priority relative to others in the same family
+ update_every: service.update_every, // the expected update frequency of the chart
+ dimensions: {
+ 'clients': {
+ id: 'clients', // the unique id of the dimension
+ name: '', // the name of the dimension
+ algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+ multiplier: 1, // the multiplier
+ divisor: 1, // the divisor
+ hidden: false // is hidden (boolean)
}
- };
-
- chart = service.chart(id, chart);
- named.charts[id] = chart;
- }
+ }
+ };
- service.begin(chart);
- service.set('clients', RecursClients);
- service.end();
+ chart = service.chart(id, chart);
+ named.charts[id] = chart;
}
+
+ service.begin(chart);
+ service.set('clients', RecursClients);
+ service.end();
}
if(typeof r.opcodes !== 'undefined')
@@ -371,15 +387,18 @@ var named = {
service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'sockets', 'named.in_sockstats', netdata.chartTypes.line, named.base_priority + 11, netdata.chartAlgorithms.incremental, 1, 1);
if(typeof r.views !== 'undefined') {
- for( var x in r.views ) {
+ keys = Object.keys(r.views);
+ len = keys.length;
+ while(len--) {
+ x = keys[len];
var resolver = r.views[x].resolver;
if(typeof resolver !== 'undefined') {
if(typeof resolver.stats !== 'undefined') {
var NumFetch = 0;
var key = service.name + '.' + x;
- var default_enable = false;
var rtt = {}, rtt_enable = false;
+ default_enable = false;
// NumFetch is an absolute value
if(typeof resolver.stats['NumFetch'] !== 'undefined') {
@@ -392,11 +411,15 @@ var named = {
}
// split the QryRTT* from the main chart
- for( var y in resolver.stats ) {
+ var ykeys = Object.keys(resolver.stats);
+ var ylen = ykeys.length;
+ while(ylen--) {
+ var y = ykeys[ylen];
+
// we maintain an index of the values found
// mapping them to objects splitted
- var look = named.lookups.resolver_stats[y];
+ look = named.lookups.resolver_stats[y];
if(typeof look === 'undefined') {
if(y.match(/^QryRTT/) !== null) {
named.lookups.resolver_stats[y] = {
@@ -429,8 +452,8 @@ var named = {
// NumFetch chart
if(typeof named.lookups.numfetch[key] !== 'undefined') {
- var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
- var chart = named.charts[id];
+ id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
+ chart = named.charts[id];
if(typeof chart === 'undefined') {
chart = {
@@ -473,8 +496,8 @@ var named = {
// service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'view_' + x, 'named.resolver_cache', netdata.chartTypes.stacked, named.base_priority + 15, netdata.chartAlgorithms.absolute, 1, 1);
if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
- var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
- var chart = named.charts[id];
+ id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
+ chart = named.charts[id];
if(typeof chart === 'undefined') {
chart = {
@@ -580,7 +603,7 @@ var named = {
service.module.processResponse(serv, data);
callback();
});
- },
+ }
};
module.exports = named;
diff --git a/node.d/node_modules/netdata.js b/node.d/node_modules/netdata.js
index 6183993b5..11202061e 100644
--- a/node.d/node_modules/netdata.js
+++ b/node.d/node_modules/netdata.js
@@ -1,5 +1,10 @@
'use strict';
+// netdata
+// real-time performance and health monitoring, done right!
+// (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
+// GPL v3+
+
var url = require('url');
var http = require('http');
var util = require('util');
@@ -8,609 +13,641 @@ var util = require('util');
var netdata = require('netdata');
var example_chart = {
- id: 'id', // the unique id of the chart
- name: 'name', // the name of the chart
- title: 'title', // the title of the chart
- units: 'units', // the units of the chart dimensions
- family: 'family', // the family of the chart
- context: 'context', // the context of the chart
- type: netdata.chartTypes.line, // the type of the chart
- priority: 0, // the priority relative to others in the same family
- update_every: 1, // the expected update frequency of the chart
- dimensions: {
- 'dim1': {
- id: 'dim1', // the unique id of the dimension
- name: 'name', // the name of the dimension
- algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm
- multiplier: 1, // the multiplier
- divisor: 1, // the divisor
- hidden: false, // is hidden (boolean)
- },
- 'dim2': {
- id: 'dim2', // the unique id of the dimension
- name: 'name', // the name of the dimension
- algorithm: 'absolute', // the id of the netdata algorithm
- multiplier: 1, // the multiplier
- divisor: 1, // the divisor
- hidden: false, // is hidden (boolean)
- }
- // add as many dimensions as needed
- }
+ id: 'id', // the unique id of the chart
+ name: 'name', // the name of the chart
+ title: 'title', // the title of the chart
+ units: 'units', // the units of the chart dimensions
+ family: 'family', // the family of the chart
+ context: 'context', // the context of the chart
+ type: netdata.chartTypes.line, // the type of the chart
+ priority: 0, // the priority relative to others in the same family
+ update_every: 1, // the expected update frequency of the chart
+ dimensions: {
+ 'dim1': {
+ id: 'dim1', // the unique id of the dimension
+ name: 'name', // the name of the dimension
+ algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm
+ multiplier: 1, // the multiplier
+ divisor: 1, // the divisor
+ hidden: false, // is hidden (boolean)
+ },
+ 'dim2': {
+ id: 'dim2', // the unique id of the dimension
+ name: 'name', // the name of the dimension
+ algorithm: 'absolute', // the id of the netdata algorithm
+ multiplier: 1, // the multiplier
+ divisor: 1, // the divisor
+ hidden: false, // is hidden (boolean)
+ }
+ // add as many dimensions as needed
+ }
};
*/
var netdata = {
- options: {
- filename: __filename,
- DEBUG: false,
- update_every: 1,
- },
-
- chartAlgorithms: {
- incremental: 'incremental',
- absolute: 'absolute',
- percentage_of_absolute_row: 'percentage-of-absolute-row',
- percentage_of_incremental_row: 'percentage-of-incremental-row'
- },
-
- chartTypes: {
- line: 'line',
- area: 'area',
- stacked: 'stacked'
- },
-
- services: new Array(),
- modules_configuring: 0,
- charts: {},
-
-
- processors: {
- http: {
- name: 'http',
-
- process: function(service, callback) {
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': making ' + this.name + ' request: ' + netdata.stringify(service.request));
-
- var req = http.request(service.request, function(response) {
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': got server response...');
-
- var end = false;
- var data = '';
- response.setEncoding('utf8');
-
- if(response.statusCode !== 200) {
- if(end === false) {
- service.error('Got HTTP code ' + response.statusCode + ', failed to get data.');
- end = true;
- callback(null);
- }
- }
-
- response.on('data', function(chunk) {
- if(end === false) data += chunk;
- });
-
- response.on('error', function() {
- if(end === false) {
- service.error(': Read error, failed to get data.');
- end = true;
- callback(null);
- }
- });
-
- response.on('end', function() {
- if(end === false) {
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': read completed.');
- end = true;
- callback(data);
- }
- });
- });
-
- req.on('error', function(e) {
- service.error('Failed to make request: ' + netdata.stringify(service.request) + ', message: ' + e.message);
- callback(null);
- });
-
- // write data to request body
- if(typeof service.postData !== 'undefined' && service.request.method === 'POST') {
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': posting data: ' + service.postData);
- req.write(service.postData);
- }
-
- req.end();
- }
- }
- },
-
- stringify: function(obj) {
- return util.inspect(obj, {depth: 10});
- },
-
- // show debug info, if debug is enabled
- debug: function(msg) {
- if(this.options.DEBUG === true) {
- var now = new Date();
- console.error(now.toString() + ': ' + netdata.options.filename + ': DEBUG: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString());
- }
- },
-
- // log an error
- error: function(msg) {
- var now = new Date();
- console.error(now.toString() + ': ' + netdata.options.filename + ': ERROR: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString());
- },
-
- // send data to netdata
- send: function(msg) {
- console.log(msg.toString());
- },
-
- service: function(service) {
- if(typeof service === 'undefined')
- service = {};
-
- var now = new Date().getTime();
-
- service._current_chart = null; // the current chart we work on
- service._queue = ''; // data to be sent to netdata
-
- service.error_reported = false; // error log flood control
-
- service.added = false; // added to netdata.services
- service.enabled = true;
- service.updates = 0;
- service.running = false;
- service.started = 0;
- service.ended = 0;
-
- if(typeof service.module === 'undefined') {
- service.module = { name: 'not-defined-module' };
- service.error('Attempted to create service without a module.');
- service.enabled = false;
- }
-
- if(typeof service.name === 'undefined') {
- service.name = 'unnamed@' + service.module.name + '/' + now;
- }
-
- if(typeof service.processor === 'undefined')
- service.processor = netdata.processors.http;
-
- if(typeof service.update_every === 'undefined')
- service.update_every = service.module.update_every;
-
- if(typeof service.update_every === 'undefined')
- service.update_every = netdata.options.update_every;
-
- if(service.update_every < netdata.options.update_every)
- service.update_every = netdata.options.update_every;
-
- // align the runs
- service.next_run = now - (now % (service.update_every * 1000));
-
- service.commit = function() {
- if(this.added !== true) {
- this.added = true;
-
- var now = new Date().getTime();
- while( this.next_run < now )
- this.next_run += (this.update_every * 1000);
-
- netdata.services.push(this);
- if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': service committed.');
- }
- };
-
- service.execute = function(callback) {
- if(service.enabled === false) {
- callback(null);
- return;
- }
-
- this.module.active++;
- this.running = true;
- this.started = new Date().getTime();
- this.updates++;
-
- if(netdata.options.DEBUG === true)
- netdata.debug(this.module.name + ': ' + this.name + ': making ' + this.processor.name + ' request: ' + netdata.stringify(this));
-
- this.processor.process(this, function(response) {
- service.ended = new Date().getTime();
- service.duration = service.ended - service.started;
-
- if(typeof response === 'undefined')
- response = null;
-
- if(response !== null)
- service.errorClear();
-
- if(netdata.options.DEBUG === true)
- netdata.debug(service.module.name + ': ' + service.name + ': processing ' + service.processor.name + ' response (received in ' + (service.ended - service.started).toString() + ' ms)');
-
- callback(service, response);
-
- service.running = false;
- service.module.active--;
- if(service.module.active < 0) {
- service.module.active = 0;
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': active module counter below zero.');
- }
-
- if(service.module.active === 0) {
- // check if we run under configure
- if(service.module.configure_callback !== null) {
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': configuration finish callback called from processResponse().');
- var ccallback = service.module.configure_callback;
- service.module.configure_callback = null;
- ccallback();
- }
- }
- });
- };
-
- service.update = function() {
- if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': starting data collection...');
-
- this.module.update(this, function() {
- if(netdata.options.DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': data collection ended in ' + service.duration.toString() + ' ms.');
- });
- };
-
- service.error = function(message) {
- if(this.error_reported === false) {
- netdata.error(this.module.name + ': ' + this.name + ': ' + message);
- this.error_reported = true;
- }
- else if(netdata.options.DEBUG === true)
- netdata.debug(this.module.name + ': ' + this.name + ': ' + message);
- };
-
- service.errorClear = function() {
- this.error_reported = false;
- };
-
- service.queue = function(txt) {
- this._queue += txt + '\n';
- };
-
- service._send_chart_to_netdata = function(chart) {
- // internal function to send a chart to netdata
- this.queue('CHART "' + chart.id + '" "' + chart.name + '" "' + chart.title + '" "' + chart.units + '" "' + chart.family + '" "' + chart.context + '" "' + chart.type + '" ' + chart.priority.toString() + ' ' + chart.update_every.toString());
-
- for(var dim in chart.dimensions) {
- var d = chart.dimensions[dim];
-
- this.queue('DIMENSION "' + d.id + '" "' + d.name + '" "' + d.algorithm + '" ' + d.multiplier.toString() + ' ' + d.divisor.toString() + ' ' + ((d.hidden === true)?'hidden':'').toString());
- d._created = true;
- d._updated = false;
- }
-
- chart._created = true;
- chart._updated = false;
- };
-
- // begin data collection for a chart
- service.begin = function(chart) {
- if(this._current_chart !== null && this._current_chart !== chart) {
- this.error('Called begin() for chart ' + chart.id + ' while chart ' + this._current_chart.id + ' is still open. Closing it.');
- this.end();
- }
-
- if(typeof(chart.id) === 'undefined' || netdata.charts[chart.id] != chart) {
- this.error('Called begin() for chart ' + chart.id + ' that is not mine. Where did you find it? Ignoring it.');
- return false;
- }
-
- if(netdata.options.DEBUG === true) netdata.debug('setting current chart to ' + chart.id);
- this._current_chart = chart;
- this._current_chart._began = true;
-
- if(this._current_chart._dimensions_count !== 0) {
- if(this._current_chart._created === false || this._current_chart._updated === true)
- this._send_chart_to_netdata(this._current_chart);
-
- var now = this.ended;
- this.queue('BEGIN ' + this._current_chart.id + ' ' + ((this._current_chart._last_updated > 0)?((now - this._current_chart._last_updated) * 1000):'').toString());
- }
- // else this.error('Called begin() for chart ' + chart.id + ' which is empty.');
-
- this._current_chart._last_updated = now;
- this._current_chart._began = true;
- this._current_chart._counter++;
-
- return true;
- };
-
- // set a collected value for a chart
- // we do most things on the first value we attempt to set
- service.set = function(dimension, value) {
- if(this._current_chart === null) {
- this.error('Called set(' + dimension + ', ' + value + ') without an open chart.');
- return false;
- }
-
- if(typeof(this._current_chart.dimensions[dimension]) === 'undefined') {
- this.error('Called set(' + dimension + ', ' + value + ') but dimension "' + dimension + '" does not exist in chart "' + this._current_chart.id + '".');
- return false;
- }
-
- if(typeof value === 'undefined' || value === null)
- return false;
-
- if(this._current_chart._dimensions_count !== 0) {
- if (value instanceof Buffer)
- this.queue('SET ' + dimension + ' = 0x' + value.toString('hex'));
- else
- this.queue('SET ' + dimension + ' = ' + value.toString());
- }
-
- return true;
- };
-
- // end data collection for the current chart - after calling begin()
- service.end = function() {
- if(this._current_chart !== null && this._current_chart._began === false) {
- this.error('Called end() without an open chart.');
- return false;
- }
-
- if(this._current_chart._dimensions_count !== 0) {
- this.queue('END');
- netdata.send(this._queue);
- }
-
- this._queue = '';
- this._current_chart._began = false;
- if(netdata.options.DEBUG === true) netdata.debug('sent chart ' + this._current_chart.id);
- this._current_chart = null;
- return true;
- };
-
- // discard the collected values for the current chart - after calling begin()
- service.flush = function() {
- if(this._current_chart === null || this._current_chart._began === false) {
- this.error('Called flush() without an open chart.');
- return false;
- }
-
- this._queue = '';
- this._current_chart._began = false;
- this._current_chart = null;
- return true;
- };
-
- // create a netdata chart
- service.chart = function(id, chart) {
- if(typeof(netdata.charts[id]) === 'undefined') {
- netdata.charts[id] = {
- _created: false,
- _updated: true,
- _began: false,
- _counter: 0,
- _last_updated: 0,
- _dimensions_count: 0,
- id: id,
- name: id,
- title: 'untitled chart',
- units: 'a unit',
- family: '',
- context: '',
- type: netdata.chartTypes.line,
- priority: 50000,
- update_every: netdata.options.update_every,
- dimensions: {}
- };
- }
-
- var c = netdata.charts[id];
-
- if(typeof(chart.name) !== 'undefined' && chart.name !== c.name) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its name');
- c.name = chart.name;
- c._updated = true;
- }
-
- if(typeof(chart.title) !== 'undefined' && chart.title !== c.title) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its title');
- c.title = chart.title;
- c._updated = true;
- }
-
- if(typeof(chart.units) !== 'undefined' && chart.units !== c.units) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its units');
- c.units = chart.units;
- c._updated = true;
- }
-
- if(typeof(chart.family) !== 'undefined' && chart.family !== c.family) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its family');
- c.family = chart.family;
- c._updated = true;
- }
-
- if(typeof(chart.context) !== 'undefined' && chart.context !== c.context) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its context');
- c.context = chart.context;
- c._updated = true;
- }
-
- if(typeof(chart.type) !== 'undefined' && chart.type !== c.type) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its type');
- c.type = chart.type;
- c._updated = true;
- }
-
- if(typeof(chart.priority) !== 'undefined' && chart.priority !== c.priority) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its priority');
- c.priority = chart.priority;
- c._updated = true;
- }
-
- if(typeof(chart.update_every) !== 'undefined' && chart.update_every !== c.update_every) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' updated its update_every from ' + c.update_every + ' to ' + chart.update_every);
- c.update_every = chart.update_every;
- c._updated = true;
- }
-
- if(typeof(chart.dimensions) !== 'undefined') {
- for(var x in chart.dimensions) {
- if(typeof(c.dimensions[x]) === 'undefined') {
- c._dimensions_count++;
-
- c.dimensions[x] = {
- _created: false,
- _updated: false,
- id: x, // the unique id of the dimension
- name: x, // the name of the dimension
- algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm
- multiplier: 1, // the multiplier
- divisor: 1, // the divisor
- hidden: false, // is hidden (boolean)
- };
-
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ' created dimension ' + x);
- c._updated = true;
- }
-
- var dim = chart.dimensions[x];
- var d = c.dimensions[x];
-
- if(typeof(dim.name) !== 'undefined' && d.name !== dim.name) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its name');
- d.name = dim.name;
- d._updated = true;
- }
-
- if(typeof(dim.algorithm) !== 'undefined' && d.algorithm !== dim.algorithm) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its algorithm from ' + d.algorithm + ' to ' + dim.algorithm);
- d.algorithm = dim.algorithm;
- d._updated = true;
- }
-
- if(typeof(dim.multiplier) !== 'undefined' && d.multiplier !== dim.multiplier) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its multiplier');
- d.multiplier = dim.multiplier;
- d._updated = true;
- }
-
- if(typeof(dim.divisor) !== 'undefined' && d.divisor !== dim.divisor) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its divisor');
- d.divisor = dim.divisor;
- d._updated = true;
- }
-
- if(typeof(dim.hidden) !== 'undefined' && d.hidden !== dim.hidden) {
- if(netdata.options.DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its hidden status');
- d.hidden = dim.hidden;
- d._updated = true;
- }
-
- if(d._updated) c._updated = true;
- }
- }
-
- //if(netdata.options.DEBUG === true) netdata.debug(netdata.charts);
- return netdata.charts[id];
- };
-
- return service;
- },
-
- runAllServices: function() {
- if(netdata.options.DEBUG === true) netdata.debug('runAllServices()');
-
- var now = new Date().getTime();
- var len = netdata.services.length;
- while(len--) {
- var service = netdata.services[len];
-
- if(service.enabled === false || service.running === true) continue;
- if(now <= service.next_run) continue;
-
- service.update();
-
- now = new Date().getTime();
- while(service.next_run < now)
- service.next_run += (service.update_every * 1000);
- }
-
- // 1/10th of update_every in pause
- setTimeout(netdata.runAllServices, netdata.options.update_every * 100);
- },
-
- start: function() {
- if(netdata.options.DEBUG === true) this.debug('started, services: ' + netdata.stringify(this.services));
-
- if(this.services.length === 0) {
- this.disableNodePlugin();
- process.exit(1);
- }
- else this.runAllServices();
- },
-
- // disable the whole node.js plugin
- disableNodePlugin: function() {
- this.send('DISABLE');
- process.exit(1);
- },
-
- requestFromParams: function(protocol, hostname, port, path, method) {
- return {
- protocol: protocol,
- hostname: hostname,
- port: port,
- path: path,
- //family: 4,
- method: method,
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Connection': 'keep-alive'
- },
- agent: new http.Agent({
- keepAlive: true,
- keepAliveMsecs: netdata.options.update_every * 1000,
- maxSockets: 2, // it must be 2 to work
- maxFreeSockets: 1
- })
- };
- },
-
- requestFromURL: function(a_url) {
- var u = url.parse(a_url);
- return netdata.requestFromParams(u.protocol, u.hostname, u.port, u.path, 'GET');
- },
-
- configure: function(module, config, callback) {
- if(netdata.options.DEBUG === true) this.debug(module.name + ': configuring (update_every: ' + this.options.update_every + ')...');
-
- module.active = 0;
- module.update_every = this.options.update_every;
-
- if(typeof config.update_every !== 'undefined')
- module.update_every = config.update_every;
-
- module.enable_autodetect = (config.enable_autodetect)?true:false;
-
- if(typeof(callback) === 'function')
- module.configure_callback = callback;
- else
- module.configure_callback = null;
-
- var added = module.configure(config);
-
- if(netdata.options.DEBUG === true) this.debug(module.name + ': configured, reporting ' + added + ' eligible services.');
-
- if(module.configure_callback !== null && added === 0) {
- if(netdata.options.DEBUG === true) this.debug(module.name + ': configuration finish callback called from configure().');
- module.configure_callback = null;
- callback();
- }
-
- return added;
- }
+ options: {
+ filename: __filename,
+ DEBUG: false,
+ update_every: 1
+ },
+
+ chartAlgorithms: {
+ incremental: 'incremental',
+ absolute: 'absolute',
+ percentage_of_absolute_row: 'percentage-of-absolute-row',
+ percentage_of_incremental_row: 'percentage-of-incremental-row'
+ },
+
+ chartTypes: {
+ line: 'line',
+ area: 'area',
+ stacked: 'stacked'
+ },
+
+ services: new Array(),
+ modules_configuring: 0,
+ charts: {},
+
+
+ processors: {
+ http: {
+ name: 'http',
+
+ process: function(service, callback) {
+ var __DEBUG = netdata.options.DEBUG;
+
+ if(__DEBUG === true)
+ netdata.debug(service.module.name + ': ' + service.name + ': making ' + this.name + ' request: ' + netdata.stringify(service.request));
+
+ var req = http.request(service.request, function(response) {
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': got server response...');
+
+ var end = false;
+ var data = '';
+ response.setEncoding('utf8');
+
+ if(response.statusCode !== 200) {
+ if(end === false) {
+ service.error('Got HTTP code ' + response.statusCode + ', failed to get data.');
+ end = true;
+ return callback(null);
+ }
+ }
+
+ response.on('data', function(chunk) {
+ if(end === false) data += chunk;
+ });
+
+ response.on('error', function() {
+ if(end === false) {
+ service.error(': Read error, failed to get data.');
+ end = true;
+ return callback(null);
+ }
+ });
+
+ response.on('end', function() {
+ if(end === false) {
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': read completed.');
+ end = true;
+ return callback(data);
+ }
+ });
+ });
+
+ req.on('error', function(e) {
+ if(__DEBUG === true) netdata.debug('Failed to make request: ' + netdata.stringify(service.request) + ', message: ' + e.message);
+ service.error('Failed to make request, message: ' + e.message);
+ return callback(null);
+ });
+
+ // write data to request body
+ if(typeof service.postData !== 'undefined' && service.request.method === 'POST') {
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': posting data: ' + service.postData);
+ req.write(service.postData);
+ }
+
+ req.end();
+ }
+ }
+ },
+
+ stringify: function(obj) {
+ return util.inspect(obj, {depth: 10});
+ },
+
+ zeropad2: function(s) {
+ return ("00" + s).slice(-2);
+ },
+
+ logdate: function(d) {
+ if(typeof d === 'undefined') d = new Date();
+ return d.getFullYear().toString() + '-' + this.zeropad2(d.getMonth() + 1) + '-' + this.zeropad2(d.getDate())
+ + ' ' + this.zeropad2(d.getHours()) + ':' + this.zeropad2(d.getMinutes()) + ':' + this.zeropad2(d.getSeconds());
+ },
+
+ // show debug info, if debug is enabled
+ debug: function(msg) {
+ if(this.options.DEBUG === true) {
+ console.error(this.logdate() + ': ' + netdata.options.filename + ': DEBUG: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString());
+ }
+ },
+
+ // log an error
+ error: function(msg) {
+ console.error(this.logdate() + ': ' + netdata.options.filename + ': ERROR: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString());
+ },
+
+ // send data to netdata
+ send: function(msg) {
+ console.log(msg.toString());
+ },
+
+ service: function(service) {
+ if(typeof service === 'undefined')
+ service = {};
+
+ var now = Date.now();
+
+ service._current_chart = null; // the current chart we work on
+ service._queue = ''; // data to be sent to netdata
+
+ service.error_reported = false; // error log flood control
+
+ service.added = false; // added to netdata.services
+ service.enabled = true;
+ service.updates = 0;
+ service.running = false;
+ service.started = 0;
+ service.ended = 0;
+
+ if(typeof service.module === 'undefined') {
+ service.module = { name: 'not-defined-module' };
+ service.error('Attempted to create service without a module.');
+ service.enabled = false;
+ }
+
+ if(typeof service.name === 'undefined') {
+ service.name = 'unnamed@' + service.module.name + '/' + now;
+ }
+
+ if(typeof service.processor === 'undefined')
+ service.processor = netdata.processors.http;
+
+ if(typeof service.update_every === 'undefined')
+ service.update_every = service.module.update_every;
+
+ if(typeof service.update_every === 'undefined')
+ service.update_every = netdata.options.update_every;
+
+ if(service.update_every < netdata.options.update_every)
+ service.update_every = netdata.options.update_every;
+
+ // align the runs
+ service.next_run = now - (now % (service.update_every * 1000)) + (service.update_every * 1000);
+
+ service.commit = function() {
+ if(this.added !== true) {
+ this.added = true;
+
+ var now = Date.now();
+ this.next_run = now - (now % (service.update_every * 1000)) + (service.update_every * 1000);
+
+ netdata.services.push(this);
+ if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': service committed.');
+ }
+ };
+
+ service.execute = function(responseProcessor) {
+ var __DEBUG = netdata.options.DEBUG;
+
+ if(service.enabled === false)
+ return responseProcessor(null);
+
+ this.module.active++;
+ this.running = true;
+ this.started = Date.now();
+ this.updates++;
+
+ if(__DEBUG === true)
+ netdata.debug(this.module.name + ': ' + this.name + ': making ' + this.processor.name + ' request: ' + netdata.stringify(this));
+
+ this.processor.process(this, function(response) {
+ service.ended = Date.now();
+ service.duration = service.ended - service.started;
+
+ if(typeof response === 'undefined')
+ response = null;
+
+ if(response !== null)
+ service.errorClear();
+
+ if(__DEBUG === true)
+ netdata.debug(service.module.name + ': ' + service.name + ': processing ' + service.processor.name + ' response (received in ' + (service.ended - service.started).toString() + ' ms)');
+
+ responseProcessor(service, response);
+
+ service.running = false;
+ service.module.active--;
+ if(service.module.active < 0) {
+ service.module.active = 0;
+ if(__DEBUG === true)
+ netdata.debug(service.module.name + ': active module counter below zero.');
+ }
+
+ if(service.module.active === 0) {
+ // check if we run under configure
+ if(service.module.configure_callback !== null) {
+ if(__DEBUG === true)
+ netdata.debug(service.module.name + ': configuration finish callback called from processResponse().');
+
+ var configure_callback = service.module.configure_callback;
+ service.module.configure_callback = null;
+ configure_callback();
+ }
+ }
+ });
+ };
+
+ service.update = function() {
+ if(netdata.options.DEBUG === true)
+ netdata.debug(this.module.name + ': ' + this.name + ': starting data collection...');
+
+ this.module.update(this, function() {
+ if(netdata.options.DEBUG === true)
+ netdata.debug(service.module.name + ': ' + service.name + ': data collection ended in ' + service.duration.toString() + ' ms.');
+ });
+ };
+
+ service.error = function(message) {
+ if(this.error_reported === false) {
+ netdata.error(this.module.name + ': ' + this.name + ': ' + message);
+ this.error_reported = true;
+ }
+ else if(netdata.options.DEBUG === true)
+ netdata.debug(this.module.name + ': ' + this.name + ': ' + message);
+ };
+
+ service.errorClear = function() {
+ this.error_reported = false;
+ };
+
+ service.queue = function(txt) {
+ this._queue += txt + '\n';
+ };
+
+ service._send_chart_to_netdata = function(chart) {
+ // internal function to send a chart to netdata
+ this.queue('CHART "' + chart.id + '" "' + chart.name + '" "' + chart.title + '" "' + chart.units + '" "' + chart.family + '" "' + chart.context + '" "' + chart.type + '" ' + chart.priority.toString() + ' ' + chart.update_every.toString());
+
+ if(typeof(chart.dimensions) !== 'undefined') {
+ var dims = Object.keys(chart.dimensions);
+ var len = dims.length;
+ while(len--) {
+ var d = chart.dimensions[dims[len]];
+
+ this.queue('DIMENSION "' + d.id + '" "' + d.name + '" "' + d.algorithm + '" ' + d.multiplier.toString() + ' ' + d.divisor.toString() + ' ' + ((d.hidden === true) ? 'hidden' : '').toString());
+ d._created = true;
+ d._updated = false;
+ }
+ }
+
+ chart._created = true;
+ chart._updated = false;
+ };
+
+ // begin data collection for a chart
+ service.begin = function(chart) {
+ if(this._current_chart !== null && this._current_chart !== chart) {
+ this.error('Called begin() for chart ' + chart.id + ' while chart ' + this._current_chart.id + ' is still open. Closing it.');
+ this.end();
+ }
+
+ if(typeof(chart.id) === 'undefined' || netdata.charts[chart.id] !== chart) {
+ this.error('Called begin() for chart ' + chart.id + ' that is not mine. Where did you find it? Ignoring it.');
+ return false;
+ }
+
+ if(netdata.options.DEBUG === true) netdata.debug('setting current chart to ' + chart.id);
+ this._current_chart = chart;
+ this._current_chart._began = true;
+
+ if(this._current_chart._dimensions_count !== 0) {
+ if(this._current_chart._created === false || this._current_chart._updated === true)
+ this._send_chart_to_netdata(this._current_chart);
+
+ var now = this.ended;
+ this.queue('BEGIN ' + this._current_chart.id + ' ' + ((this._current_chart._last_updated > 0)?((now - this._current_chart._last_updated) * 1000):'').toString());
+ }
+ // else this.error('Called begin() for chart ' + chart.id + ' which is empty.');
+
+ this._current_chart._last_updated = now;
+ this._current_chart._began = true;
+ this._current_chart._counter++;
+
+ return true;
+ };
+
+ // set a collected value for a chart
+ // we do most things on the first value we attempt to set
+ service.set = function(dimension, value) {
+ if(this._current_chart === null) {
+ this.error('Called set(' + dimension + ', ' + value + ') without an open chart.');
+ return false;
+ }
+
+ if(typeof(this._current_chart.dimensions[dimension]) === 'undefined') {
+ this.error('Called set(' + dimension + ', ' + value + ') but dimension "' + dimension + '" does not exist in chart "' + this._current_chart.id + '".');
+ return false;
+ }
+
+ if(typeof value === 'undefined' || value === null)
+ return false;
+
+ if(this._current_chart._dimensions_count !== 0) {
+ if (value instanceof Buffer)
+ this.queue('SET ' + dimension + ' = 0x' + value.toString('hex'));
+ else
+ this.queue('SET ' + dimension + ' = ' + value.toString());
+ }
+
+ return true;
+ };
+
+ // end data collection for the current chart - after calling begin()
+ service.end = function() {
+ if(this._current_chart !== null && this._current_chart._began === false) {
+ this.error('Called end() without an open chart.');
+ return false;
+ }
+
+ if(this._current_chart._dimensions_count !== 0) {
+ this.queue('END');
+ netdata.send(this._queue);
+ }
+
+ this._queue = '';
+ this._current_chart._began = false;
+ if(netdata.options.DEBUG === true) netdata.debug('sent chart ' + this._current_chart.id);
+ this._current_chart = null;
+ return true;
+ };
+
+ // discard the collected values for the current chart - after calling begin()
+ service.flush = function() {
+ if(this._current_chart === null || this._current_chart._began === false) {
+ this.error('Called flush() without an open chart.');
+ return false;
+ }
+
+ this._queue = '';
+ this._current_chart._began = false;
+ this._current_chart = null;
+ return true;
+ };
+
+ // create a netdata chart
+ service.chart = function(id, chart) {
+ var __DEBUG = netdata.options.DEBUG;
+
+ if(typeof(netdata.charts[id]) === 'undefined') {
+ netdata.charts[id] = {
+ _created: false,
+ _updated: true,
+ _began: false,
+ _counter: 0,
+ _last_updated: 0,
+ _dimensions_count: 0,
+ id: id,
+ name: id,
+ title: 'untitled chart',
+ units: 'a unit',
+ family: '',
+ context: '',
+ type: netdata.chartTypes.line,
+ priority: 50000,
+ update_every: netdata.options.update_every,
+ dimensions: {}
+ };
+ }
+
+ var c = netdata.charts[id];
+
+ if(typeof(chart.name) !== 'undefined' && chart.name !== c.name) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its name');
+ c.name = chart.name;
+ c._updated = true;
+ }
+
+ if(typeof(chart.title) !== 'undefined' && chart.title !== c.title) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its title');
+ c.title = chart.title;
+ c._updated = true;
+ }
+
+ if(typeof(chart.units) !== 'undefined' && chart.units !== c.units) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its units');
+ c.units = chart.units;
+ c._updated = true;
+ }
+
+ if(typeof(chart.family) !== 'undefined' && chart.family !== c.family) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its family');
+ c.family = chart.family;
+ c._updated = true;
+ }
+
+ if(typeof(chart.context) !== 'undefined' && chart.context !== c.context) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its context');
+ c.context = chart.context;
+ c._updated = true;
+ }
+
+ if(typeof(chart.type) !== 'undefined' && chart.type !== c.type) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its type');
+ c.type = chart.type;
+ c._updated = true;
+ }
+
+ if(typeof(chart.priority) !== 'undefined' && chart.priority !== c.priority) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its priority');
+ c.priority = chart.priority;
+ c._updated = true;
+ }
+
+ if(typeof(chart.update_every) !== 'undefined' && chart.update_every !== c.update_every) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its update_every from ' + c.update_every + ' to ' + chart.update_every);
+ c.update_every = chart.update_every;
+ c._updated = true;
+ }
+
+ if(typeof(chart.dimensions) !== 'undefined') {
+ var dims = Object.keys(chart.dimensions);
+ var len = dims.length;
+ while(len--) {
+ var x = dims[len];
+
+ if(typeof(c.dimensions[x]) === 'undefined') {
+ c._dimensions_count++;
+
+ c.dimensions[x] = {
+ _created: false,
+ _updated: false,
+ id: x, // the unique id of the dimension
+ name: x, // the name of the dimension
+ algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm
+ multiplier: 1, // the multiplier
+ divisor: 1, // the divisor
+ hidden: false // is hidden (boolean)
+ };
+
+ if(__DEBUG === true) netdata.debug('chart ' + id + ' created dimension ' + x);
+ c._updated = true;
+ }
+
+ var dim = chart.dimensions[x];
+ var d = c.dimensions[x];
+
+ if(typeof(dim.name) !== 'undefined' && d.name !== dim.name) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its name');
+ d.name = dim.name;
+ d._updated = true;
+ }
+
+ if(typeof(dim.algorithm) !== 'undefined' && d.algorithm !== dim.algorithm) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its algorithm from ' + d.algorithm + ' to ' + dim.algorithm);
+ d.algorithm = dim.algorithm;
+ d._updated = true;
+ }
+
+ if(typeof(dim.multiplier) !== 'undefined' && d.multiplier !== dim.multiplier) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its multiplier');
+ d.multiplier = dim.multiplier;
+ d._updated = true;
+ }
+
+ if(typeof(dim.divisor) !== 'undefined' && d.divisor !== dim.divisor) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its divisor');
+ d.divisor = dim.divisor;
+ d._updated = true;
+ }
+
+ if(typeof(dim.hidden) !== 'undefined' && d.hidden !== dim.hidden) {
+ if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its hidden status');
+ d.hidden = dim.hidden;
+ d._updated = true;
+ }
+
+ if(d._updated) c._updated = true;
+ }
+ }
+
+ //if(netdata.options.DEBUG === true) netdata.debug(netdata.charts);
+ return netdata.charts[id];
+ };
+
+ return service;
+ },
+
+ runAllServices: function() {
+ if(netdata.options.DEBUG === true) netdata.debug('runAllServices()');
+
+ var now = Date.now();
+ var len = netdata.services.length;
+ while(len--) {
+ var service = netdata.services[len];
+
+ if(service.enabled === false || service.running === true) continue;
+ if(now <= service.next_run) continue;
+
+ service.update();
+
+ now = Date.now();
+ service.next_run = now - (now % (service.update_every * 1000)) + (service.update_every * 1000);
+ }
+
+ // 1/10th of update_every in pause
+ setTimeout(netdata.runAllServices, netdata.options.update_every * 100);
+ },
+
+ start: function() {
+ if(netdata.options.DEBUG === true) this.debug('started, services: ' + netdata.stringify(this.services));
+
+ if(this.services.length === 0) {
+ this.disableNodePlugin();
+
+ // eslint suggested way to exit
+ var exit = process.exit;
+ exit(1);
+ }
+ else this.runAllServices();
+ },
+
+ // disable the whole node.js plugin
+ disableNodePlugin: function() {
+ this.send('DISABLE');
+
+ // eslint suggested way to exit
+ var exit = process.exit;
+ exit(1);
+ },
+
+ requestFromParams: function(protocol, hostname, port, path, method) {
+ return {
+ protocol: protocol,
+ hostname: hostname,
+ port: port,
+ path: path,
+ //family: 4,
+ method: method,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Connection': 'keep-alive'
+ },
+ agent: new http.Agent({
+ keepAlive: true,
+ keepAliveMsecs: netdata.options.update_every * 1000,
+ maxSockets: 2, // it must be 2 to work
+ maxFreeSockets: 1
+ })
+ };
+ },
+
+ requestFromURL: function(a_url) {
+ var u = url.parse(a_url);
+ return netdata.requestFromParams(u.protocol, u.hostname, u.port, u.path, 'GET');
+ },
+
+ configure: function(module, config, callback) {
+ if(netdata.options.DEBUG === true) this.debug(module.name + ': configuring (update_every: ' + this.options.update_every + ')...');
+
+ module.active = 0;
+ module.update_every = this.options.update_every;
+
+ if(typeof config.update_every !== 'undefined')
+ module.update_every = config.update_every;
+
+ module.enable_autodetect = (config.enable_autodetect)?true:false;
+
+ if(typeof(callback) === 'function')
+ module.configure_callback = callback;
+ else
+ module.configure_callback = null;
+
+ var added = module.configure(config);
+
+ if(netdata.options.DEBUG === true) this.debug(module.name + ': configured, reporting ' + added + ' eligible services.');
+
+ if(module.configure_callback !== null && added === 0) {
+ if(netdata.options.DEBUG === true) this.debug(module.name + ': configuration finish callback called from configure().');
+ var configure_callback = module.configure_callback;
+ module.configure_callback = null;
+ configure_callback();
+ }
+
+ return added;
+ }
};
-if(netdata.options.DEBUG === true) netdata.debug('loaded netdata from: ' + __filename);
+if(netdata.options.DEBUG === true) netdata.debug('loaded netdata from:', __filename);
module.exports = netdata;
diff --git a/node.d/sma_webbox.node.js b/node.d/sma_webbox.node.js
index 3dd17a5c1..3d99943d4 100644
--- a/node.d/sma_webbox.node.js
+++ b/node.d/sma_webbox.node.js
@@ -3,7 +3,7 @@
// This program will connect to one or more SMA Sunny Webboxes
// to get the Solar Power Generated (current, today, total).
-// example configuration in /etc/netdata/sma_webbox.conf
+// example configuration in /etc/netdata/node.d/sma_webbox.conf
/*
{
"enable_autodetect": false,
diff --git a/node.d/snmp.node.js b/node.d/snmp.node.js
index ddc898527..5a478937e 100644
--- a/node.d/snmp.node.js
+++ b/node.d/snmp.node.js
@@ -2,7 +2,7 @@
// This program will connect to one or more SNMP Agents
-// example configuration in /etc/netdata/snmp.conf
+// example configuration in /etc/netdata/node.d/snmp.conf
/*
{
"enable_autodetect": false,
@@ -109,7 +109,7 @@ var net_snmp = require('net-snmp');
var extend = require('extend');
var netdata = require('netdata');
-if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
+if(netdata.options.DEBUG === true) netdata.debug('loaded', __filename, ' plugin');
netdata.processors.snmp = {
name: 'snmp',
@@ -125,62 +125,72 @@ netdata.processors.snmp = {
},
prepare: function(service) {
+ var __DEBUG = netdata.options.DEBUG;
+
if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
// this is the first time we see this service
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
// build an index of all OIDs
service.snmp_oids_index = {};
- for(var c in service.request.charts) {
+ var chart_keys = Object.keys(service.request.charts);
+ var chart_keys_len = chart_keys.length;
+ while(chart_keys_len--) {
+ var c = chart_keys[chart_keys_len];
+ var chart = service.request.charts[c];
+
// for each chart
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
- if(typeof service.request.charts[c].titleoid !== 'undefined') {
- service.snmp_oids_index[this.fixoid(service.request.charts[c].titleoid)] = {
+ if(typeof chart.titleoid !== 'undefined') {
+ service.snmp_oids_index[this.fixoid(chart.titleoid)] = {
type: 'title',
- link: service.request.charts[c]
+ link: chart
};
}
- for(var d in service.request.charts[c].dimensions) {
+ var dim_keys = Object.keys(chart.dimensions);
+ var dim_keys_len = dim_keys.length;
+ while(dim_keys_len--) {
+ var d = dim_keys[dim_keys_len];
+ var dim = chart.dimensions[d];
+
// for each dimension in the chart
- var oid = this.fixoid(service.request.charts[c].dimensions[d].oid);
- var oidname = this.fixoid(service.request.charts[c].dimensions[d].oidname);
+ var oid = this.fixoid(dim.oid);
+ var oidname = this.fixoid(dim.oidname);
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname);
// link it to the point we need to set the value to
service.snmp_oids_index[oid] = {
type: 'value',
- link: service.request.charts[c].dimensions[d]
+ link: dim
};
if(typeof oidname !== 'undefined')
service.snmp_oids_index[oidname] = {
type: 'name',
- link: service.request.charts[c].dimensions[d]
+ link: dim
};
// and set the value to null
- service.request.charts[c].dimensions[d].value = null;
+ dim.value = null;
}
}
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
// now create the array of OIDs needed by net-snmp
- service.snmp_oids = new Array();
- for(var o in service.snmp_oids_index)
- service.snmp_oids.push(o);
+ service.snmp_oids = Object.keys(service.snmp_oids_index);
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
service.snmp_oids_cleaned = 0;
@@ -189,14 +199,19 @@ netdata.processors.snmp = {
service.snmp_oids_cleaned = 1;
// the second time, keep only values
+
service.snmp_oids = new Array();
- for(var o in service.snmp_oids_index)
- if(service.snmp_oids_index[o].type === 'value')
- service.snmp_oids.push(o);
+ var oid_keys = Object.keys(service.snmp_oids_index);
+ var oid_keys_len = oid_keys.length;
+ while(oid_keys_len--) {
+ if (service.snmp_oids_index[oid_keys[oid_keys_len]].type === 'value')
+ service.snmp_oids.push(oid_keys[oid_keys_len]);
+ }
}
},
getdata: function(service, index, ok, failed, callback) {
+ var __DEBUG = netdata.options.DEBUG;
var that = this;
if(index >= service.snmp_oids.length) {
@@ -218,7 +233,7 @@ netdata.processors.snmp = {
index += service.request.max_request_size;
}
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': making ' + slice.length + ' entries request, max is: ' + service.request.max_request_size);
service.snmp_session.get(slice, function(error, varbinds) {
@@ -231,14 +246,15 @@ netdata.processors.snmp = {
service.snmp_oids_index[slice[len]].value = null;
}
else {
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
- for(var i = 0; i < varbinds.length; i++) {
+ var varbinds_len = varbinds.length;
+ for(var i = 0; i < varbinds_len ; i++) {
var value = null;
if(net_snmp.isVarbindError(varbinds[i])) {
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
@@ -246,10 +262,14 @@ netdata.processors.snmp = {
failed++;
}
else {
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
- value = varbinds[i].value;
+ if(varbinds[i].type === net_snmp.ObjectType.OctetString)
+ value = parseFloat(varbinds[i].value) * 1000;
+ else
+ value = varbinds[i].value;
+
ok++;
}
@@ -262,7 +282,7 @@ netdata.processors.snmp = {
}
}
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
}
that.getdata(service, index, ok, failed, callback);
@@ -270,12 +290,14 @@ netdata.processors.snmp = {
},
process: function(service, callback) {
+ var __DEBUG = netdata.options.DEBUG;
+
this.prepare(service);
if(service.snmp_oids.length === 0) {
// no OIDs found for this service
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
service.error('no OIDs to process.');
callback(null);
@@ -286,13 +308,13 @@ netdata.processors.snmp = {
// no SNMP session has been created for this service
// the SNMP session is just the initialization of NET-SNMP
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
// create the SNMP session
service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
- if(netdata.options.DEBUG === true)
+ if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
// if we later need traps, this is how to do it:
@@ -319,19 +341,28 @@ var snmp = {
if(service.added !== true)
service.commit();
- for(var c in service.request.charts) {
- var chart = snmp.charts[c];
+ var chart_keys = Object.keys(service.request.charts);
+ var chart_keys_len = chart_keys.length;
+ for(var i = 0; i < chart_keys_len; i++) {
+ var c = chart_keys[i];
+ var chart = snmp.charts[c];
if(typeof chart === 'undefined') {
chart = service.chart(c, service.request.charts[c]);
snmp.charts[c] = chart;
}
service.begin(chart);
-
- for( var d in service.request.charts[c].dimensions )
- if(service.request.charts[c].dimensions[d].value !== null)
- service.set(d, service.request.charts[c].dimensions[d].value);
+
+ var dimensions = service.request.charts[c].dimensions;
+ var dim_keys = Object.keys(dimensions);
+ var dim_keys_len = dim_keys.length;
+ for(var j = 0; j < dim_keys_len ; j++) {
+ var d = dim_keys[j];
+
+ if (dimensions[d].value !== null)
+ service.set(d, dimensions[d].value);
+ }
service.end();
}
@@ -343,7 +374,9 @@ var snmp = {
// its purpose is to prepare the request and call
// netdata.serviceExecute()
serviceExecute: function(conf) {
- if(netdata.options.DEBUG === true)
+ var __DEBUG = netdata.options.DEBUG;
+
+ if(__DEBUG === true)
netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
var service = netdata.service({
@@ -355,30 +388,40 @@ var snmp = {
});
// multiply the charts, if required
- for(var c in service.request.charts) {
- if(netdata.options.DEBUG === true)
+ var chart_keys = Object.keys(service.request.charts);
+ var chart_keys_len = chart_keys.length;
+ for( var i = 0; i < chart_keys_len ; i++ ) {
+ var c = chart_keys[i];
+ var service_request_chart = service.request.charts[c];
+
+ if(__DEBUG === true)
netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
- if(typeof service.request.charts[c].update_every === 'undefined')
- service.request.charts[c].update_every = service.update_every;
+ if(typeof service_request_chart.update_every === 'undefined')
+ service_request_chart.update_every = service.update_every;
- if(typeof service.request.charts[c].multiply_range !== 'undefined') {
- var from = service.request.charts[c].multiply_range[0];
- var to = service.request.charts[c].multiply_range[1];
- var prio = service.request.charts[c].priority || 1;
+ if(typeof service_request_chart.multiply_range !== 'undefined') {
+ var from = service_request_chart.multiply_range[0];
+ var to = service_request_chart.multiply_range[1];
+ var prio = service_request_chart.priority || 1;
if(prio < snmp.base_priority) prio += snmp.base_priority;
while(from <= to) {
var id = c + from.toString();
- var chart = extend(true, {}, service.request.charts[c]);
+ var chart = extend(true, {}, service_request_chart);
chart.title += from.toString();
if(typeof chart.titleoid !== 'undefined')
chart.titleoid += from.toString();
chart.priority = prio++;
- for(var d in chart.dimensions) {
+
+ var dim_keys = Object.keys(chart.dimensions);
+ var dim_keys_len = dim_keys.length;
+ for(var j = 0; j < dim_keys_len ; j++) {
+ var d = dim_keys[j];
+
chart.dimensions[d].oid += from.toString();
if(typeof chart.dimensions[d].oidname !== 'undefined')
@@ -430,7 +473,7 @@ var snmp = {
service.module.processResponse(serv, data);
callback();
});
- },
+ }
};
module.exports = snmp;