diff --git a/LICENSE b/LICENSE deleted file mode 100755 index 02999e5..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 faceair & 精英王子 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index c163057..c1c30d6 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -NodeMonitor -=========== +# NodeMonitor 服务器上的状态监视器,支持查看: @@ -14,6 +13,31 @@ NodeMonitor * 用户进程状况 * 所有用户进程状况 -效果图: +## 效果图 - \ No newline at end of file + + + +## Licence + +The MIT License (MIT) + +Copyright (c) 2014 faceair + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/app.coffee b/app.coffee new file mode 100755 index 0000000..338f10c --- /dev/null +++ b/app.coffee @@ -0,0 +1,52 @@ +http = require 'http' +url = require 'url' +fs = require 'fs' +_ = require 'underscore' +monitor = require './monitor' + +global = this +global.sockets = [] + +sendData = -> + if global.sockets.length > 0 + monitor.osData (osData)-> + monitor.memData (memData)-> + monitor.psData (psData)-> + monitor.diskData (diskData)-> + Data = + "os": osData + "mem": memData + "ps": psData + "disk": diskData + _.each global.sockets, (socket)-> + socket.emit("data", Data) + +setInterval sendData, 5000 + +exports.runWebServer = -> + app = http.createServer (req, res) -> + reqfile = url.parse(req.url).pathname.slice(1).match(/[a-zA-Z0-9_ -.]+/) ? 'index.html' + fs.readFile './static/' + reqfile, (err, data) -> + if err + res.writeHead 500 + return res.end('Error loading ' + reqfile) + res.writeHead 200 + res.end data + app.listen 2957 + return app + +exports.runWebSocket = (app) -> + io = require('socket.io').listen app, + log: false + io.sockets.on 'connection', (socket) -> + global.sockets.push socket + socket.on 'disconnect', -> + sockets_new = [] + _.each global.sockets, (socket_new)-> + if socket_new.id != socket.id + sockets_new.push socket_new + global.sockets = sockets_new + +unless module.parent + app = exports.runWebServer() + exports.runWebSocket app \ No newline at end of file diff --git a/monitor.coffee b/monitor.coffee new file mode 100755 index 0000000..ae2ca71 --- /dev/null +++ b/monitor.coffee @@ -0,0 +1,109 @@ +child_process = require("child_process") +os = require("os") +monitor = {} + +monitor.osData = (cb) -> + osData = {} + mins = os.uptime() / 60 + hours = mins / 60 + days = Math.floor(hours / 24) + hours = Math.floor(hours - (days * 24)) + min = Math.floor(mins - (days * 60 * 24) - (hours * 60)) + uptimeStr = "" + uptimeStr = days + " days " if days + uptimeStr += hours + " hours " if hours + uptimeStr += min + " mins" + Today = new Date() + loadavg = os.loadavg() + loadavg_str = "" + for name, i in loadavg + loadavg_str += loadavg[i].toFixed(2) + " " + osData["os"] = + hostname: os.hostname() + type: os.type() + release: os.release() + cpus: os.cpus()[0]["model"] + servertime: Today.getFullYear() + "-" + (Today.getMonth() + 1) + "-" + Today.getDate() + " " + Today.getHours() + ":" + Today.getMinutes() + ":" + Today.getSeconds() + uptime: uptimeStr + loadavg: loadavg_str + cb osData["os"] + +monitor.memData = (cb) -> + memData = {} + child_process.exec "free -m", {}, (error, stdout) -> + rePattern = /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+.+cache:\s+(\d+)\s+(\d+)\s+Swap:\s+(\d+)\s+(\d+)\s+(\d+)/ + memInfo = rePattern.exec(stdout) + realMemUsed = memInfo[2] - memInfo[4] - memInfo[5] - memInfo[6] + buffersMemPer = Math.round(memInfo[5] / memInfo[1] * 100) + realMemPer = Math.round(realMemUsed / memInfo[1] * 100) + cachedMemPer = Math.round(memInfo[6] / memInfo[1] * 100) + memData["mem"] = + totalMem: memInfo[1] + "M" + realMem: memInfo[2] + "M" + cachedMem: memInfo[6] + "M" + realMemPer: realMemPer + cachedMemPer: cachedMemPer + buffersMemPer + freeMemPer: (100 - realMemPer - cachedMemPer - buffersMemPer) + swaptotalMem: memInfo[9] + "M" + swapUsedMemPer: Math.round(memInfo[10] / memInfo[9] * 100) + swapFreeMemPer: Math.round((memInfo[9] - memInfo[10]) / memInfo[9] * 100) + swapUsedMem: memInfo[10] + "M" + cb memData["mem"] + +monitor.psData = (cb) -> + psData = {} + child_process.exec "ps xufwa", {}, (error, stdout) -> + psData['ps'] = + user: {} + all: {} + + psArray = stdout.split("\n") + i = 1 + while i < (psArray.length - 1) + vpsArrayInfo = psArray[i] + psArray[i] = psArray[i].replace(" ", " ") while psArray[i].match(" ") + procArray = psArray[i].split(" ") + allprocArray = [] + j = 0 + while j < procArray.length + if j < 10 + allprocArray[j] = procArray[j] + else + allprocArray[10] = vpsArrayInfo.substr(64) + allprocArray[10] = allprocArray[10].replace(" ", " ") while allprocArray[10].match(" ") + j++ + psData['ps']["all"][i - 1] = allprocArray + if typeof psData['ps']["user"][procArray[0]] is "undefined" + psData['ps']["user"][procArray[0]] = + cpuPer: 0 + memPer: 0 + swapMem: 0 + realMem: 0 + procNum: 0 + numbers = [ + "cpuPer" + "memPer" + "swapMem" + "realMem" + ] + numbers.forEach (item, index) -> + psData['ps']["user"][procArray[0]][item] += Number(procArray[index + 2]) + psData['ps']["user"][procArray[0]]["procNum"] += 1 + i++ + cb psData['ps'] + +monitor.diskData = (cb) -> + diskData = {} + child_process.exec "df", {}, (error, stdout) -> + dkArray = stdout.split("\n") + dkArray[1] = dkArray[1].replace(" ", " ") while dkArray[1].match(" ") + dkArrayInfo = dkArray[1].split(" ") + + diskData["disk"] = + diskUsedPer: Math.round(Number(dkArrayInfo[2]) / Number(dkArrayInfo[1]) * 100) + diskFreePer: 100 - Math.round(Number(dkArrayInfo[2]) / Number(dkArrayInfo[1]) * 100) + diskAll: Math.round(Number(dkArrayInfo[1]) / 1048576) + "G" + diskUsed: Math.round(Number(dkArrayInfo[2]) / 1048576) + "G" + cb diskData["disk"] + +module.exports = monitor \ No newline at end of file diff --git a/monitor/Monitor.coffee b/monitor/Monitor.coffee deleted file mode 100755 index f9b9910..0000000 --- a/monitor/Monitor.coffee +++ /dev/null @@ -1,113 +0,0 @@ -class Monitor - child_process = require("child_process") - os = require("os") - - this.osData = (socket) -> - osData = {} - mins = os.uptime() / 60 - hours = mins / 60 - days = Math.floor(hours / 24) - hours = Math.floor(hours - (days * 24)) - min = Math.floor(mins - (days * 60 * 24) - (hours * 60)) - uptimeStr = "" - uptimeStr = days + " days " if days - uptimeStr += hours + " hours " if hours - uptimeStr += min + " mins" - Today = new Date() - loadavg = os.loadavg() - loadavg_str = "" - for name, i in loadavg - loadavg_str += loadavg[i].toFixed(2) + " " - osData["os"] = - hostname: os.hostname() - type: os.type() - release: os.release() - cpus: os.cpus()[0]["model"] - servertime: Today.getFullYear() + "-" + (Today.getMonth() + 1) + "-" + Today.getDate() + " " + Today.getHours() + ":" + Today.getMinutes() + ":" + Today.getSeconds() - uptime: uptimeStr - loadavg: loadavg_str - socket.emit("os",osData["os"]) - return - - this.memData = (socket) -> - memData = {} - child_process.exec "free -m", {}, (error, stdout, stderr) -> - rePattern = /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+.+cache:\s+(\d+)\s+(\d+)\s+Swap:\s+(\d+)\s+(\d+)\s+(\d+)/ - memInfo = rePattern.exec(stdout) - realMemUsed = memInfo[2] - memInfo[4] - memInfo[5] - memInfo[6] - buffersMemPer = Math.round(memInfo[5] / memInfo[1] * 100) - realMemPer = Math.round(realMemUsed / memInfo[1] * 100) - cachedMemPer = Math.round(memInfo[6] / memInfo[1] * 100) - memData["mem"] = - totalMem: memInfo[1] + "M" - realMem: memInfo[2] + "M" - realMemPer: realMemPer - cachedMemPer: cachedMemPer - cachedMem: memInfo[6] + "M" - freeMemPer: (100 - realMemPer - cachedMemPer - buffersMemPer) - swaptotalMem: memInfo[9] + "M" - swapUsedMemPer: Math.round(memInfo[10] / memInfo[9] * 100) - swapFreeMemPer: Math.round((memInfo[9] - memInfo[10]) / memInfo[9] * 100) - swapUsedMem: memInfo[10] + "M" - socket.emit("mem",memData["mem"]) - return - - this.psData = (socket) -> - psData = {} - child_process.exec "ps xufwa", {}, (error, stdout, stderr) -> - psData['ps'] = - user: {} - all: {} - - psArray = stdout.split("\n") - i = 1 - while i < (psArray.length - 1) - vpsArrayInfo = psArray[i] - psArray[i] = psArray[i].replace(" ", " ") while psArray[i].match(" ") - procArray = psArray[i].split(" ") - allprocArray = [] - j = 0 - while j < procArray.length - if j < 10 - allprocArray[j] = procArray[j] - else - allprocArray[10] = vpsArrayInfo.substr(64) - allprocArray[10] = allprocArray[10].replace(" ", " ") while allprocArray[10].match(" ") - j++ - psData['ps']["all"][i - 1] = allprocArray - if typeof psData['ps']["user"][procArray[0]] is "undefined" - psData['ps']["user"][procArray[0]] = - cpuPer: 0 - memPer: 0 - swapMem: 0 - realMem: 0 - procNum: 0 - numbers = [ - "cpuPer" - "memPer" - "swapMem" - "realMem" - ] - numbers.forEach (item, index, array) -> - psData['ps']["user"][procArray[0]][item] += Number(procArray[index + 2]) - psData['ps']["user"][procArray[0]]["procNum"] += 1 - i++ - socket.emit("ps",psData['ps']) - return - - this.diskData = (socket) -> - diskData = {} - child_process.exec "df", {}, (error, stdout, stderr) -> - dkArray = stdout.split("\n") - dkArray[1] = dkArray[1].replace(" ", " ") while dkArray[1].match(" ") - dkArrayInfo = dkArray[1].split(" ") - - diskData["disk"] = - diskUsedPer: Math.round(Number(dkArrayInfo[2]) / Number(dkArrayInfo[1]) * 100) - diskFreePer: 100 - Math.round(Number(dkArrayInfo[2]) / Number(dkArrayInfo[1]) * 100) - diskAll: Math.round(Number(dkArrayInfo[1]) / 1048576) + "G" - diskUsed: Math.round(Number(dkArrayInfo[2]) / 1048576) + "G" - socket.emit("disk",diskData["disk"]) - return - -module.exports = Monitor \ No newline at end of file diff --git a/monitor/app.coffee b/monitor/app.coffee deleted file mode 100755 index 1c06064..0000000 --- a/monitor/app.coffee +++ /dev/null @@ -1,33 +0,0 @@ -http = require 'http' -url = require 'url' -fs = require 'fs' - -Monitor = require './Monitor' - -exports.runWebServer = -> - app = http.createServer (req, res) -> - reqfile = url.parse(req.url).pathname.slice(1).match(/[a-zA-Z0-9_ -.]+/) ? 'index.html' - fs.readFile '../static/' + reqfile, (err, data) -> - if err - res.writeHead 500 - return res.end('Error loading ' + reqfile) - res.writeHead 200 - res.end(data) - app.listen 2998 - return app - -exports.runWebSocket = (port) -> - io = require('socket.io').listen port - io.sockets.on 'connection', (socket) -> - sendData = -> - Monitor.osData socket - Monitor.memData socket - Monitor.diskData socket - Monitor.psData socket - sendData() - intervalId = setInterval(sendData, 5000) - socket.on 'disconnect', -> - clearTimeout intervalId -unless module.parent - app = exports.runWebServer() - exports.runWebSocket app \ No newline at end of file diff --git a/package.json b/package.json index 9f74228..5dbd063 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "NodeMonitor", - "version": "0.0.1", + "version": "0.0.2", "private": false, "scripts": { - "start": "node ./monitor/app.js" + "start": "coffee app.coffee" }, "dependencies": { - "socket.io": "~0.9" + "socket.io": "~0.9", + "underscore": "~1.6.0" } } \ No newline at end of file diff --git a/static/change.coffee b/static/change.coffee index 5399380..d376e1e 100644 --- a/static/change.coffee +++ b/static/change.coffee @@ -1,43 +1,40 @@ -socket = io.connect("http://lochost/") -socket.on "os", (data) -> - $('#hostname').html(data.hostname) - $('#system').html(data.type + " " + data.release) - $('#cpus').html(data.cpus) - $('#servertime').html(data.servertime) - $('#uptime').html(data.uptime) - $('#loadavg').html(data.loadavg) +socket = io.connect("http://xuxian.jimu.in:2957/") +socket.on "data", (data) -> + $('#hostname').html(data.os.hostname) + $('#system').html(data.os.type + " " + data.os.release) + $('#cpus').html('' + data.os.cpus + '') + $('#servertime').html(data.os.servertime) + $('#uptime').html(data.os.uptime) + $('#loadavg').html(data.os.loadavg) -socket.on "mem", (data) -> - $('#totalMem').html(data.totalMem) - $('#realMem').html(data.realMem) - $('#cachedMem').html(data.cachedMem) - $('#realMemPer').attr("style","width: " + data.realMemPer + "%;") - $('#realMemPer').text("real " + data.realMemPer + " %") - $('#cachedMemPer').attr("style","width: " + data.cachedMemPer + "%;") - $('#cachedMemPer').text("cached " + data.cachedMemPer + " %") - $('#freeMemPer').attr("style","width: " + data.freeMemPer + "%;") - $('#freeMemPer').text("free " + data.freeMemPer + " %") - $('#swaptotalMem').html(data.swaptotalMem) - $('#swapUsedMem').html(data.swapUsedMem) - $('#swapUsedMemPer').attr("style","width: " + data.swapUsedMemPer + "%;") - $('#swapUsedMemPer').text("swapUsed " + data.swapUsedMemPer + " %") - $('#swapFreeMem').html(data.swapFreeMem) - $('#swapFreeMemPer').attr("style","width: " + data.swapFreeMemPer + "%;") - $('#swapFreeMemPer').text("swapFree " + data.swapFreeMemPer + " %") + $('#totalMem').html(data.mem.totalMem) + $('#realMem').html(data.mem.realMem) + $('#cachedMem').html(data.mem.cachedMem) + $('#realMemPer').attr("style","width: " + data.mem.realMemPer + "%;") + $('#realMemPer').text("real " + data.mem.realMemPer + " %") + $('#cachedMemPer').attr("style","width: " + data.mem.cachedMemPer + "%;") + $('#cachedMemPer').text("cached " + data.mem.cachedMemPer + " %") + $('#freeMemPer').attr("style","width: " + data.mem.freeMemPer + "%;") + $('#freeMemPer').text("free " + data.mem.freeMemPer + " %") + $('#swaptotalMem').html(data.mem.swaptotalMem) + $('#swapUsedMem').html(data.mem.swapUsedMem) + $('#swapUsedMemPer').attr("style","width: " + data.mem.swapUsedMemPer + "%;") + $('#swapUsedMemPer').text("swapUsed " + data.mem.swapUsedMemPer + " %") + $('#swapFreeMem').html(data.mem.swapFreeMem) + $('#swapFreeMemPer').attr("style","width: " + data.mem.swapFreeMemPer + "%;") + $('#swapFreeMemPer').text("swapFree " + data.mem.swapFreeMemPer + " %") -socket.on "disk", (data) -> - $('#diskAll').html(data.diskAll) - $('#diskUsed').html(data.diskUsed) - $('#diskUsedPer').attr("style","width: " + data.diskUsedPer + "%;") - $('#diskUsedPer').text("diskUsed " + data.diskUsedPer + " %") - $('#diskFreePer').attr("style","width: " + data.diskFreePer + "%;") - $('#diskFreePer').text("diskFree " + data.diskFreePer + " %") + $('#diskAll').html(data.disk.diskAll) + $('#diskUsed').html(data.disk.diskUsed) + $('#diskUsedPer').attr("style","width: " + data.disk.diskUsedPer + "%;") + $('#diskUsedPer').text("diskUsed " + data.disk.diskUsedPer + " %") + $('#diskFreePer').attr("style","width: " + data.disk.diskFreePer + "%;") + $('#diskFreePer').text("diskFree " + data.disk.diskFreePer + " %") -socket.on "ps", (data) -> psuser = psall = "" - for user of data["user"] - psuser += ("