mirror of
https://github.com/HackPlan/RootPanel.git
synced 2026-03-27 22:44:32 +08:00
public monitor
This commit is contained in:
@@ -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
|
||||
_: _
|
||||
|
||||
39
core/static/style/public/monitor.less
Normal file
39
core/static/style/public/monitor.less
Normal 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;
|
||||
}
|
||||
124
core/view/public/monitor.jade
Normal file
124
core/view/public/monitor.jade
Normal 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')
|
||||
@@ -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) ->
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user