Web サーバーのアクセスログを読んで、ステータスごとの件数と、応答の遅いリクエストの上位3件を出す。障害の調べものでよく書く、小さなツールです。いちばん手軽な「空白で区切って何番目かを取る」書き方を10言語で用意して、同じログを読ませました。
ステータスが 2OO(数字のゼロのつもりが英字のオー)の壊れた行を、10言語すべてが読めた行として数え、2OO 1 と集計しました。
何をしたか
CODE Polyglot の「よく使う書き方」 で、ログの1行の形と出力を先に決めました(正解表8件)。
203.0.113.5 - - [30/Oct/2026:09:00:01 +0900] "GET /index.html HTTP/1.1" 200 5120 0.012
- 形に合わない行は「読めない行」として数える。ステータスは3桁の数字、応答秒は「数字.数字」
- 遅い順は、応答秒の大きい順。同じ秒なら先に出た行を先に
- 改行が
\r\nでも、最後に改行が無くても同じ答えにする
よく見かける書き方は、空白で区切って11個あれば読めた行とするものです。Python ならこうです。
for line in sys.stdin:
p = line.split()
if len(p) != 11:
bad += 1
continue
rows.append({"method": p[5].lstrip('"'), "path": p[6], "status": p[8], "sec": p[10]})
落ちたところ
| ケース | 落ちた言語 | 何が起きたか |
|---|---|---|
| c002 壊れた行が混ざる | 10言語中10言語 | 区切った数が11個なので、2OO の行も読めた行になった |
| c003 応答秒の桁数が違う | Python・Kotlin・Swift・Java(10言語中4言語) | 応答秒を文字のまま並べ、10.5 が 9.8 より小さくなった |
c005 改行が \r\n | JavaScript・C#・Rust(10言語中3言語) | \r が行に残り、出力に混ざった。Rust は数への変換に失敗して止まった |
| c004 同じ応答秒が4件 | Ruby(10言語中1言語) | sort_by のあとの reverse で、同じ秒の行の順が逆になった |
| c001・c005・c008 | Java | 件数を HashMap に入れて回したので、ステータスが 200, 401, 500, 404 の順に出た |
"10.5" と "9.8" を文字として比べると、1文字目の 1 と 9 で決まるので、10.5秒の方が「小さい」ことになります。PHP の <=> は、数字だけの文字列どうしなら数として比べるので、同じ書き方でもたまたま正しく並びました。
同じ秒の並び順は、並べ替えが「安定」(同じ値の順番を変えない)かどうかで決まります。Python の sorted、Java の List.sort、Kotlin の sortedByDescending は安定です。Go の sort.Slice と C# の List.Sort は安定と決まっていませんが、今回の4件では差が出ませんでした(要素が少ないと挿入ソートになるため)。件数が増えると順番が入れ替わることがあります。
どう書いたか
行全体が決めた形に合うかを正規表現で確かめ、応答秒は数にしてから比べました。Python ならこうです(抜粋)。
LOG = re.compile(r'\S+ \S+ \S+ \[[^\]]+\] "(\S+) (\S+) [^"]+" ([0-9]{3}) ([0-9]+|-) ([0-9]+\.[0-9]+)')
for line in sys.stdin.read().split("\n"):
line = line.rstrip("\r")
m = LOG.fullmatch(line)
...
# sorted は安定(同じ値なら元の順)。reverse=True でも同じ秒どうしの順は崩れない
for sec, method, path, _ in sorted(rows, key=lambda r: float(r[0]), reverse=True)[:3]:
Rust は標準に正規表現が無いので、 [・] "・"・空白の順に切り分けて形を確かめています。安定と決まっていない並べ替えしか無い言語(Swift・Ruby の sort_by)では、何行目かを2つ目のキーにしました。10言語のコードは、どれも8件すべてで決まりどおりの答えを出しています。
まとめ
- 空白で区切って数を数えるだけでは、壊れた行を見分けられない。使う欄の形を確かめる
- 数として並べる値は、数にしてから比べる
- 「同じ値の順」を決めているなら、安定な並べ替えを使う(または行番号を2つ目のキーにする)
10言語のコードと全8件の結果は CODE Polyglot「アクセスログを集計する」 にあります。
- 第1回:HTML のエスケープ、標準の関数の答えが言語ごとに違った
- 第2回:「2026-02-30T09:00:00Z」を、4言語の標準のパーサーが3月2日として読んだ
- 第3回:「getHTTPResponseCode」をスネークケースに、よく見かける書き方は10言語中9言語で崩れた
- 第4回:アクセスログを空白で区切って集計したら、10言語すべてが壊れた行を数えた(この記事)
- 第5回:重複を消したら順番が変わった、Swift は「が」を1つにまとめた
- 第6回:İstanbul の slug が5通りに割れた、日本語のタイトルはそのまま URL に入った
Analyzegear


