jqで遊んでいたら、なんとなく思いついたので投稿。
用意するもの
CentOS release 6.7
- jq
- topコマンド
top + jq
topのバッチモードとjqで、topの出力をjson形式に変更。
$ top -b -n 1 | head -10 | tee top.txt
top - 01:58:31 up 2:47, 4 users, load average: 0.00, 0.02, 0.00
Tasks: 99 total, 1 running, 98 sleeping, 0 stopped, 0 zombie
Cpu(s): 2.0%us, 0.9%sy, 0.0%ni, 96.4%id, 0.5%wa, 0.3%hi, 0.0%si, 0.0%st
Mem: 502040k total, 379992k used, 122048k free, 44600k buffers
Swap: 1015804k total, 0k used, 1015804k free, 258188k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19232 1376 1100 S 0.0 0.3 0:00.41 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
# jqでjsonに変換
# メモリの使用率が多いやつ上位10件を取得
$ cat top.txt | jq -rcsR '[ gsub("\n$";"") | splits("\n") | sub(" +$";"") | sub("^ +";"")] | .[0:5] as $titles | .[6:] as $data | {"sys": [$titles | .[] | split(",") | [.[] | sub("^ +";"")]]} as $sys | [$data[0] | splits(" +") | sub("%";"") | sub("\\+";"")] as $row_keys | $data[1:] | [.[] | [splits(" +")]] | {"task":[.[] | [. as $r | range($row_keys|length) | {"key": $row_keys[.], "value": $r[.]}] | from_entries] | sort_by(.MEM) | reverse | .[:10]} as $task | $sys * $task'
{"sys":[["top - 01:58:31 up 2:47","4 users","load average: 0.00","0.02","0.00"],["Tasks: 99 total","1 running","98 sleeping","0 stopped","0 zombie"],["Cpu(s): 2.0%us","0.9%sy","0.0%ni","96.4%id","0.5%wa","0.3%hi","0.0%si","0.0%st"],["Mem: 502040k total","379992k used","122048k free","44600k buffers"],["Swap: 1015804k total","0k used","1015804k free","258188k cached"]],"task":[{"PID":"1","USER":"root","PR":"20","NI":"0","VIRT":"19232","RES":"1376","SHR":"1100","S":"S","CPU":"0.0","MEM":"0.3","TIME":"0:00.41","COMMAND":"init"},{"PID":"3","USER":"root","PR":"RT","NI":"0","VIRT":"0","RES":"0","SHR":"0","S":"S","CPU":"0.0","MEM":"0.0","TIME":"0:00.00","COMMAND":"migration/0"},{"PID":"2","USER":"root","PR":"20","NI":"0","VIRT":"0","RES":"0","SHR":"0","S":"S","CPU":"0.0","MEM":"0.0","TIME":"0:00.00","COMMAND":"kthreadd"}]}
# 5秒ごとにtop+jq
$ while true ; do top -b -n 1 | jq -rcsR '[ gsub("\n$";"") | splits("\n") | sub(" +$";"") | sub("^ +";"")] | .[0:5] as $titles | .[6:] as $data | {"sys": [$titles | .[] | split(",") | [.[] | sub("^ +";"")]]} as $sys | [$data[0] | splits(" +") | sub("%";"") | sub("\\+";"")] as $row_keys | $data[1:] | [.[] | [splits(" +")]] | {"task":[.[] | [. as $r | range($row_keys|length) | {"key": $row_keys[.], "value": $r[.]}] | from_entries] | sort_by(.MEM) | reverse | .[:10]} as $task | $sys * $task'; sleep 5; done
topとjqでサーバーのプロセスがjsonで取得できるようになりました。
おまけ
ブラウザ上でリアルタイムに確認したいので、websocketのサーバーとクライアントを作成。
Cargo.toml
[dependencies]
ws = "*"
[[bin]]
name = "ws-server"
path = "src/main.rs"
[[bin]]
name = "ws-client"
path = "src/bin/client.rs"
サーバー
メッセージが来たらブロードキャストするだけ。
src/main.rs
extern crate ws;
fn main() {
ws::listen("<さーばーのIP>:<ぽーと>", |out| {
move |msg| { out.broadcast(msg) }
}).unwrap()
}
クライアント
標準入力から持ってきてサーバーに送信するだけ。
src/bin/client.rs
extern crate ws;
use std::io::Read;
fn main() {
ws::connect("<さーばーのIP>:<ぽーと>", |out| {
let mut buf = String::new();
let _ = std::io::stdin().read_to_string(&mut buf).unwrap();
out.send(buf).unwrap();
move |_| { out.close(ws::CloseCode::Normal) }
}).unwrap();
}
ビルドして実行
$ cargo build --release
# サーバー起動
$ ./target/release/ws-server
# 別のターミナルでクライアントぐるぐる
$ while true; do top -b -n 1 | jq -rcsR '[ gsub("\n$";"") | splits("\n") | sub(" +$";"") | sub("^ +";"")] | .[0:5] as $titles | .[6:] as $data | {"sys": [$titles | .[] | split(",") | [.[] | sub("^ +";"")]]} as $sys | [$data[0] | splits(" +") | sub("%";"") | sub("\\+";"")] as $row_keys | $data[1:] | [.[] | [splits(" +")]] | {"task":[.[] | [. as $r | range($row_keys|length) | {"key": $row_keys[.], "value": $r[.]}] | from_entries] | sort_by(.MEM) | reverse | .[:10]} as $task | $sys * $task' | ./target/release/ws-client ; sleep 10 ; done
10秒ごとにtopのjsonが送信されてくるので、JSのWebSocket("ws://<サーバーのIP>:<ポート>/")
で
ごにょごにょしたらいいと思います。