Linux のログ:journalctl、/var/log、rsyslog、logrotate
最近の Linux ディストリビューションでは、journald がログを集め、journalctl で読みます。journalctl -u nginx は1つのサービスのログを表示し、-f はリアルタイムの流れを表示し、--since と -p で時刻と重要度を絞り込めます。テキストのログは /var/log に保存され、rsyslog が書き込むか、アプリケーションが直接書きます。logrotate は古いファイルを圧縮・削除し、ディスクが満杯になるのを防ぎます。
サービスが夜中に停止したとき、原因は多くの場合ログに残っています。問題はどこを見るかです。Ubuntu、Debian、RHEL、Fedora、Arch などの最近のディストリビューションでは、journald がイベントを集め、journalctl で読みます。同時に多くのプログラムが /var/log に通常のテキストファイルを書き、そのサイズは logrotate が管理します。ここでは、journalctl と Linux のログの実践的な使い方、ほかのログの場所、ローテーション中に重要な情報を失わない方法を説明します。
Linux のログの保存場所
ログの保存先は3つあります。全体像として覚えておくと便利です。
- journald:systemd のバイナリ形式のジャーナル。すべてのサービスの stdout と stderr、カーネルのメッセージ、syslog を受け取ります。
/var/log/journal/(永続)または/run/log/journal/(再起動まで)に保存されます。 - /var/log:テキストファイル。
rsyslog(例:/var/log/syslog、/var/log/auth.log)またはアプリケーション自身(nginx、PostgreSQL、MySQL など)が書きます。 - カーネルのリングバッファ:ドライバーとハードウェアのメッセージ。
dmesgやjournalctl -kで表示します。
| ファイル | 内容 |
|---|---|
/var/log/syslog(Debian/Ubuntu) | システム全体のログ |
/var/log/messages(RHEL/Fedora) | Red Hat 系での同じ役割 |
/var/log/auth.log または /var/log/secure | ログイン、sudo、SSH |
/var/log/kern.log | カーネルのメッセージ |
/var/log/dpkg.log、/var/log/apt/ | パッケージのインストール |
/var/log/nginx/ | Web サーバーの access.log と error.log |
/var/log/wtmp、/var/log/btmp | ログインのバイナリ記録。last と lastb で読む |
/var/log の多くのファイルは root またはグループ adm だけが読めるので、読み取りコマンドは sudo 付きで実行することがよくあります。
journalctl の基本コマンド
引数なしの journalctl は、最も古いエントリから順に、ページャー less でジャーナル全体を表示します。通常はそこまで必要ありません。たいてい表示範囲を絞ります。
journalctl # ジャーナル全体。古いものから新しいものへ
journalctl -e # 末尾を表示した状態で開く
journalctl -n 50 # 最後の 50 行
journalctl -r # 逆順。新しいものが上
journalctl --no-pager # less を使わない。スクリプトや grep に便利
ページャーの中では、less の操作が使えます。/ は検索、G は末尾、q は終了です。長い行は画面の幅で切られ、左右の矢印キーで横にスクロールできます。
サービス単位のログ:journalctl -u
最もよくある用途は、1つの systemd ユニットが書いた内容を見ることです。ファイルを探してgrepする必要はありません。
$ sudo journalctl -u nginx -n 20
Oct 14 03:12:41 web1 systemd[1]: Starting nginx.service - A high performance web server...
Oct 14 03:12:41 web1 nginx[1834]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Oct 14 03:12:41 web1 systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Oct 14 03:12:41 web1 systemd[1]: nginx.service: Failed with result 'exit-code'.
-u は繰り返し指定できます。journalctl -u nginx -u php8.2-fpm は、2つのサービスのログを時刻順に混ぜて表示します。エラーが2つのサービスの境界で発生する場合に便利です。ユーザーのユニット(systemctl --user)には journalctl --user -u 名前 を使います。
リアルタイムのログ:journalctl -f
sudo journalctl -u nginx -f
tail -f に相当します。最後の 10 件を表示して、新しいエントリを待ちます。サービスを再起動したり、エラーを再現したりする間、別のターミナルで開いておくと便利です。終了は Ctrl+C です。
時刻とブートによる絞り込み
障害の時刻が分かっている場合は、--since と --until で範囲を指定します。正確な日時も、相対的な指定も使えます。
journalctl --since "2026-10-14 02:50" --until "2026-10-14 03:30"
journalctl --since "1 hour ago"
journalctl --since yesterday --until today
journalctl -u nginx --since "10 min ago"
もう1つ便利な絞り込みは、システムの起動単位です。サーバーが自分で再起動した場合、原因は前のセッションの末尾にあります。
$ journalctl --list-boots
-2 8f1c... Sat 2026-10-12 09:01:12 UTC Sun 2026-10-13 22:47:03 UTC
-1 a7d2... Sun 2026-10-13 22:48:30 UTC Tue 2026-10-14 03:05:51 UTC
0 c3e9... Tue 2026-10-14 03:07:02 UTC Tue 2026-10-14 09:15:40 UTC
$ journalctl -b -1 -e # 1 つ前の起動の末尾
$ journalctl -b # 現在の起動のみ
起動の一覧は、ジャーナルがディスクに保存されている場合にだけ使えます。その設定方法は後半の journald の項で説明します。
重要度による絞り込み:journalctl -p
各エントリには 0 から 7 までの syslog の優先度があります。-p は指定したレベル以上の重要なエントリを表示します。
| コード | 名前 | 使われる場面 |
|---|---|---|
| 0 | emerg | システムが使用不能 |
| 1 | alert | 直ちに対応が必要 |
| 2 | crit | 致命的なエラー |
| 3 | err | エラー |
| 4 | warning | 警告 |
| 5 | notice | 正常だが注目すべきイベント |
| 6 | info | 情報メッセージ |
| 7 | debug | デバッグ |
journalctl -p err -b # 起動後のすべてのエラー
journalctl -p warning..err -u ssh # 1 つのサービスの重要度の範囲
journalctl -p err -b は、再起動やアップデートの後に最初に実行すると良い確認です。何が問題だったのかを数秒で把握できます。
検索とその他のフィルター
journald は各エントリに構造化されたフィールドを保存しているので、grep を使わずにフィルターできます。
journalctl _PID=1834 # プロセス番号で
journalctl _COMM=sshd # プログラム名で
journalctl _UID=1000 # ユーザー ID で
journalctl /usr/sbin/sshd # 実行ファイルのパスで
journalctl -k # カーネルのメッセージのみ(dmesg と同様)
journalctl -t CRON # syslog の識別子で
journalctl -g "Out of memory" # テキスト検索。正規表現が使える
-g(--grep)は systemd 237 以降で使えます。古いシステムでは、通常のパイプライン journalctl --no-pager | grep ... を使ってください。異なるフィールドのフィルターは「AND」で結ばれるので、journalctl -u nginx -p err --since today は今日の nginx のエラーだけを表示します。
出力形式
-o オプションで形式を変えられます。よく使われるものは次のとおりです。
-o short-iso:時刻を ISO 8601 形式で表示。アプリケーションのログと比べやすくなります。-o verbose:_SYSTEMD_UNIT、_PID、_BOOT_ID など、すべてのフィールドを表示。-o jsonまたはjson-pretty:スクリプトやjqでの処理向け。-o cat:日時やホスト名を含まず、メッセージの本文だけを表示。
journalctl -u myapp -o json --since today | jq -r '.MESSAGE'
journald の設定:保存と容量
設定は /etc/systemd/journald.conf にあります。変更は /etc/systemd/journald.conf.d/*.conf に書くと管理しやすくなります。最も重要なパラメータは Storage です。
persistent:ジャーナルを/var/log/journalにディスク保存し、再起動後も残す。volatile:メモリ上だけ(/run/log/journal)。auto(既定):/var/log/journalディレクトリが存在すればディスクに保存。
一部の最小構成のイメージにはそのディレクトリがなく、再起動すると履歴が消えます。永続保存を有効にするには、次のようにします。
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
ジャーナルがディスク全体を占有しないように、上限を設定します。
# /etc/systemd/journald.conf.d/size.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=1month
既定の SystemMaxUse は、ファイルシステムのサイズの 10% ですが、4 GB を超えることはありません。
journalctl のログを削除する
$ journalctl --disk-usage
Archived and active journals take up 1.8G in the file system.
sudo journalctl --vacuum-size=300M # 300 MB 以内に保つ
sudo journalctl --vacuum-time=2weeks # 2 週間より古いエントリを削除
sudo journalctl --rotate # 現在のファイルを閉じ、削除できるようにする
/var/log/journal のファイルを rm で削除するのは避けてください。vacuum は同じことを安全に行い、使用中のファイルには触れません。
rsyslog:従来のテキストログ
rsyslog は、syslog のメッセージ(journald から転送されたものを含む)を受け取り、ルールに従ってファイルに振り分けるデーモンです。設定は /etc/rsyslog.conf と /etc/rsyslog.d/*.conf にあります。ルールは「ファシリティ.優先度」のセレクターと、アクションで構成されます。
# /etc/rsyslog.d/50-default.conf(抜粋)
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
kern.* -/var/log/kern.log
パスの前のマイナス記号は、行ごとにディスクへ同期しないことを意味します。速くなりますが、障害時には最後の数行が失われることがあります。設定を変更したら、構文を確認してサービスを再起動します。
sudo rsyslogd -N1
sudo systemctl restart rsyslog
rsyslog を journald と並べて使う主な理由は、ログを中央サーバーに転送することです。TCP で送るには1行で足ります。
# /etc/rsyslog.d/90-remote.conf
*.* @@logs.example.com:514
@ を1つ書くと UDP、2つ書くと TCP になります。サーバーが完全に故障しても、ログのコピーは別のマシンに残ります。スクリプトから独自のメッセージをシステムログに書くには logger を使います。
logger -t backup -p user.err "データベースのバックアップに失敗しました"
journalctl -t backup -n 5
logrotate:ログのローテーション
テキストログは、誰かが切り詰めない限り無限に大きくなります。その役目を担うのが logrotate です。1日に1回(cron または logrotate.timer で)現在のファイルの名前を変え、古いファイルを圧縮し、最も古いものを削除します。全体の設定は /etc/logrotate.conf、アプリケーションごとのルールは /etc/logrotate.d/ にあります。
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 myapp adm
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
| ディレクティブ | 意味 |
|---|---|
daily / weekly / size 100M | ローテーションのタイミング |
rotate 14 | 保存する古いファイルの数 |
compress、delaycompress | gzip で圧縮する。ただし最新のアーカイブは圧縮しない |
missingok、notifempty | ファイルがなくてもエラーにしない。空のファイルはローテーションしない |
create 0640 user group | 新しいファイルを作るときの権限 |
copytruncate | コピーしてから中身を空にする。ログを開き直せないプログラム向け |
postrotate ... endscript | ローテーション後に実行するコマンド。通常はアプリケーションにファイルを開き直させるシグナルを送る |
ルールを変更せずに確認し、ローテーションを強制的に実行するには次のコマンドを使います。
sudo logrotate -d /etc/logrotate.d/myapp # デバッグ情報付きの試行実行
sudo logrotate -f /etc/logrotate.d/myapp # 今すぐローテーション
よくあるミスは、postrotate や copytruncate を書き忘れることです。すると、アプリケーションは古いディスクリプタで名前を変えた app.log.1 に書き続け、新しい app.log は空のままになります。
テキストログの読み方
/var/log のファイルには、標準的なツールで十分です。
sudo tail -n 100 /var/log/syslog # 最後の行
sudo tail -F /var/log/nginx/error.log # ローテーションを越えて追跡
sudo less +G /var/log/auth.log # 末尾を表示した状態で開く
sudo zgrep "Failed password" /var/log/auth.log.*.gz # 圧縮アーカイブを検索
sudo grep -c " 500 " /var/log/nginx/access.log # 500 応答の数
大文字の tail -F に注意してください。-f と違い、logrotate がファイルを差し替えたときに、ファイルを開き直します。
障害調査の手順:夜中にサービスが止まった場合
「夜中にサービスが停止した」という事例は、次の順序で調べると効率的です。
systemctl status myapp:現在の状態と、ジャーナルの最後の数行。journalctl -u myapp --since "03:00" --until "03:30":停止の時点でサービスが何を書いたか。journalctl -p err -b:同じ時間帯にシステム上の別のエラーがなかったか。journalctl -k --since "03:00" -g "Out of memory|Killed process":カーネルの OOM Killer がプロセスを終了させていないか。/var/log/myapp/にあるアプリケーション自身のログ。圧縮された.gzのアーカイブも含む。- サーバーが再起動していた場合は、
journalctl -b -1 -e。
まとめ
日常のログ確認には、いくつかのコマンドで十分です。サービスには journalctl -u、流れを見るには -f、範囲を絞るには --since と -p err、再起動の調査には -b -1 を使います。テキストのログは /var/log にあり、rsyslog が振り分けと転送を行います。logrotate と journalctl --vacuum-* を使うと、ログがディスクを使い尽くすことを防げます。journalctl、ローテーション、負荷の診断は、Linux コースの講義で実践しながら解説しています。
よくある質問
journalctl が現在の起動以降の記録しか表示しないのはなぜですか?
ジャーナルがメモリ上(/run/log/journal)に保存されているためです。/var/log/journal ディレクトリを作成するか、journald.conf で Storage=persistent を設定し、systemd-journald を再起動してください。
通常のユーザーが sudo なしでシステムのジャーナルを読めるようにするには?
そのユーザーを systemd-journal グループ(Debian と Ubuntu では adm)に追加します。sudo usermod -aG systemd-journal 名前 を実行し、ログインし直してください。
別のディスクにあるシステムのジャーナルを見ることはできますか?
はい。-D オプションでジャーナルのディレクトリを指定します。例:journalctl -D /mnt/var/log/journal。--file オプションを使うと、個別の .journal ファイルを読めます。
journald があれば rsyslog は必要ですか?
必須ではありません。古いツール向けにテキストファイルが必要な場合や、ログを中央サーバーに転送する場合に役立ちます。多くの最小構成のイメージではインストールされていません。
サービスのログをファイルに書き出して同僚に送るには?
journalctl -u 名前 --since today --no-pager > service.log を実行します。できあがるのは普通のテキストファイルです。