会員登録すると
学習することができます。
会員登録する(無料)
登録済みの方はこちら
ログイン

ログを読む ― tail・grep・sort | uniq -c で「多い・最初・同じ」を探す

目安学習時間 20分

課題

全問正解でレクチャー完了です。

【問題1】

1回のリクエストに関係するログの行だけを順番に並べたいとき、手がかりにするものはどれですか。

[選択肢]

【問題2】

アクセスログで状態コードごとの件数を多い順に出すコマンドの組み合わせとして、正しいものはどれですか。

[選択肢]
会員登録すると
学習することができます。
会員登録する(無料)

学ぶ目的

読む前に、問いを決める

ログは何千行、何万行とあります。上から順に読むことはしません。問いを決めてから、コマンドで絞り込みます。障害のときの問いは、だいたい次の3つです。

問い 使うもの
何が多いか awk で列を取り出し、`sort \
最初はいつか grep -m1(最初の1件だけ)
同じリクエストの行はどれか リクエストIDで grep

以下は、練習用に作ったログで手元で実行した結果です。障害の筋書きは「10:12 に新しい版を公開した直後から、応募が失敗している」です。

今まさに起きているかを見る:tail

tail -n 3 app.log                              # 最後の3行
tail -f app.log | grep --line-buffered ERROR   # 追記されたエラー行だけを流し続ける

tail -f は、ファイルに行が足されるたびに表示します(Ctrl+C で止める)。直した後に「もうエラーが出ていないか」を見張るときにも使います。--line-buffered を付けないと、grep が出力をためこんで、すぐに表示されないことがあります。

何が多いか:状態コードを数える

アクセスログは、空白で区切ると9番目の列が状態コードです。

awk '{print $9}' access.log | sort | uniq -c | sort -rn
   7 200
   4 500
   2 404
   1 302

500 が4件。では、どの画面で起きたか。

awk '$9 == 500 {print $7}' access.log | sort | uniq -c | sort -rn
   2 /jobs/12/apply
   1 /jobs/8/apply
   1 /jobs/31/apply

すべて応募(apply)でした。同じ件数の行の並び順は、環境によって変わることがあります。

「同じ500」の中身は同じとは限らない

アプリのログで、エラーの種類を数えます。

grep ERROR app.log | cut -d' ' -f4- | sort | uniq -c | sort -rn
   3 NoMethodError: undefined method 'name' for an instance of Job
   1 Net::ReadTimeout: notification server did not respond

外から見ると同じ「500」が4件でも、原因は2種類ありました。1件だけ、通知先のサーバが応答しなかったものです。まとめて1つの原因だと思い込むと、片方を直しても「まだ出ている」ことになります。

最初はいつか

grep -m1 ERROR app.log
grep deploy app.log
2026-10-24T10:13:05 ERROR [req=9a7f] NoMethodError: undefined method 'name' for an instance of Job
2026-10-24T10:12:30 INFO  [deploy] release 20261024101230 started

最初のエラーは、新しい版の公開の35秒後です。直近の変更が一番の容疑者になります(第6回)。最新のエラーだけを見ていると、この並びに気づけません。

時刻で範囲を切りたいときは、時刻が先頭にあり、2026-10-24T10:13:30 のように桁がそろった形なら、文字列の大小比較で絞れます。

awk '$1 >= "2026-10-24T10:13:30" && $1 < "2026-10-24T10:14:40"' app.log

同じリクエストの行をつなぐ:リクエストID

1つのリクエストの行は、ほかのリクエストの行と混ざって書かれます。そこで、多くのアプリは行にリクエストID(1回のリクエストに振られた番号)を付けます。これで探すと、1回分の出来事が順番に並びます。

grep 'req=9a7f' app.log
2026-10-24T10:13:05 INFO  [req=9a7f] POST /jobs/12/apply
2026-10-24T10:13:05 INFO  [req=9a7f] application saved id=902
2026-10-24T10:13:05 ERROR [req=9a7f] NoMethodError: undefined method 'name' for an instance of Job
2026-10-24T10:13:05 INFO  [req=9a7f] completed 500 in 47ms

応募は保存されてから、エラーになっています。 第2回の「データは届いているのに失敗と表示される」状態です。影響の見積もりが、ログ1つで変わります。

grep が「Binary file ... matches」としか言わないとき

ログに文字ではないバイト(NUL文字など)が混ざると、grep は中身を出さずに、こう言うだけになります(手元の macOS で確認。表示の文言は OS や grep の版で違います)。

Binary file broken.log matches

grep -a(文字として扱う)を付けるか、tr -d '\000' で取り除いてから探します。naminori の本番ログを集計するときも、この1手間を入れています。

tr -d '\000' < broken.log | grep ERROR

長い1ファイルを見て回る:less

less app.log で開き、/ERROR で検索、n で次へ、G で末尾、F で tail -f のように流し続ける、q で終わります。

ここで後から困ること

「エラーがたくさん出ています」とだけ報告すると、直した後に本当に減ったのかを比べられません。数えたコマンドと件数を、そのまま記録に残しておきます(第8回)。

このレクチャーで学ぶこと

  • 問いを決めてから絞り込む
  • tail -f で今を見張る
  • 状態コードとエラーの種類を数える
  • 最初のエラーと直近の変更を並べる
  • リクエストIDで1回分の出来事をつなぐ
  • Binary file matches の対処

質問

まだ質問は投稿されていません。

質問投稿

ログイン後に質問の投稿ができます。