diff --git a/ChangeLog b/ChangeLog index 27d31c4..eb75f79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,12 @@ +Version 1.6.0rc1 + - PR #10 : added Load plugin (Thanks to Paul Tzianos) - PR #11 : added Ping plugin (Thanks to Paul Tzianos) - PR #12 : added Disk plugin (Thanks to Paul Tzianos) - PR #15 : added Df plugin (Thanks to Paul Tzianos) - PR #13 (1) : removed duplicate modules from collectdCompat plugin (Thanks to Paul Tzianos) - PR #13 (2) : some modules of CollectdCompat plugin are now optional (Thanks to Paul Tzianos) +- PR #14 : Added crypto support (Thanks to Dimitris Rozakis) Version 1.5.1 diff --git a/config/default.json b/config/default.json index 8637460..56f5eac 100644 --- a/config/default.json +++ b/config/default.json @@ -10,6 +10,13 @@ "Interval": 60, +// Cryptography/Security settings + "Crypto": { + "SecurityLevel": 0, + "Username": "alice", + "Password": "12345678" + }, + // Time To Live : will stop Collectm after this value (86400sec = 1 day). // This is useful if you think there is a memory leak and want to reboot periodically // Collectm. Stop Collectm after 86400sec and Windows will restart the service. diff --git a/node_modules/collectdout/README.md b/node_modules/collectdout/README.md index 38a00a3..b454838 100755 --- a/node_modules/collectdout/README.md +++ b/node_modules/collectdout/README.md @@ -19,6 +19,18 @@ var client = new Collectd(60000, "collectd_server", 25826, "my_server"); ``` Fourth argument is optional, default is os.hostname() +To transmit data securely with username 'alice' and password '12345', you can +select authentication (HMAC) by setting the security level to 1. +```javascript +var client = new Collectd(60000, "collectd_server", 25826, "my_server", + 1, 'alice', '12345'); +``` +You can also encrypt the trasmitted data by setting the security level to 2. +```javascript +var client = new Collectd(60000, "collectd_server", 25826, "my_server", + 2, 'alice', '12345'); +``` + Create your plugin instance: ```javascript var plugin = client.plugin('myapp', 'worker13'); @@ -37,6 +49,10 @@ plugin.addCounter('uptime', '0', 1); ``` # Change log +- v0.0.8 + * Adding crypto support +- v0.0.7 + * Fix counter bug - v0.0.6 * Possibility to send notification - v0.0.5 diff --git a/node_modules/collectdout/lib/index.js b/node_modules/collectdout/lib/index.js index 867dbc1..21b9f2e 100755 --- a/node_modules/collectdout/lib/index.js +++ b/node_modules/collectdout/lib/index.js @@ -1,6 +1,7 @@ var dgram = require('dgram'); var net = require('net'); var os = require('os'); +var crypto = require('crypto'); /** * Generic helper because all Collectd plugins and PluginInstance @@ -92,8 +93,8 @@ PluginInstance.prototype = { * * Syntax : * 1/ var client = Collectd(); - * 2/ var client = Collectd(int, string, int, string); - * 3/ var client = Collectd(int, object, ignored, string); + * 2/ var client = Collectd(int, string, int, string, int, string, string); + * 3/ var client = Collectd(int, object, ignored, string, int, string, string); * * All arguments are optional (like in syntax 1) * Syntax 1 @@ -103,16 +104,30 @@ PluginInstance.prototype = { * arg2 is the Collectd server name * arg3 is the Collectd server port * arg4 is the host name used in Collectd values + * arg5 is the security level (0: No security, 1: Sign, 2: Encrypt) + * optional, defaults to 0 (No security) + * arg6 is the username used for signing/encrypting + * required only if security level is 1 (Sign) or 2 (Encrypt) + * arg7 is the password used for signing/encrypting + * required only if security level is 1 (Sign) or 2 (Encrypt) * Syntax 3 * arg1 is the interval between 2 sending data to Collectd servers * arg2 is an array like this : [ ['host1', port], ['host2', port], ...] * arg3 is ignored. * arg4 is the host name used in Collectd values + * arg5 is the security level (0: No security, 1: Sign, 2: Encrypt) + * optional, defaults to 0 (No security) + * arg6 is the username used for signing/encrypting + * required only if security level is 1 (Sign) or 2 (Encrypt) + * arg7 is the password used for signing/encrypting + * required only if security level is 1 (Sign) or 2 (Encrypt) */ -function Collectd(interval, host, port, hostname) { +function Collectd(interval, host, port, hostname, securityLevel, username, password) { this.interval = interval || 10000; this.serverHosts = []; - + this.securityLevel = securityLevel; + this.username = username; + this.password = password; this.plugins = {}; this.hostname = typeof hostname !== 'undefined' ? hostname : os.hostname(); @@ -156,8 +171,12 @@ Collectd.prototype.plugin = function(name, instance) { */ Collectd.prototype.send = function() { var prevHostname, prevPlugin, prevInstance, prevType, prevTypeInstance, prevTime, prevInterval; - - var pkt = new Packet(this.write.bind(this)); + var pkt = new Packet({ + sendCb: this.write.bind(this), + securityLevel: this.securityLevel, + username: this.username, + password: this.password, + }); var hostname = this.hostname; var interval = this.interval; var time = Math.floor(new Date().getTime() / 1000); @@ -245,8 +264,9 @@ Collectd.prototype.NOTIF_OKAY=4; * Note : if notif.h is defined and its value is false, the default hostname will be sent */ Collectd.prototype.sendNotif = function(notif) { - - var pkt = new Packet(this.write.bind(this)); + var pkt = new Packet({ + sendCb: this.write.bind(this) + }); var hostname = this.hostname; var time = Math.floor(new Date().getTime() / 1000); @@ -279,20 +299,135 @@ Collectd.prototype.write = function(buf) { } }; - var MAX_PACKET_SIZE = 1024; -function Packet(sendCb) { - this.sendCb = sendCb; - this.buf = new Buffer(MAX_PACKET_SIZE); +var SECURITY_LEVEL = { + NONE: 0, + SIGN: 1, + ENCRYPT: 2, +}; +var SIGNATURE_OVERHEAD = 36; +var ENCRYPTION_OVERHEAD = 42; + +function Packet(args) { + + this.sendCb = args.sendCb; + this.username = args.username; + this.password = args.password; + this.securityLevel = args.securityLevel !== undefined ? args.securityLevel : 0; this.pos = 0; + + switch (this.securityLevel) { + case SECURITY_LEVEL.NONE: + this.overhead = 0; + break; + case SECURITY_LEVEL.SIGN: + this.overhead = SIGNATURE_OVERHEAD + this.username.length; + break; + case SECURITY_LEVEL.ENCRYPT: + this.overhead = ENCRYPTION_OVERHEAD + this.username.length; + break; + default: + throw 'Packet: Invalid Security Level'; + break; + } + + this.buf = new Buffer(MAX_PACKET_SIZE - this.overhead); } Packet.prototype = { + send: function() { - if (this.pos > 0) - this.sendCb(this.buf.slice(0, this.pos)); - this.pos = 0; + if (this.pos > 0) { + this.encapsulate(); + this.sendCb(this.buf); + } + this.pos = 0; + }, + + encapsulate: function () { + switch (this.securityLevel) { + case SECURITY_LEVEL.NONE: + break; + case SECURITY_LEVEL.SIGN: + this.sign(); + break; + case SECURITY_LEVEL.ENCRYPT: + this.encrypt(); + break; + default: + throw new Error('Invalid Security Level: ' + + this.securityLevel); + } + }, + + sign: function () { + + // Signed Packet format: + // [header][data] + // + // Header format: + // [packet_type][header_length][ mac ][ username ] + // [ 2 bytes ][ 2 bytes ][ 32 bytes ][ dynamic ] + + // original (unencapsulated) packet + var original = this.buf.slice(0, this.pos); + + // Calculate HMAC on concatenation of username and payload + var hmac_sha256 = crypto.createHmac('sha256', this.password); + hmac_sha256.write(this.username); + hmac_sha256.write(original); + var mac = hmac_sha256.digest(); + + // Create a new buffer for the signed packet + var buffer = new Buffer(this.overhead + original.length); + buffer.writeUInt16BE('0x0200', 0); + buffer.writeUInt16BE(this.overhead, 2); + mac.copy(buffer, 4); + buffer.write(this.username, 36); + original.copy(buffer, this.overhead); + this.buf = buffer; + }, + + encrypt: function () { + // Encrypted Packet format: + // [header][encr(data)] + // + // Header format: + // [packet_type][total_packet_length][username_length][username][ IV ][ encr(checksum) ] + // [ 2 bytes ][ 2 bytes ][ 2 bytes ][dynamic ][ 16 bytes ][ 20 bytes ] + + // original (unencapsulated) packet + var original = this.buf.slice(0, this.pos); + + // Calculate SHA1 checksum of original packet + var sha1 = crypto.createHash('sha1'); + sha1.write(original); + var checksum = sha1.digest(); + + // Create encryption key by hashing password + var sha256 = crypto.createHash('sha256'); + sha256.write(this.password); + var key = sha256.digest(); + + // Generate an initialization vector + var iv = crypto.randomBytes(16); + + // Encrypt concatenation of checksum and original + var aes256_ofb = crypto.createCipheriv('aes-256-ofb', key, iv); + aes256_ofb.write(checksum); + aes256_ofb.write(original); + var ciphertext = aes256_ofb.read() + + // Create a new buffer for the encrypted packet + var buffer = new Buffer(this.overhead + original.length); + buffer.writeUInt16BE('0x0210', 0); + buffer.writeUInt16BE(buffer.length, 2); + buffer.writeUInt16BE(this.username.length, 4); + buffer.write(this.username, 6); + iv.copy(buffer, 6 + this.username.length); + ciphertext.copy(buffer, 6 + this.username.length + 16); + this.buf = buffer; }, addStringPart: function(id, str) { @@ -370,27 +505,27 @@ Packet.prototype = { /* Tries to make it fit in 1024 bytes or starts a new packet */ catchOverflow: function(cb, resetCb) { - var tries = 2; - while(tries > 0) { - tries--; - - var oldPos = this.pos; - try { - /* On success return */ - return cb(); - } catch (e) { - if (e.constructor === PacketOverflow) { - /* Flush packet so far */ - this.pos = oldPos; - this.send(); - this.buf = new Buffer(MAX_PACKET_SIZE); - /* Clear state */ - resetCb(); - /* And retry... */ - } else - throw e; - } - } + var tries = 2; + while(tries > 0) { + tries--; + + var oldPos = this.pos; + try { + /* On success return */ + return cb(); + } catch (e) { + if (e.constructor === PacketOverflow) { + /* Flush packet so far */ + this.pos = oldPos; + this.send(); + this.buf = new Buffer(MAX_PACKET_SIZE - this.overhead); + /* Clear state */ + resetCb(); + /* And retry... */ + } else + throw e; + } + } } }; diff --git a/node_modules/collectdout/package.json b/node_modules/collectdout/package.json index 16d9c33..7d6b0ba 100755 --- a/node_modules/collectdout/package.json +++ b/node_modules/collectdout/package.json @@ -1,7 +1,7 @@ { "name": "collectdout", "description": "Periodically send values out to a Collectd server for statistics", - "version": "0.0.7", + "version": "0.0.8", "main": "./lib/index.js", "author": { "name": "Astro" @@ -25,20 +25,22 @@ "type": "MIT" } ], - "gitHead": "eb033e62b95cf754d985742cd9a3460a856399b9", - "_id": "collectdout@0.0.7", + "gitHead": "ff256ddbddfcfc9af0d7a4e4f008141370a2b1df", + "_id": "collectdout@0.0.8", "scripts": {}, - "_shasum": "84d31b4a9de71762d8efd3b7611881f4de3afafb", + "_shasum": "25e9ef3f04a65bcff9eb9fb524b4446482ae4d02", "_from": "collectdout@*", - "_npmVersion": "1.4.28", + "_npmVersion": "2.1.5", + "_nodeVersion": "0.10.25", "_npmUser": { "name": "feraudet", "email": "cyril@feraudet.com" }, "dist": { - "shasum": "84d31b4a9de71762d8efd3b7611881f4de3afafb", - "tarball": "http://registry.npmjs.org/collectdout/-/collectdout-0.0.7.tgz" + "shasum": "25e9ef3f04a65bcff9eb9fb524b4446482ae4d02", + "tarball": "http://registry.npmjs.org/collectdout/-/collectdout-0.0.8.tgz" }, "directories": {}, - "_resolved": "https://registry.npmjs.org/collectdout/-/collectdout-0.0.7.tgz" + "_resolved": "https://registry.npmjs.org/collectdout/-/collectdout-0.0.8.tgz", + "readme": "ERROR: No README data found!" } diff --git a/package.json b/package.json index 6c891d2..c5d598c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CollectM", - "version": "1.5.1modularization", + "version": "1.6.0rc1", "author": "Cyril Feraudet", "license": "GPLv2", "dependancies": { diff --git a/src/collectm.js b/src/collectm.js index aed5974..6ca975b 100755 --- a/src/collectm.js +++ b/src/collectm.js @@ -1,246 +1,275 @@ - -var process = require('process'); -process.env.ALLOW_CONFIG_MUTATIONS = 1; - - -var os = require('os'); -var Collectd = require('collectdout'); -var cfg = require('config'); -var collectmHTTPConfig = require('./httpconfig.js'); - -var collectmVersion = '<%= pkg.version %>'; - -var counters = []; -var client; -var path = require('path'); -var fs = require('fs'); -var cu = require('./collectm_utils.js'); -var prefix = path.join(path.dirname(require.main.filename), '..'); -var collectmHostname = 'unknown'; -var collectmTimeToLive = 0; -var logdeletiondays = 0; -var defaultInterval = 60000; - -// Initialize logger -try { - fs.mkdirSync(path.join(prefix, 'logs')); -} catch(e) { - if ( e.code != 'EEXIST' ) throw e; -} -var winston = require('winston'); -var logger = new (winston.Logger)({ - transports: [ - new (winston.transports.Console)(), - new (winston.transports.DailyRotateFile)({ - filename: path.join(prefix, 'logs', 'collectm.log'), - handleExceptions: true, - maxsize: 10000000, - maxFiles: 10, - prettyPrint: true, - json:false, - datePattern: '.yyyy-MM-dd', - exitOnError: false }) - ] -}); - -logger.info('Collectm version %s', collectmVersion); -logger.info('Collectm is starting'); - -var plugin = {}; -var pluginsCfg = []; - -// Initialize configuration directory in the same way that node-config does. -var configDir = cfg.util.initParam('NODE_CONFIG_DIR', path.join(prefix,'config')); -if (configDir.indexOf('.') === 0) { - configDir = path.join(process.cwd(), configDir); -} -logger.info('Using configuration files in '+configDir); -process.env.NODE_CONFIG_DIR=configDir; -cfg = cfg.util.extendDeep({}, cfg, cfg.util.loadFileConfigs()); - -var each = function(obj, block) { - var attr; - for(attr in obj) { - if(obj.hasOwnProperty(attr)) - block(attr, obj[attr]); - } -}; - -function get_hostname_with_case() { - var h = cfg.has('Hostname') ? cfg.get('Hostname') : os.hostname(); - var hcase = cfg.has('HostnameCase') ? cfg.get('HostnameCase') : 'default'; - switch(hcase) { - case 'upper': h = h.toUpperCase(); break; - case 'lower': h = h.toLowerCase(); break; - } - return(h); -} - -function get_collectd_servers_and_ports() { - var servers = cfg.has('Network.servers') ? cfg.get('Network.servers') : {}; - var res = []; - var h; - var p; - for (var i in servers) { - h = servers[i].hostname; - p = servers[i].port || 25826; - res.push( [ h, p ] ); - logger.log('info', 'Sending metrics to Collectd '+h+':'+p+'.'); - } - return(res); -} - -function get_interval() { - return(cfg.has('Interval') ? (cfg.get('Interval') * 1000) : 60000); -} - -function get_collectm_ttl() { - return(cfg.has('CollectmTimeToLive') ? (cfg.get('CollectmTimeToLive') * 1000) : 0); -} - -function get_log_deletion_days() { - return(cfg.has('LogDeletionDays') ? (cfg.get('LogDeletionDays') ) : 0); -} - -function remove_old_logs(days) { - var now = new Date(); - now = now.getTime(); - - fs.readdir(path.join(prefix, 'logs'), function(err, files) { - var filenames; - if(err) { - logger.log('error', 'Problem while reading log dir : '+err); - return; - } - filenames = files.map(function (f) { - return path.join(prefix,'logs',f); - }); - - each(filenames, function(i,f) { - if(/collectm\.log/.test(f)) { - fs.stat(f, function(err, stat) { - if(err) { - logger.log('error', 'Problem while reading log file '+f+' : '+err); - return; - } - if(stat.isFile()) { - if(now - stat.mtime.getTime() > (days * 86400 * 1000)) { - logger.log('info', 'Removing old log '+f); - fs.unlink(f, function(err) { - if(err) { - logger.log('error', 'Problem while removing log file '+f+' : '+err); - } - }); - } - } - }); - } - }); - - }); -} - -collectmHostname = get_hostname_with_case(); -logger.log('info', 'Sending metrics to Collectd with hostname '+collectmHostname+' (case sensitive).'); -defaultInterval = get_interval(); -client = new Collectd(defaultInterval, get_collectd_servers_and_ports(), 0, collectmHostname); -logger.log('info', 'Default interval is ' + defaultInterval + ' ms'); - -/* Load the plugins */ -pluginsCfg = cfg.has('Plugin') ? cfg.get('Plugin') : []; -plugin = {}; -each(pluginsCfg, function(p) { - var enabled; - plugin[p] = { 'enabled': 0 }; - try { - enabled = cfg.has('Plugin.'+p+'.enable') ? cfg.get('Plugin.'+p+'.enable') : 1; - if(enabled) { - plugin[p].plugin = require(path.join(prefix,'plugins', p+'.js')); - plugin[p].enabled = 1; - } - } catch(e) { - logger.error('Failed to load plugin '+p+' ('+e+')\n'); - plugin[p].enabled = 0; - } -}); - -/* Initialize the plugins */ -each(plugin, function(p) { - if(plugin[p].enabled) { - try { - plugin[p].plugin.reInit(); - logger.info('Plugin %s : reInit done', p); - } catch(e) { - logger.error('Failed to reInit plugin '+p+' ('+e+')\n'); - } - } -}); - -/* Configure the plugins */ -each(plugin, function(p) { - if(plugin[p].enabled) { - try { - rc = plugin[p].plugin.reloadConfig({ - config: cfg.get('Plugin.'+p), - client: client, - counters: counters, - logger: logger - }); - if(rc) { - logger.info('Plugin %s : reloadConfig failed. Disabling plugin.', p); - plugin[p].enabled = 0; - - } else { - logger.info('Plugin %s : reloadConfig done', p); - } - } catch(e) { - logger.error('Failed to reloadConfig plugin '+p+' ('+e+')\n'); - plugin[p].enabled = 0; - } - } -}); - -/* Start the plugins */ -each(plugin, function(p) { - if(plugin[p].enabled) { - try { - plugin[p].plugin.monitor(); - logger.info('Plugin %s : monitoring enabled', p); - } catch(e) { - logger.error('Failed to start plugin '+p+' monitor ('+e+')\n'); - } - } -}); - -/* Load the httpconfig User Interface */ -if(cfg.get('HttpConfig.enable')) { - collectmHTTPConfig.init({ - cfg: cfg, - path: prefix, - configDir: configDir, - collectmVersion: collectmVersion, - plugins: plugin, - }); - collectmHTTPConfig.start(); - logger.info('Enabled httpconfig server'); -} - -/* Set Time To Live for this process (prevent memory leak impact) */ -collectmTimeToLive = get_collectm_ttl(); -if(collectmTimeToLive > 60) { - logger.info('TTL configured : will gracefully stop after '+parseInt(collectmTimeToLive/1000)+' seconds'); - setTimeout(function() { - logger.error('Gracefully stopped after configured TTL'); - process.exit(); - }, collectmTimeToLive); -} - -/* Remove old logs */ -logdeletiondays = get_log_deletion_days(); -if(logdeletiondays > 0) { - logger.info('Log files will be deleted after '+parseInt(logdeletiondays)+' days'); - remove_old_logs(logdeletiondays); - setInterval(function() { remove_old_logs(logdeletiondays); }, 86400 * 1000); -} - -// vim: set filetype=javascript fdm=marker sw=4 ts=4 et: + +var process = require('process'); +process.env.ALLOW_CONFIG_MUTATIONS = 1; + + +var os = require('os'); +var Collectd = require('collectdout'); +var cfg = require('config'); +var collectmHTTPConfig = require('./httpconfig.js'); + +var collectmVersion = '<%= pkg.version %>'; + +var counters = []; +var client; +var path = require('path'); +var fs = require('fs'); +var cu = require('./collectm_utils.js'); +var prefix = path.join(path.dirname(require.main.filename), '..'); +var collectmHostname = 'unknown'; +var collectmTimeToLive = 0; +var logdeletiondays = 0; +var defaultInterval = 60000; + +// Initialize logger +try { + fs.mkdirSync(path.join(prefix, 'logs')); +} catch(e) { + if ( e.code != 'EEXIST' ) throw e; +} +var winston = require('winston'); +var logger = new (winston.Logger)({ + transports: [ + new (winston.transports.Console)(), + new (winston.transports.DailyRotateFile)({ + filename: path.join(prefix, 'logs', 'collectm.log'), + handleExceptions: true, + maxsize: 10000000, + maxFiles: 10, + prettyPrint: true, + json:false, + datePattern: '.yyyy-MM-dd', + exitOnError: false }) + ] +}); + +logger.info('Collectm version %s', collectmVersion); +logger.info('Collectm is starting'); + +var plugin = {}; +var pluginsCfg = []; + +// Initialize configuration directory in the same way that node-config does. +var configDir = cfg.util.initParam('NODE_CONFIG_DIR', path.join(prefix,'config')); +if (configDir.indexOf('.') === 0) { + configDir = path.join(process.cwd(), configDir); +} +logger.info('Using configuration files in '+configDir); +process.env.NODE_CONFIG_DIR=configDir; +cfg = cfg.util.extendDeep({}, cfg, cfg.util.loadFileConfigs()); + +var each = function(obj, block) { + var attr; + for(attr in obj) { + if(obj.hasOwnProperty(attr)) + block(attr, obj[attr]); + } +}; + +function get_hostname_with_case() { + var h = cfg.has('Hostname') ? cfg.get('Hostname') : os.hostname(); + var hcase = cfg.has('HostnameCase') ? cfg.get('HostnameCase') : 'default'; + switch(hcase) { + case 'upper': h = h.toUpperCase(); break; + case 'lower': h = h.toLowerCase(); break; + } + return(h); +} + +function get_collectd_servers_and_ports() { + var servers = cfg.has('Network.servers') ? cfg.get('Network.servers') : {}; + var res = []; + var h; + var p; + for (var i in servers) { + h = servers[i].hostname; + p = servers[i].port || 25826; + res.push( [ h, p ] ); + logger.log('info', 'Sending metrics to Collectd '+h+':'+p+'.'); + } + return(res); +} + +function get_interval() { + return(cfg.has('Interval') ? (cfg.get('Interval') * 1000) : 60000); +} + +function get_security_level() { + var securityLevel = 0; + if (cfg.has('Crypto') && cfg.get('Crypto').SecurityLevel !== undefined) { + securityLevel = cfg.get('Crypto').SecurityLevel; + if (securityLevel !== 0 && securityLevel !== 1 && securityLevel !== 2) { + throw new Error('Security level must be in (0, 1, 2).'); + } + } + if ((get_username() === '' || get_password() === '') && securityLevel > 0) { + throw new Error('Security level set greater to 0 but username or password left empty.'); + } + return securityLevel; +} + +function get_username() { + if (cfg.has('Crypto') && cfg.get('Crypto').Username !== undefined) { + return cfg.get('Crypto').Username; + } + return ''; +} + +function get_password() { + if (cfg.has('Crypto') && cfg.get('Crypto').Password !== undefined) { + return cfg.get('Crypto').Password; + } + return ''; +} + +function get_collectm_ttl() { + return(cfg.has('CollectmTimeToLive') ? (cfg.get('CollectmTimeToLive') * 1000) : 0); +} + +function get_log_deletion_days() { + return(cfg.has('LogDeletionDays') ? (cfg.get('LogDeletionDays') ) : 0); +} + +function remove_old_logs(days) { + var now = new Date(); + now = now.getTime(); + + fs.readdir(path.join(prefix, 'logs'), function(err, files) { + var filenames; + if(err) { + logger.log('error', 'Problem while reading log dir : '+err); + return; + } + filenames = files.map(function (f) { + return path.join(prefix,'logs',f); + }); + + each(filenames, function(i,f) { + if(/collectm\.log/.test(f)) { + fs.stat(f, function(err, stat) { + if(err) { + logger.log('error', 'Problem while reading log file '+f+' : '+err); + return; + } + if(stat.isFile()) { + if(now - stat.mtime.getTime() > (days * 86400 * 1000)) { + logger.log('info', 'Removing old log '+f); + fs.unlink(f, function(err) { + if(err) { + logger.log('error', 'Problem while removing log file '+f+' : '+err); + } + }); + } + } + }); + } + }); + + }); +} + +collectmHostname = get_hostname_with_case(); +logger.log('info', 'Sending metrics to Collectd with hostname '+collectmHostname+' (case sensitive).'); +defaultInterval = get_interval(); +client = new Collectd(defaultInterval, get_collectd_servers_and_ports(), 0, collectmHostname, + get_security_level(), get_username(), get_password()); +logger.log('info', 'Default interval is ' + defaultInterval + ' ms'); + +/* Load the plugins */ +pluginsCfg = cfg.has('Plugin') ? cfg.get('Plugin') : []; +plugin = {}; +each(pluginsCfg, function(p) { + var enabled; + plugin[p] = { 'enabled': 0 }; + try { + enabled = cfg.has('Plugin.'+p+'.enable') ? cfg.get('Plugin.'+p+'.enable') : 1; + if(enabled) { + plugin[p].plugin = require(path.join(prefix,'plugins', p+'.js')); + plugin[p].enabled = 1; + } + } catch(e) { + logger.error('Failed to load plugin '+p+' ('+e+')\n'); + plugin[p].enabled = 0; + } +}); + +/* Initialize the plugins */ +each(plugin, function(p) { + if(plugin[p].enabled) { + try { + plugin[p].plugin.reInit(); + logger.info('Plugin %s : reInit done', p); + } catch(e) { + logger.error('Failed to reInit plugin '+p+' ('+e+')\n'); + } + } +}); + +/* Configure the plugins */ +each(plugin, function(p) { + if(plugin[p].enabled) { + try { + rc = plugin[p].plugin.reloadConfig({ + config: cfg.get('Plugin.'+p), + client: client, + counters: counters, + logger: logger + }); + if(rc) { + logger.info('Plugin %s : reloadConfig failed. Disabling plugin.', p); + plugin[p].enabled = 0; + + } else { + logger.info('Plugin %s : reloadConfig done', p); + } + } catch(e) { + logger.error('Failed to reloadConfig plugin '+p+' ('+e+')\n'); + plugin[p].enabled = 0; + } + } +}); + +/* Start the plugins */ +each(plugin, function(p) { + if(plugin[p].enabled) { + try { + plugin[p].plugin.monitor(); + logger.info('Plugin %s : monitoring enabled', p); + } catch(e) { + logger.error('Failed to start plugin '+p+' monitor ('+e+')\n'); + } + } +}); + +/* Load the httpconfig User Interface */ +if(cfg.get('HttpConfig.enable')) { + collectmHTTPConfig.init({ + cfg: cfg, + path: prefix, + configDir: configDir, + collectmVersion: collectmVersion, + plugins: plugin, + }); + collectmHTTPConfig.start(); + logger.info('Enabled httpconfig server'); +} + +/* Set Time To Live for this process (prevent memory leak impact) */ +collectmTimeToLive = get_collectm_ttl(); +if(collectmTimeToLive > 60) { + logger.info('TTL configured : will gracefully stop after '+parseInt(collectmTimeToLive/1000)+' seconds'); + setTimeout(function() { + logger.error('Gracefully stopped after configured TTL'); + process.exit(); + }, collectmTimeToLive); +} + +/* Remove old logs */ +logdeletiondays = get_log_deletion_days(); +if(logdeletiondays > 0) { + logger.info('Log files will be deleted after '+parseInt(logdeletiondays)+' days'); + remove_old_logs(logdeletiondays); + setInterval(function() { remove_old_logs(logdeletiondays); }, 86400 * 1000); +} + +// vim: set filetype=javascript fdm=marker sw=4 ts=4 et: