はじめに
先日に職場で「テキスト状態のログファイルと、gzipで圧縮されたログファイルの中から任意の文言を含むログを抽出したい」という話になりました。
特にエラーログを調査する時は、「gzipで圧縮されたログ」と「プレーンテキストのログ」の両方を確認することが多いため、その方法を記事にまとめてみました。
検証環境
- WSL2(Ubuntu 22.04.3 LTS)
zgrepによる検索
-
zgrep
コマンドを使うことで、プレーンテキストとgzipのログを合わせて検索できました。-
grep
コマンドと同じ使い方なので、直感的で分かりやすいです。
-
zgrepによる検索結果
nkojima@NKOJIMA-DESKTOP:~$ zgrep "error" /var/log/dmesg*
/var/log/dmesg:[ 1.211764] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
/var/log/dmesg.0:[ 4.531410] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
/var/log/dmesg.1.gz:[ 1.280337] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
/var/log/dmesg.2.gz:[ 0.729120] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
/var/log/dmesg.3.gz:[ 0.814380] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
/var/log/dmesg.4.gz:[ 0.742996] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
zgrepを使わないスクリプト
- 苦手なシェルスクリプトの学習用に、
zgrep
を使わないスクリプトを作ってみました。-
zgrep
を使わない場合、file
、grep
、zcat
などを組み合わせることになり、かなり面倒なことになりました💦
-
- 以下の
log_finder.sh
は、第1引数にログを探索するパス、第2引数にログ内で探す文言を指定します。- 例えば以下の表のような形で指定します。
第1引数 | 第2引数 | |
---|---|---|
/var/log/dmesg*にマッチするファイルから、errorを含む行を探す | "/var/log/dmesg*" | "error" |
/var/log/syslog*.gzにマッチするファイルから、warningを含む行を探す | "/var/log/syslog*.gz" | "warning" |
- ログファイルはテキストもしくはgzipで保存されていることがあるため、どちらにも対応させています。
-
file -i {ファイルパス}
でMIMEタイプを確認してから、cat
もしくはzcat
コマンドでファイルを開いて中身を確認しています。 - ここでは
grep -q {MIMEタイプの一部}
を使うことで終了ステータスコードだけを返させて、このステータスが0であれば引数のMIMEタイプであると判定しています。
-
- 結果の出力時には
grep -n
を使うことで、ログの行番号を合わせて出力しています。
log_finder.sh
#!/bin/sh
# 引数1: ログを探索するパス
# 引数2: ログ内で探す文言
target_path=$1
target_text=$2
echo "「${target_path}」にマッチするファイルから、「${target_text}」を含む行を抽出します..."
for file_path in $target_path;
do
echo "target_file: $file_path"
if echo `file -i $file_path` | grep -q "directory"; then
echo "This is a directory."
echo "" # 出力をファイル間で区切るための改行
continue
fi
if echo `file -i $file_path` | grep -q "gzip"; then
zcat $file_path | grep -n $target_text
else
cat $file_path | grep -n $target_text
fi
echo "" # 出力をファイル間で区切るための改行
done
echo "処理終了"
- 以下の実行結果では、先頭に記載した行番号は「line 〇〇」という形式で表記したかったのですが、面倒だったのでやめておきました💦
実行結果の例
nkojima@NKOJIMA-DESKTOP:~$ ./log_finder.sh "/var/log/dmesg*" "error"
「/var/log/dmesg*」にマッチするファイルから、「error」を含む行を抽出します...
target_file: /var/log/dmesg
418:[ 1.211764] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
target_file: /var/log/dmesg.0
427:[ 4.531410] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
target_file: /var/log/dmesg.1.gz
427:[ 1.280337] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
target_file: /var/log/dmesg.2.gz
425:[ 0.729120] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
target_file: /var/log/dmesg.3.gz
418:[ 0.814380] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
target_file: /var/log/dmesg.4.gz
418:[ 0.742996] kernel: EXT4-fs (sdc): mounted filesystem with ordered data mode. Opts: discard,errors=remount-ro,data=ordered. Quota mode: none.
処理終了
まとめ
-
zgrep
コマンドはプレーンテキスト/gzipのどちらも簡単に検索できるので、非常に便利です。 - 学習目的で
zgrep
コマンドを使わずに自作のスクリプトを作ってみたものの、コードが汚くて車輪の再発明にすらなりませんでした...