Perfect System Monitor Demo 简体ä¸ć–‡
This project demonstrates how to use Perfect SysInfo library to monitor realtime performance of server.
Ensure you have installed and activated the latest Swift 3.1 tool chain.
Use the following commands in terminal to quick install & run this demo:
$ git clone https://github.com/PerfectExamples/SystemMonitor-Demo.git
$ cd SystemMonitor-Demo
$ swift build
$ ./.build/debug/SystemMonitor
If success, the terminal should display something like [INFO] Starting HTTP server localhost on 0.0.0.0:8888
.
Then you can check the server status by browsing http://localhost:8888
:
This project is based on Perfect Template. If you are not familiar with Perfect server, please try Perfect Template Start Project first.
This server contains two routes, /api
for server JSON query of real time polling. /**
is actually mapping to /index.html
as homepage.
"routes":[
["method":"get", "uri":"/api", "handler":handler],
["method":"get", "uri":"/**", "handler":PerfectHTTPServer.HTTPHandler.staticFiles,
"documentRoot":"./webroot"]
]
Considering that SysInfo
has a rich set of system information so it is necessary to pick up those info which is really needed.
The following code filters out a few basic metrics to monitor and translate into a JSON string. Please note the OS differences:
- CPU usage: average idle time, system time and user time, in percentage.
- Free memory
- Network I/O
- Disk I/O
extension SysInfo {
static var express: String? {
get {
#if os(Linux)
guard
let cpu = SysInfo.CPU["cpu"],
let mem = SysInfo.Memory["MemAvailable"],
let net = SysInfo.Net["enp0s3"],
let dsk = SysInfo.Disk["sda"],
let wr = dsk["writes_completed"],
let rd = dsk["reads_completed"]
else {
return nil
}
#else
guard
let cpu = SysInfo.CPU["cpu"],
let mem = SysInfo.Memory["free"],
let net = SysInfo.Net["en0"],
let dsk = SysInfo.Disk["disk0"],
let wr = dsk["bytes_written"],
let rd = dsk["bytes_read"]
else {
return nil
}
#endif
guard
let idl = cpu["idle"],
let user = cpu["user"],
let system = cpu["system"],
let nice = cpu["nice"],
let rcv = net["i"],
let snd = net["o"]
else {
return nil
}
let total = (idl + user + system + nice) / 100
let idle = idl / total
let usr = user / total
let sys = system / total
let MB = UInt64(1048576)
let report : [String: Int]
= ["idle": idle, "usr": usr, "sys": sys, "free": mem,
"rcv": rcv, "snd": snd,
"rd": Int(rd / MB), "wr": Int(wr / MB)]
do {
return try report.jsonEncodedString()
}catch {
return nil
}//end do
}
}
}
Once got the request, the server will immediately send back the JSON:
func handler(data: [String:Any]) throws -> RequestHandler {
return {
_ , res in
guard let report = SysInfo.express else {
res.status = .badGateway
res.completed()
return
}//end
res.setHeader(.contentType, value: "text/json")
.appendBody(string: report)
.completed()
}
}
The homepage is very simple: use promises
to download the data and render it by a certain chart framework, such as ChartJS
:
/// setup a chart
function setup(api) {
var ctx = document.getElementById(api).getContext("2d");
return new Chart(ctx, {
type: 'line',
data: { datasets: datagroups[api] },
options: {
scales: {
xAxes: [{
type: 'linear',
position: 'bottom'
}]
}
}
});
}//end setup
/// polling data from server api by promises, decode JSON and render in chart
function update(){
fetch('http://' + window.location.host + '/api',{method: 'get'})
.then( (resp) => { return resp.json() })
.then( (obj) => {
var chart = charts["cpu"];
var dset = chart.chart.config.data.datasets;
appendDataTo(dset, "CPU-idle", counter, obj.idle);
appendDataTo(dset, "CPU-user", counter, obj.usr);
appendDataTo(dset, "CPU-system", counter, obj.sys);
chart.update();
var chart = charts["mem"];
var dset = chart.chart.config.data.datasets;
appendDataTo(dset, "MEM-free", counter, obj.free);
chart.update();
var chart = charts["net"];
var dset = chart.chart.config.data.datasets;
appendDataTo(dset, "NET-recv", counter, obj.rcv);
appendDataTo(dset, "NET-snd", counter, obj.snd);
chart.update();
var chart = charts["ios"];
var dset = chart.chart.config.data.datasets;
appendDataTo(dset, "DISK-read", counter, obj.rd);
appendDataTo(dset, "DISK-write", counter, obj.wr);
chart.update();
counter += 1;
});
}//end function
/// repeatedly polling data every second
window.setInterval(update, 1000);
We are transitioning to using JIRA for all bugs and support related issues, therefore the GitHub issues has been disabled.
If you find a mistake, bug, or any other helpful suggestion you'd like to make on the docs please head over to http://jira.perfect.org:8080/servicedesk/customer/portal/1 and raise it.
A comprehensive list of open issues can be found at http://jira.perfect.org:8080/projects/ISS/issues
For more information on the Perfect project, please visit perfect.org.