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.
Download, Build & Run
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:
Walk Through
This project is based on Perfect Template. If you are not familiar with Perfect server, please try Perfect Template Start Project first.
API Routes
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"]
]System Information
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
}
}
}
Request / Response Handler
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()
}
}
index.html
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);Issues
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
Further Information
For more information on the Perfect project, please visit perfect.org.

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.


