ログストリームからのメトリクスとヒストグラムの計算
ストリーミング中のログデータから、リクエストレート、パーセンタイル、上位N件のレポートを直接集計します。
「ログストリームからのメトリクスとヒストグラムの計算」はCoddyKit上の無料Linux Command Line & Bash Scripting Masteryレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLinux Command Line & Bash Scripting Mastery学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Linux Command Line & Bash Scripting Masteryコースには全4レッスンが含まれています。
raw ログからメトリクスを計算する理由
本番システムは、1 秒あたり数千行のログを出力します。raw ログを高価な分析プラットフォームへ送る代わりに、シェル上でリクエストレート、パーセンタイル、Top-N レポートを直接計算すれば、ほぼコストをかけずに済みます。
- リクエストレート: サービスは 1 秒または 1 分あたりに何件のリクエストを処理していますか。
- レイテンシのパーセンタイル: p50/p95/p99 の応答時間はどのくらいですか。
- Top-N レポート: エンドポイント、IP、エラーコードのうち、最も頻繁に現れるものはどれですか。
awk、sort、uniq、bc などのシェルツールは、強力で組み合わせ可能なパイプラインを構成します。これにより、ターミナルを離れることなく、ライブのログストリームや過去のファイルからこれらの疑問に答えられます。
一般的なアクセスログの構造
ほとんどの Web サーバーはCombined Log Formatでログを書き込みます。各フィールドを理解することは、あらゆるメトリクスパイプラインの基礎です。
127.0.0.1 - frank [10/Oct/2024:13:55:36 -0700] "GET /api/users HTTP/1.1" 200 2326 0.042- フィールド 1: クライアント IP
- フィールド 4(角括弧内): タイムスタンプ
- フィールド 7(引用符内): HTTP メソッド + パス
- フィールド 9: ステータスコード
- フィールド 10: レスポンスのバイト数
- フィールド 11: 応答時間(秒単位。カスタムフィールドで、常に存在するとは限りません)
awk を使うと、位置($1、$9 など)でフィールドを参照できます。引用符内のフィールドは、注意して分割した場合にのみ 1 つのトークンとして扱われます。ログ行を awk -F'"' で囲むか、複数回に分けて処理してください。
1 分あたりのリクエストレートのカウント
1 分あたりのリクエスト数を計算するには、各タイムスタンプから分の部分を取り出し、出現回数を数えます。[day/Mon/year:HH:MM というパターンで、時刻の分単位のバケットを取得できます。
次のパイプラインは access.log を読み込み、分 → リクエスト数の表を出力します。
#!/usr/bin/env bash
# Requests per minute from an nginx/apache access log
# Usage: bash req_per_min.sh access.log
LOG="${1:-access.log}"
awk '{
# Extract [day/Mon/year:HH:MM from field 4
match($0, /\[([^:]+:[0-9]+:[0-9]+)/, arr)
minute = arr[1]
if (minute != "") count[minute]++
} END {
for (m in count) print count[m], m
}' "$LOG" | sort -k2ライブストリームによるスライディングウィンドウのレート
ライブ追跡では、スライディングウィンドウが必要です。ここでのポイントは、tail -f の出力を awk にパイプし、システムクロック(systime())を使って N 秒ごとにカウンターをリセットすることです。
次の例では、10 秒ごとにレート行を出力します。
#!/usr/bin/env bash
# Live request rate — prints lines/10s from a tailed log
# Usage: bash live_rate.sh /var/log/nginx/access.log
LOG="${1:-/var/log/nginx/access.log}"
WINDOW=10
tail -f "$LOG" | awk -v win="$WINDOW" '
BEGIN { start = systime(); count = 0 }
{
count++
now = systime()
if (now - start >= win) {
printf "[%s] %d req/%ds (%.1f req/s)\n",
strftime("%H:%M:%S", now), count, win, count/win
count = 0
start = now
}
}'パーセンタイル計算用のレイテンシ値の抽出
パーセンタイルを求めるには、観測したすべてのレイテンシ値をソートする必要があります。標準的な手順は次のとおりです。
- レイテンシ列を通常の数値リストとして抽出します。
- 数値順にソートします。
- 行数の計算を使って、正しい順位の値を選びます。
次のスクリプトは、フィールド 11(秒単位の応答時間)を抽出し、次の手順でパーセンタイルを計算するために一時ファイルへ保存します。
#!/usr/bin/env bash
# Extract latency column from access log (field 11)
# Assumes last field on each line is response time in seconds
LOG="${1:-access.log}"
TMP=$(mktemp /tmp/latency_XXXXXX.txt)
awk '{ if ($NF ~ /^[0-9]+\.?[0-9]*$/) print $NF }' "$LOG" \
| sort -n > "$TMP"
echo "Extracted $(wc -l < "$TMP") latency samples -> $TMP"
echo "$TMP" # callers can read this fileawk による p50、p95、p99 の計算
レイテンシ値をソートしたら、パーセンタイルの選択は算術計算で行えます。p パーセンタイルは、行 ceil(p/100 * N) に位置します。ソート済みファイルを配列に読み込めば、純粋な awk だけで 1 回の走査で計算できます。
#!/usr/bin/env bash
# Compute p50 / p95 / p99 from a sorted latency file
# Usage: bash percentiles.sh latency_sorted.txt
# Demo: generate 1000 random latencies if no file given
if [[ $# -eq 0 ]]; then
SORTED=$(mktemp)
for i in $(seq 1 1000); do
awk 'BEGIN { srand(); printf "%.4f\n", 0.001 + rand()*0.999 }'
done | sort -n > "$SORTED"
else
SORTED="$1"
fi
awk '
{ values[NR] = $1 }
END {
n = NR
if (n == 0) { print "No data"; exit }
p50 = values[int(n * 0.50 + 0.9999)]
p95 = values[int(n * 0.95 + 0.9999)]
p99 = values[int(n * 0.99 + 0.9999)]
printf "p50 = %.4fs\np95 = %.4fs\np99 = %.4fs\nN = %d\n",
p50, p95, p99, n
}' "$SORTED"Top-N エンドポイントレポートの作成
Top-N レポートでは、「最も多くアクセスされたパスはどれか」という疑問に答えられます。シェルでよく使われる定石は次のとおりです。
awkで対象のフィールド(例: URL パス)を出力するsortで同じ値をまとめるuniq -cで連続する重複を数えるsort -rnで件数の降順に順位付けするhead -n Nで上位 N 件を取得する
#!/usr/bin/env bash
# Top-10 most requested URL paths from access log
# Usage: bash top_endpoints.sh access.log [N]
LOG="${1:-access.log}"
N="${2:-10}"
echo "=== Top $N endpoints ==="
awk -F'"' '{ print $2 }' "$LOG" \
| awk '{ print $2 }' \
| sort \
| uniq -c \
| sort -rn \
| head -n "$N" \
| awk '{ printf "%6d %s\n", $1, $2 }'ステータスコード別 Top-N: エラーをひと目で把握
HTTP ステータスコードは、サービスの健全性を示します。ログ行をステータスコードごとにグループ化して数えると、エラーがまれに発生しているのか、システム全体に及んでいるのかが分かります。
次のスクリプトは、2xx/3xx/4xx/5xx のすべてのバケットについて内訳を生成します。
#!/usr/bin/env bash
# Status code frequency breakdown
# Usage: bash status_breakdown.sh access.log
LOG="${1:-access.log}"
echo "=== HTTP Status Code Distribution ==="
awk '{ print $9 }' "$LOG" \
| grep -E '^[0-9]{3}$' \
| sort \
| uniq -c \
| sort -rn \
| awk '{ printf "%6d %s\n", $1, $2 }'
echo
echo "=== 5xx Error Spike Check ==="
awk '$9 ~ /^5/ { print $9, $7 }' "$LOG" \
| sort | uniq -c | sort -rn | head -20awk による ASCII ヒストグラム
テキストヒストグラムを使うと、ターミナルや CI ログでレイテンシの分布をすぐに読み取れます。手順は次のとおりです。
- 各レイテンシ値をビン(例: 0-50ms、50-100ms、…)に分類します。
- ビンごとに観測数を数えます。
- 最大件数に合わせてスケーリングした
#文字の棒を出力します。
グラフ作成ツールを使わずに、二峰性の分布や外れ値を見つける際に非常に役立ちます。
#!/usr/bin/env bash
# ASCII latency histogram from a list of latency values in seconds
# Demo: generates synthetic data if no input file is provided
if [[ $# -eq 0 ]]; then
# Generate 500 synthetic latencies (ms converted to s)
python3 -c "
import random, math
for _ in range(500):
# bimodal: fast cluster ~50ms, slow cluster ~300ms
if random.random() < 0.75:
v = max(1, random.gauss(50, 15))
else:
v = max(1, random.gauss(300, 80))
print(f'{v/1000:.4f}')
" | sort -n | awk '
{ values[NR] = $1 * 1000 } # convert to ms
END {
buckets = 10; maxVal = 500
step = maxVal / buckets
for (i = 0; i < buckets; i++) hist[i] = 0
for (i = 1; i <= NR; i++) {
b = int(values[i] / step)
if (b >= buckets) b = buckets - 1
hist[b]++
}
maxCount = 0
for (i = 0; i < buckets; i++) if (hist[i] > maxCount) maxCount = hist[i]
print "Latency (ms) Count Distribution"
print "---------------------------------------"
for (i = 0; i < buckets; i++) {
lo = i * step; hi = lo + step
barLen = int(hist[i] / maxCount * 40)
bar = ""
for (j = 0; j < barLen; j++) bar = bar "#"
printf "%4d-%4dms %5d %s\n", lo, hi, hist[i], bar
}
}'
else
echo "Usage: pipe a sorted latency file (in seconds) to this pattern"
fiメトリクスの統合: 一括サマリーレポート
本番環境のランブックでは、レート、レイテンシのパーセンタイル、上位エンドポイント、エラーレートといった主要なメトリクスをすべて一度に出力する単一のコマンドが必要になることがよくあります。ここまでに学んだ内容を 1 つのスクリプトにまとめ、人間やアラートシステムから呼び出せるようにできます。
#!/usr/bin/env bash
# One-shot log summary report
# Usage: bash log_summary.sh access.log
LOG="${1:-access.log}"
[[ -f "$LOG" ]] || { echo "File not found: $LOG"; exit 1; }
TOTAL=$(wc -l < "$LOG")
ERRORS=$(awk '$9 ~ /^[45]/' "$LOG" | wc -l)
ERR_RATE=$(awk "BEGIN { printf \"%.1f\", ($ERRORS / ($TOTAL || 1)) * 100 }")
echo "====================================="
echo " Log Summary: $LOG"
echo "====================================="
printf " Total requests : %d\n" "$TOTAL"
printf " 4xx/5xx errors : %d (%.1f%%)\n" "$ERRORS" "$ERR_RATE"
echo
echo "--- Top 5 Endpoints ---"
awk -F'"' '{ print $2 }' "$LOG" | awk '{ print $2 }' \
| sort | uniq -c | sort -rn | head -5 \
| awk '{ printf " %6d %s\n", $1, $2 }'
echo
echo "--- Latency Percentiles ---"
awk '{ if ($NF ~ /^[0-9]+\.?[0-9]*$/) print $NF * 1000 }' "$LOG" \
| sort -n \
| awk '
{ v[NR]=$1 }
END {
if (NR==0) { print " No latency data"; exit }
printf " p50 = %.1fms\n", v[int(NR*0.50+0.9999)]
printf " p95 = %.1fms\n", v[int(NR*0.95+0.9999)]
printf " p99 = %.1fms\n", v[int(NR*0.99+0.9999)]
}'名前付きパイプと tee によるストリーミングメトリクス
オブザーバビリティパイプラインでは、ログストリームを分岐する必要がよくあります。つまり、raw 行をディスクに書き込みながら、同時にメトリクスも計算します。名前付きパイプ(mkfifo)と tee を使えば、ストリーム全体をメモリにバッファリングせずにこれを実現できます。
mkfifo /tmp/log_pipe— 名前付きパイプを作成するtee /tmp/log_pipe | metric_consumer &— 一方の分岐をメトリクスコンシューマーへ送る- もう一方の分岐でアーカイブファイルに書き込む
このパターンにより、ディスクへの書き込みとメトリクスの集計を分離でき、どちらの側も独立して再起動できます。
#!/usr/bin/env bash
# Fan-out: write to archive AND count errors in real time
# Run: bash fanout_pipeline.sh /var/log/nginx/access.log
LOG="${1:-/var/log/nginx/access.log}"
ARCHIVE="/tmp/access_archive.log"
PIPE="/tmp/log_metrics_pipe"
# Clean up on exit
trap 'rm -f "$PIPE"' EXIT
mkfifo "$PIPE"
# Branch 1: count 5xx errors per minute from the pipe
awk '$9 ~ /^5/ {
match($0, /\[([^:]+:[0-9]+:[0-9]+)/, arr)
errors[arr[1]]++
} END {
for (m in errors) printf "5xx errors at %s: %d\n", m, errors[m]
}' "$PIPE" &
# Branch 2: archive to disk + feed Branch 1 via pipe
tail -f "$LOG" | tee "$PIPE" >> "$ARCHIVE"ソート済み配列から p95 パーセンタイルを正しく計算する awk の手法はどれですか
N 個のソート済みレイテンシ値を awk の配列 v[1..N] に読み込んであります。p95 パーセンタイルを正しく取得する式はどれですか。
レッスンのまとめ: ログストリームからのメトリクスとヒストグラム
このレッスンでは、Bash だけで完全なメトリクスパイプラインを構築しました。
- リクエストレート:
awkでタイムスタンプから分単位のバケットを抽出して出現回数を数え、tail -fとsystime()でライブのスライディングウィンドウレートを取得します。 - レイテンシパーセンタイル: レイテンシ列を抽出し、
sort -nでソートしてから、awk でint(N * p + 0.9999)を使い、ceil(p/100 * N)番目の行を選びます。 - Top-N レポート: 定番の
awk | sort | uniq -c | sort -rn | head -Nパイプラインは、パス、IP、ステータスコードなど、あらゆるカテゴリフィールドで利用できます。 - ASCII ヒストグラム: 値をバケットに分け、ビンごとに数を集計し、最大のビンの件数に合わせて棒の長さを拡大縮小することで、分布をひと目で確認できます。
- 名前付きパイプによるファンアウト:
mkfifoとteeを使うと、ストリーム全体をメモリに読み込まずに、生ログのアーカイブとメトリクスコンシューマーへの供給を同時に行えます。
これらの組み合わせ可能なプリミティブにより、インシデント発生時に外部ツールへ依存する必要がなくなり、Bash が動作するあらゆる環境で実行できる軽量なオブザーバビリティスクリプトの基盤となります。
よくある質問
「ログストリームからのメトリクスとヒストグラムの計算」レッスンは無料ですか?
はい。「ログストリームからのメトリクスとヒストグラムの計算」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Linux Command Line & Bash Scripting Masteryコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Linux Command Line & Bash Scripting Masteryコースには全4レッスンが含まれています。
「ログストリームからのメトリクスとヒストグラムの計算」で何を学びますか?
ストリーミング中のログデータから、リクエストレート、パーセンタイル、上位N件のレポートを直接集計します。 ブラウザで直接実行するハンズオンコードでLinux Command Line & Bash Scripting Masteryを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Linux Command Line & Bash Scripting Masteryを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLinux Command Line & Bash Scripting Masteryは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「ログストリームからのメトリクスとヒストグラムの計算」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLinux Command Line & Bash Scripting Masteryレッスンでコードを書いて実行できますか?
はい。すべてのLinux Command Line & Bash Scripting Masteryレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 大規模なWeb・アプリケーションログの解析
- リアルタイムのログ追跡とストリーミングアラート
- スクリプトでjournalctlを使ったjournaldの検索
- ログストリームからのメトリクスとヒストグラムの計算