/* Last changed: 2015-11-11 */ /* CUSTOMIZATION ============= result is a JSON encoded 2 dimensional indexed array: result = [ ['Name1', 'Value1'], ['Name2', 'Value2'], ['Name3', 'Value3'], ... ]; You can define any number of items. If there are new-line characters ("\n") in value, it will be displayed more rows in Android app. */ var port = 3000; var sys = require('sys'), http = require('http') os = require('os'), child_process = require('child_process'); var main = function () { var CONFIG = { // URL of Nginx status page Nginx: 'http://localhost:8080/nginx_status', // connection parameters for mysqladmin MySQL: '--port=3306 --socket=/var/run/mysqld/mysqld.sock --user=**** --password=****', // connection parameters for pg_connect //PostgreSQL: "postgres://user:password@localhost:5432/database" }; var d2 = function (number) { number = '00' + number; number = number.substring(number.length - 2); return number; }; var percent = function (value, sum, decimals) { decimals = decimals || 0; if (sum == 0) value = value > 0 ? 100 : 0; else value = value / sum * 100; return value.toFixed(decimals) + '%'; } var execute = function(command, parameters, trim) { parameters = parameters || ''; trim = trim || true; if (parameters != '') parameters = ' ' + parameters; var output = null; try { output = child_process.execSync(command + parameters, {stdio: ['pipe', 'pipe', 'ignore']}); } catch(e) { command = child_process.execSync("whereis -b " + command + " | awk '{print $2}'", {stdio: ['pipe', 'pipe', 'ignore']}).toString().trim(); if (command) { try { output = child_process.execSync(command + parameters, {stdio: ['pipe', 'pipe', 'ignore']}); } catch(e) {} } } if (output === null) return null; output = output.toString(); return trim ? output.trim() : output; } var lines2array = function (lines) { lines = lines.split('\n'); var array = []; for (var i = 0; i < lines.length; i++) { line = lines[i]; line = line.trim().split(/\s+/i, 2); if (line.length >= 2) array[line[0]] = line[1]; else array[line[0]] = null; } return array; } var result = []; // DateTime var data = new Date(); var tz = data.getTimezoneOffset(); result.push(['DateTime', data.getFullYear() + '-' + d2(data.getMonth()+1) + '-' + d2(data.getDate()) + ' ' + d2(data.getHours()) + ':' + d2(data.getMinutes()) + ':' + d2(data.getSeconds()) + (tz < 0 ? '+' : '-') + d2(Math.abs(tz / 60)) + ':' + d2(Math.abs(tz % 60))]); // UpTime var data = os.uptime(); result.push(['UpTime', Math.floor(data/60/60/24)+' days, ' + d2(Math.floor(data/60/60)%24) + ':' + d2(Math.floor(data/60)%60) + ':' + d2(data%60)]); // LoadAVG var data = os.loadavg(); result.push(['LoadAVG', data[0].toFixed(2) + ' ' + data[1].toFixed(2) + ' ' + data[2].toFixed(2) ]); // CPU temperature var data = execute('sensors', '--no-adapter'); if (data) { var cores = data.match(/(coretemp(?:.|[\r\n])*?)(?:(?:\r?\n){2,}|$)/gi); if (cores) { for (var i = 0; i < cores.length; i++) { var core = cores[i]; core = core.replace(/^(?:.|[\r\n])*?(Core(?:\s+\d+)?):\s+[+]?((?:.|[\r\n])*?)(?:\.\d+)?[\s°]+([cf])(?:.|[\r\n])*$/gi, '$1\t$2°$3'); core = core.split('\t', 2); result.push(["CPU "+ core[0], core[1]]); } } } // Disc var data = execute('df', '-h --local | grep "^/dev/"'); if (data) { data = data.split(/\r?\n+/); for (var i = 0; i < data.length; i++) { d = data[i].split(/\s+/); result.push(['Disc ' + i, d[5] + ' '+ d[2] + '/' + d[1] + ' '+ d[4]]); var temp = execute('hddtemp', "--wake-up " + d[0]); if (temp) { temp = temp.replace(/^(?:.|[\r\n])*?(\d+)[\s°]+(\w)$/gi, '$1°$2'); result.push(["Disc " + i + " temperature", temp]); } } } // Memory var data = execute('free', '-t -m | grep "^Mem"'); if (data) { data = data.split(/\s+/gi); data[2] -= data[6]; // without cache data = data[2] + "M/" + data[1] + "M " + percent(data[2], data[1]); result.push(['Memory', data]); } // Swap var data = execute('free', '-t -m | grep "^Swap"'); if (data) { data = data.split(/\s+/); result.push(['Swap', data[2] + 'M/' + data[1] + 'M ' + percent(data[2], data[1])]); } // Processes result.push(['Processes', execute('ps', 'aux --no-heading | wc -l')]); // Users var data = execute('who', "| cut -d' ' -f1 | uniq -c | awk '{print $2\" (\"$1\")\"}' | sort"); result.push(['Users', data ? data : '-']); // SMB users var data = execute('smbstatus', "-b | grep -E '^[0-9]+' | awk '{print $2}' | uniq -c | awk '{print $2\" (\"$1\")\"}' | sort"); result.push(['SMB users', data ? data : '-']); // Apache // YOU MUST ENABLE Apache mod_status MODULE var apacheSettings = execute('apache2ctl', "-V | grep -E 'HTTPD_ROOT|SERVER_CONFIG_FILE|APACHE_MPM_DIR'").replace(/^.*?(\w+)="([^"]*)".*$/gm, '$1 $2'); if (apacheSettings) { apacheSettings = lines2array(apacheSettings); var apacheModule = ''; if (apacheSettings['APACHE_MPM_DIR'].match(/prefork/)) apacheModule = 'prefork'; if (apacheSettings['APACHE_MPM_DIR'].match(/worker/)) apacheModule = 'worker'; if (apacheSettings['APACHE_MPM_DIR'].match(/event/)) apacheModule = 'event'; if (! apacheModule) apacheModule = execute('apache2ctl', "-t -D DUMP_MODULES | grep 'mpm_[^_]*_module'").replace(/^mpm_([^_]+)_module.*$/i, '$1'); apacheConfig = execute('grep', " -v '^#' "+apacheSettings['HTTPD_ROOT']+"/"+apacheSettings['SERVER_CONFIG_FILE']).replace(/#.*$/gmi, '$1'); var reg = new RegExp('^(?:.|[\r\n])*?(?:.|[\r\n])*$', 'gi'); var maxClients = parseInt(apacheConfig.replace(reg, '$1')); data = execute('apache2ctl', 'status | grep -E "([0-9]+)[^0-9]+([0-9]+) idle workers"'); if (data) { data = data.replace(/^.*?(\d+)[^\d]+(\d)+[^\d]+$/i, '$1/$2'); data = data.split('/'); data = data[0] + '/' + (maxClients) + ' ' + percent(data[0], maxClients); result.push(['Apache', data]); } delete apacheConfig; } if (CONFIG['Nginx']) { // Nginx // YOU MUST ENABLE nginx_status on localhost // location /nginx_status { // stub_status on; // access_log off; // allow 127.0.0.1; // deny all; // } var nginxConfig = execute('cat', "/etc/nginx/nginx.conf | grep -E '(worker_connections|worker_processes)'").replace(/#.*$/gmi, ''); var maxClients = parseInt(nginxConfig.replace(/^(?:.|[\r\n])*?worker_connections\s+(\d+)(?:.|[\r\n])*?$/gi, '$1')) * parseInt(nginxConfig.replace(/^(?:.|[\r\n])*?worker_processes\s+(\d+)(?:.|[\r\n])*?$/gi, '$1')); var nginxStatus = execute('wget', "-q -O - " + CONFIG['Nginx'] + " | grep 'Active connections'"); var activeClients = parseInt(nginxStatus.replace(/^(?:.|[\r\n])*?(\d+)(?:.|[\r\n])*?$/gi, '$1')); result.push(['Nginx', activeClients + "/" + maxClients + " " + percent(activeClients, maxClients)]); delete activeClients delete maxClients; delete nginxStatus; delete nginxConfig; } // MySQL var variables = execute('mysqladmin ', CONFIG['MySQL'] + " variables | grep 'max_connections' | grep '|' | sed 's/|/ /g' | awk '{print $1\" \"$2}'"); var status = execute('mysqladmin ', CONFIG['MySQL'] + " extended-status | grep 'Threads_connected' | grep '|' | sed 's/|/ /g' | awk '{print $1\" \"$2}'"); if (variables && status) { variables = lines2array(variables); status = lines2array(status); result.push(['MySQL', status['Threads_connected'] + '/' + variables['max_connections'] + ' ' + percent(status['Threads_connected'], variables['max_connections'])]); } delete variables; delete status; // PostgreSQL if (CONFIG['PostgreSQL']) { var pg = require('pg'); var client = new pg.Client(CONFIG['PostgreSQL']); client.connect(function(err) { if(err) { result.push(['PostgreSQL', err]); return; } client.query("SELECT (SELECT COUNT(*) from pg_stat_activity) AS f1, setting AS f2 FROM pg_settings WHERE name = 'max_connections'", function(err, res) { if(err) { result.push(['PostgreSQL', err]); return; } result.push(['PostgreSQL', res.rows[0].f1 + '/' + res.rows[0].f2 + ' ' + percent(res.rows[0].f1, res.rows[0].f2)]); client.end(); }); }); } return result; } if (true) { http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'application/json; charset=utf-8'}); response.end(JSON.stringify(main())); }).listen(port); console.log('Server running at http://127.0.0.1:'+port+'/'); } else { console.log(JSON.stringify(main())); }