LoginSignup
13
12

More than 5 years have passed since last update.

topとjqでプロセスのリモート監視

Posted at

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>:<ポート>/")
ごにょごにょしたらいいと思います。

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12