フランス拠点の障害対応で使う圧縮ログ、gzipのままgrepすると文字化けする理由

这篇内容暂时只有 日本語 版本,以下是原文。

フランス拠点の障害対応で、アプリのログを1日分まとめてapp-2024-06-12.log.gzの形で受け取ることが多い。日本語のキーワードで検索しようとしてzgrepではなく通常のgrepをかけてしまい、何もヒットしないまま10分ほど溶かした経験がある。環境はUbuntu 22.04、ロケールはfr_FR.UTF-8、ファイルサイズは1日あたり400MB前後、圧縮後で40MB程度。ログ本文はUTF-8だが、現地の運用担当がWindowsのメモ帳で一部を編集して再圧縮したファイルが混ざっていた。

まずやったのは、圧縮形式と文字コードを同時に確認する手順の固定化。

file app-2024-06-12.log.gz
zcat app-2024-06-12.log.gz | file -
zcat app-2024-06-12.log.gz | head -c 200 | hexdump -C | head

fileがgzip compressed dataを返しても中身がUTF-8とは限らない。hexdumpで先頭を見ると、BOM付きUTF-8やShift_JIS由来のバイト列が混ざっているケースがあった。検索は次のように分けた。

zgrep -a "エラー" app-2024-06-12.log.gz
zcat app-2024-06-12.log.gz | iconv -f CP932 -t UTF-8//IGNORE | grep "エラー"

-aを付けないとgzipバイナリと判定されてBinary file matchesで止まる。iconvは//IGNOREを付けないと不正バイトで途中終了するが、その分だけ行が落ちるので件数は一致しない。

なぜこうするか。gzipはバイト列を圧縮するだけで文字コードを保持しない。zgrepは展開後にそのままgrepするため、ロケールがfr_FR.UTF-8の端末ではCP932のバイト列が不正なUTF-8として扱われ、行ごと捨てられることがある。つまり「ヒットしない」のではなく「読めていない」。逆にiconvで変換すると、元のバイト列が壊れていた行は消える。完全一致を求めるなら変換前の生バイトでgrep -aをかけ、目視で確認するのが結局は速い。

失效するのは、ログが複数世代でローテートされていて途中から文字コードが変わっている場合。1ファイルずつ判定するしかない。またzgrep -aは巨大ファイルでメモリを食うので、400MB超の単一ファイルではzcat | grepに分けた方が安定した。私が踏んだのは、iconvの変換結果をそのまま障害報告に貼り、件数が合わないと現地から指摘されたこと。変換は検索用で、証跡には使わないと決めてからは混乱が減った。

同じように、フランス側から届く圧縮ログで「検索できない」と感じたとき、文字コードを疑う前に何を確認していますか。

0
赞同度 100% · 0 条评论 · 3 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。