public monitor

This commit is contained in:
jysperm
2014-07-30 18:14:31 +08:00
parent 833abdb8c1
commit 3ca0b48787
5 changed files with 281 additions and 8 deletions

View File

@@ -1,6 +1,12 @@
child_process = require 'child_process'
os = require 'os'
fs = require 'fs'
plugin = require '../plugin'
{renderAccount} = require './middleware'
monitor = require '../../plugin/linux/monitor'
module.exports = exports = express.Router()
exports.get '/services', renderAccount, (req, res) ->
@@ -13,3 +19,106 @@ exports.get '/services', renderAccount, (req, res) ->
res.render 'public/services',
plans: _.values(config.plans)
services: result
exports.get '/monitor', renderAccount, (req, res) ->
async.parallel
resources_usage: (callback) ->
monitor.monitoringStorage ->
resources_usage = []
for username, usage of monitor.resources_usage
resources_usage.push
username: username
cpu: usage.cpu
memory: usage.memory
storage: parseInt monitor.storage_usage[username]?.size_used ? 0
process: _.filter(monitor.last_plist, (i) -> i.user == username).length
callback null, resources_usage
system: (callback) ->
async.parallel
system: (callback) ->
fs.readFile '/etc/issue', (err, content) ->
callback err, content.toString().replace(/\\\w/g, '').trim()
, (err, result) ->
callback null, _.extend result,
hostname: os.hostname()
cpu: os.cpus()[0]['model']
uptime: os.uptime()
loadavg: _.map(os.loadavg(), (i) -> i.toFixed(2)).join(', ')
address: os.networkInterfaces()['eth0'][0].address
time: new Date()
storage: (callback) ->
child_process.exec "df -h", (err, stdout) ->
disks = {}
for line in stdout.split('\n')
[dev, size, used, available, used_per, mounted] = _.compact(line.split(' '))
disks[mounted] =
dev: dev
size: parseInt size?.match(/\d+/)
used: parseInt used?.match(/\d+/)
available: available
used_per: used_per
root_disk = disks['/']
used = root_disk.used
total = root_disk.size
free = total - used
used_per = (used / total * 100).toFixed()
free_per = 100 - used_per
callback null,
used: used
free: free
total: total
used_per: used_per
free_per: free_per
memory: (callback) ->
fs.readFile '/proc/meminfo', (err, content) ->
mapping = {}
for line in content.toString().split('\n')
[key, value] = line.split ':'
if value
mapping[key.trim()] = parseInt (parseInt(value.trim().match(/\d+/)) / 1024).toFixed()
used = mapping['MemTotal'] - mapping['MemFree'] - mapping['Buffers'] - mapping['Cached']
used_per = (used / mapping['MemTotal'] * 100).toFixed()
cached_per = (mapping['Cached'] / mapping['MemTotal'] * 100).toFixed()
buffers_per = (mapping['Buffers'] / mapping['MemTotal'] * 100).toFixed()
free_per = 100 - used_per - cached_per - buffers_per
swap_free_per = (mapping['SwapFree'] / mapping['SwapTotal'] * 100).toFixed()
swap_used_per = 100 - swap_free_per
callback null,
used: used
cached: mapping['Cached']
buffers: mapping['Buffers']
free: mapping['MemFree']
total: mapping['MemTotal']
swap_used: mapping['SwapTotal'] - mapping['SwapFree']
swap_free: mapping['SwapFree']
swap_total: mapping['SwapTotal']
used_per: used_per
cached_per: cached_per
buffers_per: buffers_per
free_per: free_per
swap_used_per: swap_used_per
swap_free_per: swap_free_per
, (err, result) ->
res.render 'public/monitor', _.extend result,
last_plist: monitor.last_plist
_: _

View File

@@ -0,0 +1,39 @@
.progress-bar {
text-align: center;
}
.multi-progress span {
position: inherit;
display: inherit;
width: 100%;
color: inherit;
}
body #content .row {
margin-bottom: 0px;
}
.process-list {
overflow-x: scroll;
}
.col-md-4 {
padding-left: 0;
}
.col-md-8 {
padding-right: 0;
}
.process-list td {
font-size: 14px;
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
white-space: nowrap;
}
.progress-bar.blank {
background-color: #f5f5f5;
color: black;
-webkit-box-shadow: none;
box-shadow: none;
}

View File

@@ -0,0 +1,124 @@
extends ../layout
prepend head
title 服务器状态 | #{t('app.name')}
append head
link(rel='stylesheet', href='/style/panel.css')
link(rel='stylesheet', href='/style/public/monitor.css')
block content
#content.container
.row
.col-md-4
.panel.panel-default
.panel-heading
h3.panel-title System
table.table
tbody
tr
td Hostname
td= system.hostname
tr
td System
td= system.system
tr
td CPU
td= system.cpu
tr
td Time
td= system.time
tr
td Uptime
td= system.uptime
tr
td Loadavg
td= system.loadavg
tr
td Address
td= system.address
.col-md-8
.panel.panel-default
.panel-heading
h3.panel-title Memory & Storage
.panel-body
p Memory
.progress.multi-progress
.progress-bar.progress-bar-danger(role='progressbar', style='width: #{memory.used_per}%;')
span(title= '#{memory.used}M') #{memory.used_per}%
.progress-bar.progress-bar-info(role='progressbar', style='width: #{memory.cached_per}%;')
span(title= '#{memory.cached}M') #{memory.cached_per}%
.progress-bar.progress-bar-success(role='progressbar', style='width: #{memory.buffers_per}%;')
span(title= '#{memory.buffers}M') #{memory.buffers_per}%
.progress-bar.blank(role='progressbar', style='width: #{memory.free_per}%;')
span(title= '#{memory.free}M') #{memory.free_per}%
p SAWP
.progress.multi-progress
.progress-bar.progress-bar-warning(role='progressbar', style='width: #{memory.swap_used_per}%;')
span(title= '#{memory.swap_used_per}M') #{memory.swap_used_per}%
.progress-bar.blank(role='progressbar', style='width: #{memory.swap_free_per}%;')
span(title= '#{memory.swap_free}M') #{memory.swap_free_per}%
p Storage
.progress.multi-progress
.progress-bar.progress-bar-warning(role='progressbar', style='width: #{storage.used_per}%;')
span(title= '#{storage.used}%M') #{storage.used_per}%
.progress-bar.blank(role='progressbar', style='width: #{memory.free_per}%;')
span(title= '#{memory.free}M') #{memory.free_per}%
.row
.panel.panel-default
.panel-heading
h3.panel-title Users
table.table.table-hover
thead
tr
th User
th Process
th CPU 1 Hour
th Memory 1 Hour
th Storage
tbody
for item in resources_usage
tr
td= item.username
td= item.process
td #{item.cpu}s
td #{item.memory.toFixed(1)}M
td #{(item.storage / 1024).toFixed(1)}M
.row
.panel.panel-default.process-list
.panel-heading
h3.panel-title Process
table.table.table-hover
thead
tr
th USER
th PID
th %CPU
th %MEM
th VSZ
th RSS
th TTY
th STAT
th START
th TIME
th COMMAND
tbody
for process in last_plist
tr
td= process.user
td= process.pid
td= process.cpu_per
td= process.mem_per
td= process.vsz
td= process.rss
td= process.tty
td= process.stat
td= process.start
td= process.time
td!= _.escape(process.command).replace(/ /g, ' ')
append footer
script(src='/script/panel.js')

View File

@@ -9,10 +9,11 @@ REDIS_KEY = 'rp:linux:resources_usage'
REDIS_OVERVIEW = 'rp:linux:overview'
ITEM_IN_RESOURCES_LIST = 3600 * 1000 / config.plugins.linux.monitor_cycle
last_plist = []
exports.last_plist = []
passwd_cache = {}
exports.resources_usage = {}
exports.storage_usage = {}
exports.run = ->
exports.monitoring()
@@ -77,7 +78,7 @@ exports.monitoring = ->
exports.loadPasswd ->
exports.getProcessList (plist) ->
plist = _.reject plist, (item) ->
return item.user == 'root'
return item.rss == 0
async.parallel
cpu: (callback) ->
@@ -129,7 +130,7 @@ exports.monitoring = ->
callback()
, ->
app.redis.set REDIS_KEY, JSON.stringify(resources_usage_list), ->
last_plist = plist
exports.last_plist = plist
exports.monitoringStorage = (callback) ->
app.redis.get 'rp:storage_usage', (err, result) ->
@@ -153,19 +154,19 @@ exports.monitoringStorage = (callback) ->
inode_used: inode_used
}
exports.resources_usage.storage = {}
exports.storage_usage = {}
for item in lines
exports.resources_usage.storage[item.username] = item
exports.storage_usage[item.username] = item
app.redis.setex 'rp:storage_usage', 3, JSON.stringify(exports.resources_usage.storage), ->
app.redis.setex 'rp:storage_usage', 3, JSON.stringify(exports.storage_usage), ->
callback()
exports.monitoringCpu = (plist, callback) ->
total_time = {}
findLastProcess = (process) ->
return _.find last_plist, (i) ->
return _.find exports.last_plist, (i) ->
return i.pid == process.pid and i.user == process.user and i.command == process.command
addTime = (account_name, time) ->

View File

@@ -27,7 +27,7 @@ module.exports =
}
storage_usage: do ->
usage = monitor.resources_usage['storage'][account.username]
usage = monitor.storage_usage[account.username]
now_per = (usage.size_used / 1000 / account.attribute.resources_limit.storage * 100).toFixed()
return {
now_per: now_per