俺の愛用ワンライナー、Web企業のエンジニア16人に聞きました

エンジニアの皆さんが愛用する自作のワンライナーってどんなもの?Web企業で働くエンジニアの方々に、秘蔵のワンライナーを聞きました。

俺の愛用ワンライナー、Web企業のエンジニア16人に聞きました

ワンライナーとは、何か特定の処理を「たった1行のプログラム」だけで実現するものです。サービス運用に携わるエンジニアの皆さんも、愛用している独自のワンライナーを持っているのではないでしょうか。「独自のワンライナー」とは、エンジニア各人のナレッジやノウハウが詰まっているとも考えられます。

本企画ではさまざまジャンルで活躍するエンジニア16人に、業務を支えてくれるワンライナーを紹介してもらいました。参考に使ってみるも良し。眺めて楽しむも良し。個性あふれる貴重な「オレオレ・ワンライナー」の数々をご覧ください!

※各カテゴリー内では所属企業名の50音順に掲載。回答者は敬称略とする。

リソース管理

プロセスを停止する

pgrep -f [h]ogehoge | sudo xargs kill -9
  • 使用言語:bash

サーバ内で実行されているhogehogeという名前のプロセスを、ゴースト化・サスペンド化にかかわらず絶対にkillします。プロセス名の1文字目を[]で囲むことにより、pgrepで探しているプロセス自体が除外されます。

運用中のサービスのなかで、特定のプロセスが意図しない形で複数立ち上がってしまっていたものを、正常・非正常実行にかかわらず、全て停止しなければならない、という残念な状況で使う処理です。気持ちも残念になります。

比較的、汎用性のあるワンライナーですが、いろいろなプロセスで多用する状況になると悲しい気持ちになります……。

Google Kubernetes Engine全体のノードのリソース状況を確認する

kubectl get nodes | grep gke | cut -f1 -d' ' | xargs -I{} sh -c 'kubectl describe node {} | grep -A 2 "CPU Requests" | tail -n 1; sleep 1'
  • 使用言語:bash

Google Kubernetes Engine全体のノードのリソース状況を確認するワンライナーです。GKEノード数が多くなり、どれくらいリソースを利用しているのか把握しにくくなったため、一括で確認する方法が必要になり作成しました。なお、xargsを使わずに他の方式で書いたら速くなりました。修正後ワンライナーは以下の通り

kubectl describe node | egrep -A 2 "^ +CPU Requests"|egrep '[0-9]+'

物理メモリを多く使用しているプロセスを抽出する

ps aux | sort -n -k 6 | tail -n 10
  • 使用言語:bash

物理メモリを多く使用しているプロセスの上位10件を抽出します。引数の数字を変えるだけでCPUとメモリについて調べることができて便利です。複雑なコマンドではないため忘れにくいのも良い点です。サーバーのリプレイスでリソースの消費に差が出たとき、このワンライナーで比較できたため、大活躍しました!

CPU使用率が高いプロセスを見つける

watch -n 2 "ps aux| sort -nk +3 | tail" or watch -n 2 "ps aux| sort -nk +4 | tail"
  • 使用言語:bash

CPU使用率が高いプロセスを見つけるときに使用します。なお、+4はメモリの使用率が高いプロセスを見つけるときのオプションです。Dockerになっていないサーバーでなぜか負荷が高くなるときがありますが、このワンライナーを使えば、原因となっているプロセスを効率よく特定できます。

データ集計

maillogから、メールの送信者情報を取得する

(for queue in `grep 'status=sent' /var/log/maillog | awk '{print $6}' | tr -d ':'`; do grep $queue /var/log/maillog | grep sasl_username | awk '{print $7}' | cut -d '=' -f2 | tr -d ','; done;) | sort | uniq -c | sort -n
  • 使用言語:bash

maillogからqueue IDを抽出し、各queue IDごとのユーザ認証者のリモートホストとリモートIPを拾い、出現回数とともに出力します。

以前、大規模メールシステムを扱っていた際に大量送信するユーザがいたためサーバが高負荷になることがあったのですが、その原因特定のために使用していました。postfix + procmail + formail を使っていてqueue IDが変化して送信されることが多かったのと、出力結果をそのまま報告書にコピペしたいので、こんな回りくどいことをしていました。

Apacheのアクセスログから、ページごとのアクセスランキングを集計

zgrep -hE "\"GET /.+ HTTP.+\" 200 " `find /var/log/httpd -name 'access_log.*'` | awk '{print $1$8}' | sort | uniq -c | sort -nr
  • 使用言語:bash

Apacheのアクセスログから、アクセスランキングを算出。アクセス数の多い順にそのURLとアクセス数を表示します(Common Log Format with Virtual Hostで動作します)。

実行例:
1263 www.example.com/
1352 www.example.com/about/
 456 www2.example.com/

私自身はワンライナー初心者ですが、この記事企画を機に、複数のWebサイトを運用しているWebサーバで、アクセスログからアクセスランキングを算出したいと思い書いてみました。awkコマンドの利便性に感動しました。

時間帯ごとのおおまかなエラーレートを集計する

awk '{$2=substr($2,1,13);print $2,$3,$4,$6;}' access.log | sort | uniq -c

access.log は以下のようなWebサーバ(nginxなど)のログファイルを想定します。

10.229.60.225 2018-02-27T08:40:14+09:00 "GET /path/to/app HTTP/1.1" 200
10.93.104.150 2018-02-27T11:06:47+09:00 "DELETE /path/to/app HTTP/1.1" 200
10.255.181.79 2018-02-27T11:07:47+09:00 "GET /path/to/app HTTP/1.1" 200
10.108.135.104 2018-02-27T14:43:21+09:00 "POST /path/to/app HTTP/1.1" 200
10.209.240.194 2018-02-27T18:39:07+09:00 "POST /path/to/app HTTP/1.1" 502
  • 使用言語:bash、awk

時間帯ごとの大まかなエラーレートを集計できます。もちろん少し変更すれば別の指標での集計も容易です。わざわざDBやSQLiteに入れるまでもないレベルの集計なら、このワンライナーの応用範囲はかなりあります。

環境が整ってきたため、現在では本番サーバ上のログを直接集計することはありません。そういった環境が整備されていない頃、リリース後の監視の際にこのようなワンライナーを重宝していました。

データベースからダンプファイルを取得する

pg_dump -h hostname -U username -f #{Rails.root}/tmp/app_name.dump database_name
  • 使用言語:SQL(PostgreSQL)

ホストがhostnameでオーナーがusernameのdatabase_nameデータベースからダンプファイルを取得します。本番のデータをローカルDBにリストアする際、最新のダンプファイルが欲しい場合に使用します。

ローカルで開発する際に本番環境と同じ状態が作れるので便利ですが、サービスが大規模になってくるとダンプやリストアが重くなり過ぎて、だんだんと使えなくなります。スタートアップでの開発や個人開発向きかもしれません。

MySQLのbinlogの中身を発行されたクエリ単位で集計する

mysqlbinlog mysqld-bin.xxxxxx --start-datetime '2018-02-26 12:59:59' --stop-datetime '2018-02-26 13:00:59' | perl -e 'while(<>){ chomp; next if m/^#/; if( m{/\*!\*/;$} ){ $p .= $_; print "${p}\n"; $p="" } else { $p .= "${_} "}}'|perl -nle 'm/^(DELETE FROM|REPLACE INTO|INSERT INTO|UPDATE|BEGIN|COMMIT)\s+([^ ]+)/i && print "${1} ${2}"' | sort | uniq -c | sort -n -r
  • 使用言語:bash、Perl、mysqlbinlog

MySQLのbinlogの中身を発行されたクエリ単位で集計します。かつて、毎時XX分になるとDBの負荷が跳ねることがあったため、その際どんなクエリが流れているのかを調べるために作成したワンライナーです。

まとめて発行できるクエリであればBulk Insertなどに変えてもらったり、逆にゆっくり流しても大丈夫なクエリであればcommit間隔を調整してもらったりと、このコードを元に調査・報告していました。

また、上記は更新クエリなのですが、参照クエリが原因となる場合はPERCONA TOOLKITのmk-query-digest(pt-query-digest)に食わせるためにtcpdumpを取得して使っています。その際は以下のワンライナーを使用します。

tcpdump -i bond0 -s 65535 -x -n -q -c 100000 -tttt 'port 3306' > tcpdump.out 2> /dev/null mk-query-digest --type=tcpdump --filter '$event->{fingerprint} !~ m/^(commit|admin|set)/' --limit 100 tcpdump.out

どちらもクエリの質をチェックして改善できる点を洗い出し、開発側のエンジニアと相談するための材料としています。

データ整理

fluentdのログを見やすく整形する

cat /var/log/td-agent/td-agent.log |awk -F'[:{+]' '{print $4, $5}'|sort |uniq -c
  • 使用言語:bash

fluentdのログをだいたいの場合見やすく整形できます。fluentdに新しいプラグインを導入した際など、業務においてデバックする機会があると思います。しかし、fluentdのログは、時に1行が非常に長く、生ログの目grepを頑張るのがつらいケースもあります。そういう時に、私が一人で使って一人で幸せになっているワンライナーです。つまらないシェル芸で恐縮です。

自然数の数列をビジュアライズする

for i in `seq 0 30`;do echo $RANDOM;done | awk -v scale=1500 -v max=30 '{num=int($1/scale);for(i=0;i<=max;i++){if(i==num){p="o"}else if(I<num){p="| "}else{p=". "};printf p" "};printf "\n\n"}' | rs -T | tail -r | sed -e "s/\./ /g"

※"for i in `seq 0 30`;do echo $RANDOM;done" は任意の自然数の数列に変更する。 ※scale, maxは任意の自然数に変更する。

  • 使用言語:sh

出力されたログの行数を日付ごとに出したいときなどに、増加傾向にあるのか減少傾向にあるのかチェックするために使用していました。

便利技

ランダムな大文字小文字英数字を、スピーディにクリップコピーする

ruby -e "src = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a ; puts (0...20).map{ src[rand(src.size-1)] }.join" | pbcopy
  • 使用言語:Ruby

ランダムな大文字小文字英数字の20文字をターミナルに出さずにクリップコピーします。適当な文字列にパッと書き換えたいシーンで利用しています。

Gistに上げておいたgitのCommit templateを取り込む

wget -O $HOME/.git_commit_template [GistのrawのURL] && git config --global commit.template $HOME/.git_commit_template
  • 使用言語:bash

Gistに上げておいたgitのCommit templateを取り込みたいときに叩くワンライナーです。gitでコミットする際、コメントの先頭に絵文字を入れているのですが、その絵文字の名前と外観を毎回思い出すのが大変だったので、Commit templateに絵文字のリストと、どのような場合に使うかを入れてしまおうと思い、作成しました。

JMeterによる負荷テスト

threads=( cat config/threads); duration=`cat config/duration`; for file in plans/*.jmx; do for thread in ${threads[@]}; do jmeter -n -t ${file} -Jthread=${thread} -Jduration=${duration}; done done
  • 使用言語:bash

Linux環境でさまざまなテストケースを自動実行します。観光客向けグルメアプリ「日本美食」では高品質なサービスを提供するために、定期的にJMeterを利用してさまざまな負荷テストを実施しています。今回のワンライナーはそうしたテストシナリオの一部です。他のシナリオと合わせて、自動的にテスト実行、結果収集、レポート作成までを実現してくれます。

  • 回答者:日本美食株式会社 T.Spike(Architect)
  • 主な運営サービス:日本美食(観光客向けグルメアプリ「日本美食」は、「media」と「payment」を組み合わせ、訪日観光客と飲食店に今までにない体験を提供しています)

PNGファイルの処理

convert img1.png \( +clone -fill white -draw 'color 0,0 reset' \) +swap -composite img2.png

※whiteの部分は任意の色のほか、pattern:checkerboardなどの組み込みパターンも使用可能

  • 使用言語:sh、ImageMagick

PNGを不透明にする。または背景をつけるために使っています。

Gitコマンドを強化する

`gs` & `gd` from https://github.com/scmbreeze/scm_breeze/
  • 使用言語:bash

SCM BreezeはGitを便利に利用できる機能を提供してくれるシェルスクリプト群です。gsとgdはそれぞれgit statusとgit diffの機能を強化したものになっています。(大半はショートカット系の機能です)

おわりに

「たった1行のプログラム」と侮るなかれ。データ集計からプロセス操作、画像加工まで、ワンライナーで実現できる処理は多種多様です。本稿のコードを参考にして、あなたの「オレオレ・ワンライナー」を作り出してみてください。

編集:中薗昴(サムライト)

若手ハイキャリアのスカウト転職