2022/05/25 8:53追記
そもそもログファイルを管理するlogrotate
コマンドが存在していて、こいつが全部できるみたい。設定のデバッグもできるらしい。すごい。
はじめに
業務で自社の提供するサーバーアプリケーションの負荷検証をすることになった。EC2インスタンスをもらって検証してみたけど、開発中だからなのかすごい勢いでログファイルがでかくなる。1時間でGB単位でかくなる。ストレージをでかくしてもらってもいいけどこれではきりがない。
そこでcronで定期的にログを圧縮しつつまとめればいいのではと思った。多分いろんな前例があると思うけどまぁいい。
やりたいこと
アプリケーションの動作中はこういう感じで1時間ごとのいろいろなログが吐かれる。
[yume_yu@server]$ ls
HOGA_20220524_20.log HOGA_20220524_21.log
HOGE_20220524_20.log HOGE_20220524_21.log
...
これを1時間ごとに圧縮して決まったディレクトリの保存したい。かつ、圧縮と一緒に元ファイルも消したい。
検証環境
$ cat /etc/redhat-release
CentOS Linux release 8.5.2111
いつのまにかサポート切れてたCentOS 8
本番はRedHadEnterpriseだから...
調べてみた
tarコマンド
まずはファイルを圧縮しつつ削除しなくては。圧縮といえばtar。調べるとこんな記事が見つかった。
tar/zipしたあと元ファイルを削除 – Siguniang's Blog
どうやら--remove-file
というオプションがあるらしい。たしかに$man tar
にもこうある。
--remove-files
Remove files from disk after adding them to the archive.
やってみたらこうなった。予想通りでいいかんじ。
[yume_yu@server]$ ls
delete me please
[yume_yu@server]$ tar --remove-file -zcvf archive.tar.gz ./*
./delete
./me
./please
[yume_yu@server]$ ls
archive.tar.gz
dateコマンド
ログファイルの名前には必ず日付と時刻が入ってる。日付といえばdateコマンド、だけどほしいのは今じゃなくて1時間前の時間。と思ったらdateコマンドは-dオプションで相対的な時間の指定もできるらしい。
date コマンド | コマンドの使い方(Linux) | hydroculのメモ
ほんまか?と思いつつ試す。
[yume_yu@server]$ date "+%Y/%m/%d-%H:%M"
2022/05/25-00:46
[yume_yu@server]$ date '+%Y/%m/%d-%H:%M' -d '1 hour'
2022/05/25-01:46
[yume_yu@server]$ date '+%Y/%m/%d-%H:%M' -d '2 hours'
2022/05/25-02:46
[yume_yu@server]$ date '+%Y/%m/%d-%H:%M' -d '1 hour ago'
2022/05/24-23:46
[yume_yu@server]$ date '+%Y/%m/%d-%H:%M' -d '-2 hour'
2022/05/24-22:46
ほんとだった。
やってみよう
これらを合体させてcronで回すべきコマンドを作ってみる。とりあえず今回はn時5分にn-1時台のログをまとめる想定でいく。
[yume_yu@server]$ date '+%Y%m%d_%H'
20220525_01
[yume_yu@server]$ ls
FUGALOG_20220525_00.log FUGALOG_20220525_01.log
HOGALOG_20220525_00.log HOGALOG_20220525_01.log
HOGELOG_20220525_00.log HOGELOG_20220525_01.log
[yume_yu@server]$ ls | grep $(date '+%Y%m%d_%H' -d '1 hour ago') | xargs tar --remove-file -zcvf $(date '+LOGS_%Y%m%d_%H.tar.gz' -d '1 hour ago')
FUGALOG_20220525_00.log
HOGALOG_20220525_00.log
HOGELOG_20220525_00.log
[yume_yu@server]$ ls
FUGALOG_20220525_01.log HOGALOG_20220525_01.log HOGELOG_20220525_01.log LOGS_20220525_00.tar.gz
うーんいい感じ。あとはcron用にする。
# 平日の7~22時のn時5分に実行する
5 7-22 * * 1-5 cd {log_dir_path}; ls | grep $(date '+%Y%m%d_%H' -d '1 hour ago') | xargs tar --remove-file -zcvf $(date '+{archive_dir_path}/LOGS_%Y%m%d_%H.tar.gz' -d '1 hour ago')
これでよし。テストとして現在時刻(01:22)に動作するようにしてやってみた。
[yume_yu@server test_tar_ball]$ ls
FUGALOG_20220525_00.log FUGALOG_20220525_01.log HOGALOG_20220525_00.log HOGALOG_20220525_01.log HOGELOG_20220525_00.log HOGELOG_20220525_01.log
[yume_yu@server test_tar_ball]$ date
2022年 5月 25日 水曜日 01:21:49 JST
[yume_yu@server test_tar_ball]$ date
2022年 5月 25日 水曜日 01:22:08 JST
[yume_yu@server test_tar_ball]$ ls
FUGALOG_20220525_00.log FUGALOG_20220525_01.log HOGALOG_20220525_00.log HOGALOG_20220525_01.log HOGELOG_20220525_00.log HOGELOG_20220525_01.log
当然です。なぜならcrontabでは%
はエスケープが必要だから...
crontab(5) を確認すると以下の記述がありました。
その行のコマンド部(改行文字または % 文字まで)が /bin/sh (またはその crontab ファイルの SHELL 環境変数で指定されたシェル)によって実行される。
コマンド中にパーセント記号 (%) がバックスラッシュ () によってエスケープされずに置かれていると、改行文字に置き換えられ、最初に現れた % 以降の全てのデータは標準入力としてコマンドに送られる。出典: crontab ではパーセント記号をエスケープする | はったりエンジニアの備忘録
https://blog.manabusakai.com/2013/05/crontab-escape-percent/
こういうことを避けるために実行ファイルにする。もちろん実行権限の付与も忘れずに。
#!/bin/bash
LOG_DIR={log_dir_path}
ARCHIVE_DIR={archive_dir_path}
cd $LOG_DIR
ls | grep $(date '+%Y%m%d_%H' -d '1 hour ago') | xargs tar --remove-file -zcvf $(date "+$ARCHIVE_DIR/LOGS_%Y%m%d_%H.tar.gz" -d '1 hour ago')
# 平日の7~22時のn時5分に実行する
5 7-22 * * 1-5 /path/to/compress_log.sh
結果
これでうまく行った。めでたし。
[yume_yu@server]$ ls
FUGALOG_20220525_01.log HOGALOG_20220525_01.log HOGELOG_20220525_01.log
[yume_yu@server]$ ls ../archive/
LOGS_20220525_00.tar.gz