こんにちは、インフラエンジニアのryuです。
/etc/logrotate.d/ に設定を置いたのに、アプリのログがどんどん大きくなっていく。そんな経験はないでしょうか。
あるいは、ローテートはされているのに、なぜか app.log.1 のほうにログが書き込まれ続けている。新しい app.log は空っぽのまま、という状態です。
logrotateは、設定ファイルを書けば終わりのように見えます。ところが実際には、いつ動くのか、何を基準にローテートを判断するのか、ローテートのあとアプリがどのファイルに書くのか、という3つの仕組みが関わっています。
今日は、logrotateがうまく効かないときに、どこから順番に確かめればよいかを整理します。ディスクがあふれたときの調べ方はディスクが100%になったときの切り分けの記事で解説しているので、今回はその手前、ログを増やしすぎないための仕組みの話です。
logrotateは、いつ・誰が動かしているのか?¶
まず押さえておきたいのは、logrotateは常駐しているプログラムではない、ということです。
logrotateのマニュアルには、通常は毎日のcronジョブとして、またはsystemdを使う環境では logrotate.timer によって実行されると書かれています。つまり、1日に1回起動されて、そのときに条件を満たしたログだけをローテートして終了します。
systemdの環境なら、次のコマンドで最後にいつ動いたか、次にいつ動くかが分かります。
# タイマーの次回・前回の実行時刻を確認する
systemctl list-timers logrotate.timer
# 直近の実行結果(エラーが出ていないか)を確認する
systemctl status logrotate.service
journalctl -u logrotate.service --since "3 days ago"
logrotateの公式リポジトリにあるタイマーのサンプルでは、OnCalendar=daily に加えて RandomizedDelaySec=1h と Persistent=true が指定されています。日付が変わってからランダムに最大1時間ずれて動き、電源が落ちていて実行を逃した場合は次の起動時に実行される、という設定です。
cronで動かしている環境では、/etc/cron.daily/logrotate にスクリプトが置かれていることが多いです。どちらで動いているかはディストリビューションによって違うので、両方確認しておくと安心です。
cronとsystemd timerの違いについては、cronとsystemd timerの使い分けの記事で詳しく解説しています。
1日1回しか動かないことの意味¶
ここで大事なのは、logrotateが1日1回しか動かないなら、設定に size 100M と書いても、100MBを超えた瞬間にローテートされるわけではない、という点です。
1日に5GB出力されるログなら、次にlogrotateが動くまでに5GBまで育ってしまいます。サイズの条件は、logrotateが起動したときに判定されるだけです。
マニュアルにも、hourlyでローテートしたいなら、logrotate自体を1時間ごとに動かすように設定を変える必要がある、と書かれています。
ローテートされないときに、最初に確認すること¶
ローテートされない原因を調べるとき、いきなり設定ファイルを書き換えるのはおすすめしません。まずは、logrotateが今の設定をどう解釈しているかを見ます。
-d でドライランして、判断の理由を読む¶
logrotateには -d(--debug)というオプションがあります。マニュアルでは、デバッグモードではログに一切変更を加えず、状態ファイルも更新しない、と説明されています。
# 特定の設定だけをドライランする(実際のローテートはされない)
sudo logrotate -d /etc/logrotate.d/myapp
出力には、対象のファイルごとにローテートが必要かどうかの判断が表示されます。よく見かける出力は次のようなものです。
considering log /var/log/myapp/app.log
Now: 2026-09-30 10:15
Last rotated at 2026-09-30 00:00
log does not need rotating (log has been rotated at 2026-09-30 00:00, which is less than a day ago)
daily の設定なら、前回のローテートから1日たっていないので今回は見送る、という判断です。size を使っている場合は、log size is below the 'size' threshold のように、サイズが基準に届いていないことが理由として表示されます。
log does not need rotating と出ていれば、logrotateは動いているけれど、条件を満たしていないと判断していることが分かります。逆に、対象のファイル名がそもそも出てこなければ、パスの書き間違いやワイルドカードの指定ミスを疑います。
状態ファイルを確認する¶
logrotateは、各ログを最後にいつローテートしたかを状態ファイルに記録しています。Ubuntuのマニュアルでは、既定の状態ファイルは /var/lib/logrotate/status と書かれています。
# 対象のログが最後にいつローテートされたかを確認する
sudo grep myapp /var/lib/logrotate/status
ディストリビューションによってはファイル名が違うことがあるので、見つからないときは man logrotate の FILES の項目を確認してください。
この状態ファイルには、意外な落とし穴があります。マニュアルによると、logrotateは初めて見るログについては、現在時刻を前回のローテート時刻として記録します。そのため、daily や weekly といった時間の条件は、初回の実行では満たされないことがあります。
設定を追加した翌日にローテートされていなくても、慌てる必要はありません。状態ファイルに記録された時刻から、条件の期間が過ぎるのを待つことになります。
よく見かけるエラーと原因¶
ドライランや journalctl の出力にエラーが出ている場合は、次の表を目安にしてください。
| 症状・メッセージ | 考えられる原因 | 確認すること |
|---|---|---|
| 対象のファイル名が出力に出てこない | パスやワイルドカードの書き間違い | ls で同じパターンを展開してみる |
log does not need rotating |
期間やサイズの条件を満たしていない | 状態ファイルの時刻と size 系の設定 |
parent directory has insecure permissions |
ログのディレクトリが root 以外のグループやその他のユーザーから書き込める | su ディレクティブで実行ユーザーを指定する |
error: ... No such file or directory |
ログファイルが存在しない | missingok を付けるか、パスを見直す |
| 設定を足したのに初日にローテートされない | 初回は現在時刻が前回ローテート時刻として記録される | 翌日以降の動きを確認する |
3行目のメッセージは、logrotateのソースコードにそのまま書かれているもので、su ディレクティブでローテートに使うユーザーとグループを指定するように案内しています。アプリ専用のユーザーがログのディレクトリを所有している場合によく出ます。
ローテートされたのに、古いファイルに書き込まれ続けるのはなぜ?¶
次は、ローテート自体は成功しているのに、アプリが app.log.1 に書き続けてしまうケースです。これはlogrotateの問題というより、Linuxのファイルの扱い方が関係しています。
多くのアプリは、起動時にログファイルを開き、そのまま開きっぱなしで書き込みを続けます。このとき、アプリが握っているのはファイル名ではなく、ファイルそのもの(inode)です。
logrotateの既定の動きは、app.log を app.log.1 に名前を変えることです。名前が変わっても、中身のファイルは同じです。
ファイル名を変えても、アプリが開いているファイルは変わらない。だから、名前を変えたあとの
app.log.1に書き込みが続く。
実際に確認してみると、よく分かります。
# アプリのプロセスがどのファイルを開いているかを見る
sudo ls -l /proc/$(pgrep -o myapp)/fd | grep log
# 出力例: 名前を変えたあとのファイルを握ったままになっている
# l-wx------ 1 myapp myapp 64 Sep 30 10:20 3 -> /var/log/myapp/app.log.1
この問題を解決するには、ローテートのあとにアプリにログファイルを開き直してもらうか、名前を変えずにファイルの中身を切り詰めるかのどちらかが必要です。前者が create と postrotate、後者が copytruncate です。
create と postrotate でログを開き直させる¶
create は、ローテートの直後に同じ名前で新しいログファイルを作るオプションです。マニュアルでは、postrotate のスクリプトが実行される前に作られる、と説明されています。
ただし、新しいファイルを作っただけでは、アプリは古いファイルを握ったままです。そこで、postrotate でアプリにログを開き直させます。マニュアルの例では、Apacheに対して次のように書かれています。
"/var/log/httpd/access.log" /var/log/httpd/error.log {
rotate 5
mail recipient@example.org
size 100k
sharedscripts
postrotate
/usr/bin/killall -HUP httpd
endscript
}
sharedscripts は、対象のログが複数あっても、postrotate のスクリプトを1回だけ実行するためのオプションです。これがないと、ログの数だけアプリの再読み込みが走ります。
どのシグナルやコマンドでログを開き直すかは、アプリによって違います。アプリのドキュメントで、ログファイルを開き直す方法を確認してから書くようにしましょう。
copytruncate の使いどころと注意点¶
アプリにログを開き直させる方法がない場合に使うのが copytruncate です。元のファイルをコピーしてから、元のファイルの中身を0バイトに切り詰めます。
アプリは同じファイルを握ったままなので、開き直しは不要です。その代わり、マニュアルには、コピーしてから切り詰めるまでのごく短い時間に書かれたログは失われる可能性がある、と明記されています。
もう一つ、copytruncate を使うと create は効かなくなります。元のファイルがそのまま残るからです。
2つの方法の違いを表にまとめます。
| 項目 | create + postrotate | copytruncate |
|---|---|---|
| 元のファイル | 名前を変えて退避し、新しく作る | そのまま残し、中身を切り詰める |
| アプリ側の対応 | ログを開き直す仕組みが必要 | 不要 |
| ログの欠落 | 基本的に起きない | コピーと切り詰めの間の分が失われうる |
| 大きなログの場合 | 名前を変えるだけなので速い | コピーの分だけ時間とディスクを使う |
| 向いている場面 | 開き直しの方法が用意されているデーモン | 開き直しができないアプリ |
基本は create と postrotate を使い、どうしても開き直せないアプリにだけ copytruncate を使う、と考えるのがよいと思います。
delaycompress を付ける理由¶
圧縮を有効にしていると、もう一つ問題が起きることがあります。ローテート直後の app.log.1 を即座に圧縮してしまうと、まだそのファイルに書き込んでいるアプリがあった場合に困るのです。
マニュアルでは delaycompress について、直前のログの圧縮を次のローテートまで遅らせるオプションで、ログファイルを閉じるように指示できないプログラムがしばらく古いファイルに書き込み続ける場合に使える、と説明されています。compress と組み合わせたときだけ意味があります。
古いログが残らない・消えないときは rotate の値を見る¶
ローテートは動いているのに、振り返りたい日のログがもう残っていない。そんなときは、rotate の値を確認します。
マニュアルによると、rotate に指定した回数だけローテートされたあと、古いファイルは削除されます。0を指定すると古い世代は残らずに削除され、既定値も0です。
つまり、rotate を書き忘れた設定では、ローテートした古いログが残りません。daily と rotate 7 なら約1週間分、weekly と rotate 4 なら約4週間分が残る、と考えると分かりやすいと思います。
逆に -1 を指定すると、maxage の指定がない限り古いログは削除されません。マニュアルでも、性能やディスク容量を無駄にするおそれがあるので注意して使うように書かれています。
保存期間は、障害調査やセキュリティの要件から逆算して決めるものです。セキュリティの規程で保存期間が決まっている場合は、そちらに合わせて rotate の値を決めましょう。
size・minsize・maxsize の違いを整理する¶
サイズの指定にも、混同しやすい3つのオプションがあります。マニュアルの説明をもとに整理すると、次のようになります。
| オプション | 動き |
|---|---|
size |
期間の条件とは排他で、サイズを超えていれば前回のローテート時刻に関係なくローテートする |
minsize |
サイズを超えていても、daily などの期間が過ぎるまではローテートしない |
maxsize |
期間が過ぎていなくても、サイズを超えていればローテートする |
たとえば「毎日ローテートしたいが、急にログが増えた日は途中でも切りたい」なら、daily と maxsize の組み合わせになります。ただし先ほど書いたとおり、判定はlogrotateが起動したときだけです。途中で切りたいなら、logrotateを1日に複数回動かす設定が別に必要になります。
設定を変えたあとは、-d でドライランしてから、必要に応じて -f(--force)で強制的にローテートして動きを確かめます。
# 変更後の設定をドライランで確認
sudo logrotate -d /etc/logrotate.d/myapp
# 問題なければ強制ローテートし、詳細を表示して確認
sudo logrotate -v -f /etc/logrotate.d/myapp
# アプリが新しいファイルに書いているかを確認
sudo ls -l /proc/$(pgrep -o myapp)/fd | grep log
-f は本番のログを実際に動かします。検証環境で先に試すか、作業として手順を決めてから実行するようにしてください。
ログの出力先そのものを調べたい場合は、syslogの設定方法の記事も参考になると思います。
Linuxの運用を体系的に学び直すなら¶
logrotateのトラブルは、ファイルとinode、プロセスとファイルディスクリプタ、cronやsystemd timerといった、Linuxの基本的な仕組みがいくつも重なって起きます。一つひとつは単純でも、つながりが見えていないと原因にたどり着きにくい分野です。
InfraAcademyでは、Linuxのファイルやプロセス、ログの扱いを、実際に手を動かしながら順番に学べるLinuxのロードマップを用意しています。現場で断片的に覚えてきた知識を、つなげて整理したいときに使ってみてください。
まとめ¶
今日は、logrotateがうまく効かないときの確かめ方を解説しました。要点を振り返ります。
- logrotateは常駐せず、通常は1日1回、cronか
logrotate.timerで起動される - サイズの条件も、logrotateが起動したときにしか判定されない
- 原因調査は、
-dのドライランと状態ファイルの確認から始める - 古いファイルに書き込まれ続けるのは、アプリがファイル名ではなくファイルそのものを握っているから
- 基本は
createとpostrotateで開き直させ、できないときだけcopytruncateを使う
ログは、障害のときに頼りになる一方で、放っておくとディスクをあふれさせる原因にもなります。今日の手順で、自分の担当サーバーの設定を一度ドライランしてみてください。



