本番ログを持ち帰る前に — 開発環境とログの4つの摩擦

技術解説

ビルドログ、48万行。

落ちた理由は、そのどこかの1行です。スクロールバーを掴む前に、何をしますか。

詰まる場所は4つあります。どれも「ログを自分の環境に持ってきて読む」ときに起きる摩擦です。

CIのビルドログ、本番から持ち帰るダンプ、WSL越しのファイルアクセス、そしてチーム内の環境差。4つとも、ログの中身は何も悪くありません。悪いのはログと読む人のあいだにある経路です。

先に結論: UwView は48万行のビルドログでも80GBのダンプでも、分割せずに開いた瞬間から表示・検索できます。ファイル全体をメモリへ読み込まないので、読める大きさがRAMで決まりません。Pro は索引と圧縮を保存するので、同じファイルを2回目以降は行番号付きで瞬時に開き直せます(47.73GBのテキストで実測0.02〜0.07秒。特定環境での測定例で、環境により異なります)。処理はすべて手元のマシンで完結し、対象ファイルを外部へ送りません(詳細は記事末尾)


1. CIのビルドログが長すぎて、落ちた理由が見つからない

状況

パイプラインが赤くなりました。ブラウザでログを開きます。48万行。

ERROR で検索すると137件。先頭の1件に飛びますが、そこに書かれているのは「依存の解決に失敗した」という結果だけで、原因ではありません。スクロールしていくと、今度は同じログが3回繰り返されていることに気づきます。リトライです。

なぜ起きるか

CIのログは、人が読む形で書かれていないからです。理由が4つ重なります。

  • 並列ジョブのインターリーブ — 複数ジョブの出力が1本のストリームに混ざります。行は時系列ですが、文脈は時系列ではありません(第5回のスレッド混線と同じ形です)
  • ANSIエスケープ — 色付けの制御文字が本文に混ざるため、grep 'ERROR' が当たらないことがあります。[31mERROR は ERROR を含みますが、ERROR: のような前後一致を書いた正規表現は崩れます
  • 進捗バー — キャリッジリターンで上書きされる表示は、ファイルにすると1行が数MBになります。「48万行」の行数表示は、ここで嘘になります
  • リトライ — 同じ失敗が2回3回と記録され、どれが最初かが見た目で分かりません

そしてブラウザのログビューアは、多くの場合仮想スクロールで一部しか持っていません。Ctrl+F はロード済みの範囲にしか当たりません。「検索して出なかった」は「無い」ではありません。

汎用ツールでの対処と限界

生ログを落としてから整形するのが基本です。

# 1) CIのCLIで「生ログ」を取得する(ブラウザのビューアを経由しない)
#    → build-raw.log に保存

# 2) 色付けの制御文字を落とす(colorized-logs の ansi2txt が手軽)
ansi2txt < build-raw.log > build-plain.log

# 3) キャリッジリターンを改行に開く(進捗バーの1行が展開される)
tr '\r' '\n' < build-plain.log > build-lines.log

# 4) 最初の失敗だけを文脈つきで見る
grep -n -m 1 -B 20 -A 5 -E 'ERROR|FAIL' build-lines.log

コマンド名やオプションは使っているCIサービスと実装(GNU / BSD)で変わります。ansi2txt が入っていなければ sed や perl の置換でも落とせますが、エスケープ文字の書き方がシェルと実装で変わるので、手元の man で確認してください。

限界は3つ。

ひとつめ、整形するたびにファイルが増えること。build-raw → build-plain → build-lines と3本になり、そのうち行番号が一致しなくなります。CIのUIが「12,345行目」と言っても、整形後のファイルでは別の行です。

ふたつめ、保持期間。ログの保存期限は多くのサービスで数週間です。「先月も同じところで落ちていた気がする」を確かめたいときに、比較対象が消えています。

みっつめ、整形後も結局大きいこと。キャリッジリターンを展開すると行数は数倍に膨らみます。エディタで開こうとして固まる——第1回の壁にそのまま戻ります。


2. 本番でしか起きないバグ — 持ち帰りには2つの制約が同時にかかる

状況

開発環境では再現しません。本番のログをもらうことにします。

返ってきた見積りは80GB。転送に1時間、手元のSSDの空きは60GB。そして運用チームから「そのログ、個人情報が入っていますよ」と言われます。

なぜ起きるか

サイズと機密という、性質の違う2つの制約が同時にかかるからです。しかも片方を解く手が、もう片方を悪化させます。

サイズを解こうとすると、絞るか分けるかになります。ところが絞る条件は、原因が分かってから決まるものです。分からないから持ち帰るのに、持ち帰る前に条件を要求される——これが順序の矛盾です。実務では「とりあえず grep で当日分だけ」と絞り、あとで「その外に答えがあった」と気づきます。

機密を解こうとすると、マスキングになります。こちらは不可逆です。メールアドレスを伏せ字に潰したあとで「同一人物の2回の操作を突き合わせたい」となっても、潰した先からは戻れません。しかもマスキングの正規表現は、漏らすか壊すかのどちらかに転びます。漏らせば持ち出し事故、壊せばJSONがパースできなくなります。

汎用ツールでの対処と限界

# 転送は圧縮したまま(ネットワークが細いときは、転送時圧縮より事前圧縮が確実)
gzip -c app.log > app.log.gz
# あとは普段使っている転送手段で app.log.gz を開発機へ送る

# 絞る場合は「絞った条件」をファイル名に残す
grep -E '2026-09-1[01]' app.log > app-20260910-11.log

# マスキングは可逆にできない。せめて元を残した上でコピーにかける
sed -E 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+/MASKED/g' app.log > app-masked.log

限界は3つ。

ひとつめ、圧縮して置くと検索が遅くなること。80GBが9GBになっても、zgrep は毎回展開しながら走ります(第8回)。

ふたつめ、分けると座標が消えること。split した断片の1行目は「1行目」で、原本の何行目かは分かりません。第16回に書いた「切り出しが壊す3つのもの」が、ここでもそのまま起きます。

みっつめが本質です。持ち出しの可否は、サイズではなく経路の問題だということ。ローカルに置いて自分のマシンだけで読むのと、クラウドのログ解析サービスへ投げるのでは、審査の重さがまったく違います。手元で完結する道具を使うなら、議題は「どこへ送るか」ではなく「どこに置くか」だけになります。


3. WSL越しに30GBを読むと、なぜか10倍遅い

状況

Windows側に置いた30GBのログを、WSL の grep で調べます。

Linux サーバなら2分で終わる処理が、20分経っても終わりません。CPUは暇で、ディスクのランプも落ち着いています。どこで待っているのか分かりません。

なぜ起きるか

OSの境界を越えるファイルアクセスには、1回ごとの通信コストがあるからです。

WSL2 から見える Windows 側のドライブは、Windows のファイルシステムをプロトコル越しにマウントしたものです(既定では 9P)。読み出しは1回ごとにホスト側へのラウンドトリップになり、小さな read を大量に発行する処理ほど不利になります。逆方向——Windows のツールから WSL 側のファイルを読む場合も同じ構図です。

ここで効くのは転送量ではなく回数です。grep のような逐次走査は大きめの単位で読むので比較的マシですが、行単位で読み戻すような処理、ファイルの末尾付近を何度も往復する処理は、回数が増えるぶんそのまま遅くなります。WSL1 と WSL2 でも挙動が違い、バージョンによっても変わります。

汎用ツールでの対処と限界

いちばん効くのは、境界を越えさせないことです。

# WINLOG = Windows側に置いたログのパス(WSLから見えるマウント先)

# Linux側のネイティブFSへコピーしてから処理する
cp "$WINLOG" ~/work/app.log

# あるいは、境界を越える量そのものを減らす(圧縮してから渡す)
gzip -c "$WINLOG" > ~/work/app.log.gz

WSL の設定ファイル(wsl.conf)のマウントオプションやメタデータ設定で改善する余地もありますが、効果は構成依存です。

限界は2つ。

ひとつめ、コピーは容量を2倍使い、そのコピー自体に時間がかかること。30GBを移す数分を、調査のたびに払います。

ふたつめ、Windows側で読めば境界を越えないが、こんどは道具がないこと。メモ帳は数GBで沈黙し(第1回)、grep も less も標準では入っていません。だから WSL に戻る——この往復が問題の正体です。つまりこれは性能の問題ではなく、どちらのOS側に読む道具があるかという配置の問題です。


4. 「このログ、俺のPCだと開けたよ」

状況

30GBのログを渡された同僚が、開けないと言います。あなたのデスクトップでは開けました。

メモリ64GBと16GBの差です。結果として、ログ調査がメモリを積んだ1人に集まります。その人が休暇のあいだ、調査は止まります。

なぜ起きるか

「全部メモリに読む」前提の道具を使っていると、読める上限がRAMで決まるからです。上限がマシンごとに違えば、チームの能力はいちばん低いマシンではなく、いちばん高いマシンを持つ1人に依存する形になります。

もうひとつ、道具がバラバラだと言葉が共有できません。「12,034,541行目を見て」と言っても、相手の道具が \r を改行として数えていれば、別の行が表示されます。BOM、UTF-16、改行コードの違いでも行番号はズレます(第3回・第11回)。行番号は共通語のつもりで使われますが、道具が違えば共通語になりません。

汎用ツールでの対処と限界

定番は、共有サーバに全員で ssh して less で読む形です。ログを外に出さずに済み、環境差も消えます。

限界は3つ。

ひとつめ、遅延。画面の描画が往復ごとに待たされるので、目で追う調査には向きません。リモートワークだとさらに重くなります(ネタ帳の「画面共有しながらログを追うつらさ」はここです)。

ふたつめ、残らないこと。色分け、ブックマーク、検索条件——less を閉じれば全部消えます。引き継ぎの単位が「口頭の説明」になります(第13回で触れた再開の話と同じ問題です)。

みっつめ、1台に並ぶこと。2人が同時に数十GBを走査すれば、そのサーバのI/Oを奪い合います。

結論は、環境を揃えるとはRAMを揃えることではなく、RAMに依存しない道具を揃えることです。16GBのノートでも開けるなら、誰が開いても同じ行番号になり、調査は1人に集まりません。


4つに共通していたもの

摩擦 どこで詰まるか 直接の原因 汎用ツールでの対処 残る問題
CIのビルドログ ブラウザのビューア 並列混線・ANSI・進捗バー・リトライ 生ログを落として ansi2txt/tr で整形 整形のたびに行番号がズレる。整形後も大きい
本番の持ち帰り 転送と審査 サイズと機密が同時にかかる 圧縮転送・grep で絞る・マスキング 絞る条件は原因が分かってから決まる。マスキングは不可逆
WSL越しの読み出し OSの境界 アクセス回数ぶんのラウンドトリップ ネイティブFSへ cp してから処理 容量2倍とコピー時間。Windows側に道具がない
チームの環境差 読む人のマシン 読める上限がRAMで決まる 共有サーバに ssh して less 遅延・何も残らない・1台に並ぶ

4つとも、ログを加工してから読むか、ログのある場所まで出向いて読むかの二択に追い込まれています。そして加工すれば行番号が変わり、出向けば何も残りません。

だから必要な条件は3つに整理できます。

  • 読める大きさがRAMで決まらない — 4章の環境差は、ここが満たされた時点で消えます。1章・2章の「整形して小さくする」も不要になります
  • 原本をそのまま読める — 分割もマスキングも整形もしないまま開けること。2章の不可逆な判断を、あとに回せます
  • 手元で完結する — 2章の審査の議題が「どこへ送るか」から「どこに置くか」に変わります。3章も、ファイルの置き場所だけの問題になります

冒頭の48万行に戻ります。あれは「長すぎて読めない」のではありません。読む前に整形させられることで、行番号という唯一の座標を失っていただけです。


使っている道具

私が開発している UwView(無料)は、巨大なテキストを開いた瞬間から表示・スクロール・検索できるビューアです。ファイル全体をメモリへ読み込まないので、RAMより大きいファイルでも開けます。索引はバックグラウンドで作られ、完成すると行番号が付きます。

上の3条件のうち、1つめと2つめは無料版がそのまま満たします。

  • 読める大きさがRAMで決まりません。 16GBのノートでも数十GBのファイルを開けます(無料版での実測上限は47.73GB・約8.9億行。特定環境での測定例です)。4章の「俺のPCだと開けた」が起きる前提そのものが消えます
  • 原本に書き込まず、分割も切り出しもしません。 1章の整形の中間ファイルを作らずに開けるので、行番号がCIのUIと一致したままです。2章の「とりあえず絞る」も後回しにできます
  • Windows / macOS / Linux で同じものが使えます。 3章の「どちらのOS側に道具があるか」が選べるようになります。Windows 側のログを Windows 側の道具で読めば、境界を越える往復は発生しません
  • 処理はすべて手元のマシンで完結します。 対象ファイルを外部へ送りません。2章の持ち出し審査では、ここが前提条件になることがあります
  • 文字コードは開いたまま切り替えられます(UTF-8 / Shift-JIS(CP932) / EUC-JP / UTF-16 を自動判定)。iconv を挟む中間ファイルが増えません(第3回)
  • ハイライトは行を消さずに色を付けます。 1章の並列混線を、ジョブ名で色分けして目で解けます(第5回)

3つめに関係する機能と、繰り返し開く場面は UwView Pro の領分です。

  • 索引と圧縮を保存する: 一度開いたファイルは2回目以降行番号付きのまま瞬時に開き直せます(47.73GBのテキストで実測0.02〜0.07秒。特定環境での測定例で、環境により異なります)。2章で持ち帰ったダンプは、報告書を書く日、レビューで差し戻された日、似た障害が再発した日と、何日にもわたって開き直します
  • 約1/9で保管しつつ検索できる: 2章の「手元のSSDに入らない」に直接効きます。圧縮キャッシュ経由で検索できるので、zgrep のように毎回展開しながら走る必要がありません(第8回)
  • 多段階検索(ドリルダウン): 絞り込んだ結果をさらに別の語で絞れます。原本の行番号は最後の段まで保持されます。2章の「絞る条件は原因が分かってから決まる」に対して、原本を絞らずに視点だけを絞る形で答えられます(多段階検索の記事)
  • ±N は段ごとに独立: 絞る段は±1、読む段は±20。1章の「-B 20 では足りないと分かってから grep をやり直す」が消えます(無料版は±1固定、可変の±N は Pro)
  • シーケンシャル検索: w1 → w2 → w3 がこの順に現れる箇所だけを拾います。1章の「リトライで同じ失敗が3回記録されている」ログから、最初の1回の並びを条件にできます(実装記事)。正直に書くと、各段は前段の位置から本文を走査するので、所要時間は全文検索と同程度かかります
  • 検索条件や色分けを保存して渡せる: 4章の「less を閉じると全部消える」に効きます(アーカイブ×セッション復元の記事)

正直な限界

UwView はビューアです。CIのログ収集基盤でも、ログ集約サービスでもありません。

  • 1章のANSIエスケープ除去・進捗バーの折りたたみはしません。前処理が必要なら sed と tr はあなたの仕事です
  • CIのAPIからログを取ってくる機能もありません。CIのCLIは別途必要です
  • 2章のマスキングはしません。個人情報の扱いは各組織の規程に従ってください
  • 3章のI/Oペナルティは、道具では消えません。ファイルをどちらのOS側に置き、どちら側の道具で読むかの配置で解く問題です
  • リアルタイムの追従監視、アラート、複数ログの自動突き合わせ——いずれもありません
  • 対象はテキストです。バイナリのダンプやコアダンプは扱えません

参考までに、非破壊の差分編集(Edit Upgrade)は別ライセンスとして存在しますが、この記事の4項目はすべて読み取りだけの仕事です。ここで要るのは View 側です。

コマンドラインから同じことをする

v1.6.0 で uvp コマンドが付きました(無料版には uvf)。GUI と同じ .uwvz を使うので、CLI で作った索引はそのまま GUI でも効きます。この記事の4章に対応させると、こう書きます。

# 1章: 整形前の生ログのまま、失敗の前後20行を読む(中間ファイルを作らない)
uvp build-raw.log -E 'ERROR|FAIL' -C 20

# 1章の続き: リトライで3回出る失敗を、ジョブ名で絞ってから読む
uvp build-raw.log -E 'ERROR|FAIL' 'job=integration-test' -C 20

# 2章: 持ち帰った80GBのダンプは、.uwvz のまま展開せずに探せる
uvp app.log.uwvz 'request_id=7f3a'

# 3章: 境界を越えないよう、Windows 側のログは Windows 側の uvp で読む
uvp D:\logs\app.log 'Timeout' -C 5

# 4章: 同じ .uwvz を渡せば、誰のマシンでも同じ行番号の同じ結果になる
uvp app.log.uwvz 'connection reset' -out shared-hits.txt

終了コードは grep と同じ 0=あり・1=なしに、2=上限に当たって打ち切った(既定は無制限。-limit N で上限を決めたときだけ)が加わります。if uvp build-raw.log 'OutOfMemoryError'; then がそのまま書けるので、CIのジョブやチームの調査スクリプトにそのまま混ぜられます。無料版の uvf でも答えと終了コードは同じなので、4章の「環境を揃える」をスクリプト側から始められます(ただし uvf は索引を持たないので速くはありません)。

正直に書くと、1問目は uvp が ripgrep より少し遅くなります——.uwvz(圧縮+索引)を先に作るぶんで、50GB なら 59.0秒 対 54.9〜55.8秒=6〜7%。v1.6.6.1 で「作ってから探し直す」のをやめ、作りながら探すようにしたぶん 6.7秒 縮みました。効いてくるのは2問目からで、同じ 50GB の検索が 6.6秒、ripgrep の 55〜57秒に対して 8.4倍です。3GB のような小さいファイルでは同等——索引を引く意味が薄くなります。無料の uvf は、どのサイズでも ripgrep と同等です(実測記事。Mac M4・外付けUSB SSD・OpenStreetMap XML での測定例で、環境により異なります)。

そして、ストレージを専有している巨大ログを圧縮して保管し、さらに高速に検索したいなら UwView Pro をどうぞ。永続索引・圧縮キャッシュ検索・約1/9保管で、開き直しも検索も一段速くなります(全OS対応・買い切り/月額プランあり)。

リンク

  • 第1回: 巨大ファイルに沈む4つの定番ツールと、その先: https://uvp.y42u.net/blog/uwview-ps01-huge-file-tool-limits/
  • 第3回: 文字コード4つの罠と切り分け手順: https://uvp.y42u.net/blog/uwview-ps03-japanese-encoding-traps/
  • 第5回: 開発ログとの正しい付き合い方4選: https://uvp.y42u.net/blog/uwview-ps05-debug-log-practices/
  • 第8回: 圧縮保管と検索の両立: https://uvp.y42u.net/blog/uwview-ps08-compressed-archive-search/
  • 第11回: レガシー文字コードを2026年に読む: https://uvp.y42u.net/blog/uwview-ps11-legacy-encoding-euc-utf16/
  • 第13回: 巨大データ検品の4技法: https://uvp.y42u.net/blog/uwview-ps13-huge-data-inspection/
  • 第15回: コマンドライン職人芸の限界線4本: https://uvp.y42u.net/blog/uwview-ps15-cli-craft-limits/
  • 第16回: 保全・切り出し・改ざん対策の4原則: https://uvp.y42u.net/blog/uwview-ps16-log-as-evidence/
  • uvp コマンドを付けました(ripgrep との実測比較): https://uvp.y42u.net/blog/uvp-cli-release-vs-ripgrep/
  • 絞り込んだ先からさらに絞り込む(多段階検索): https://uvp.y42u.net/blog/uvp-drilldown-search/
  • その順に現れる箇所だけを探す(シーケンシャル検索): https://uvp.y42u.net/blog/uvp-sequence-search/
  • アーカイブ×セッション復元の実務フロー: https://uvp.y42u.net/blog/uwview-archive-session-restore-workflow/
  • ソースコード(GitHub): https://github.com/amru195704/UwView

開発者より: アプリ・Kindle本・公開プロジェクトの一覧は GitHub: amru195704 にまとめています。


お願い
本記事の情報は参考目的で掲載しており、正確性・完全性を保証するものではありません。本番データの持ち出し・個人情報のマスキング・ログの保管は、各組織の規程および適用される法令に従ってください。記事中の行数・容量・ファイル名はすべて説明のための例であり、特定の事案を指すものではありません。sed・tr・grep・gzip・cp 等の挙動は実装(GNU/BSD/busybox)・バージョン・ビルドオプションにより異なり、CIサービスのCLIやログ保持期間も提供元の仕様変更で変わります。WSL のファイルアクセス性能はバージョン(WSL1/WSL2)・Windowsのビルド・マウント設定・ウイルス対策ソフトの有無により大きく変わるため、本文の記述は傾向の説明であって特定の数値を保証するものではありません。オプション名や既定値は必ず手元の man および公式ドキュメントで確認してください。実測と明記した数値も特定の1環境での測定例であり、同じ結果を保証するものではありません。誤記・不正確な情報がございましたら、コメント欄よりご指摘いただければ、確認のうえ修正いたします。

タイトルとURLをコピーしました