journalctlとは、systemdのログ保管係であるsystemd-journaldが集めたログ(ジャーナル)を、検索・表示・削除するためのコマンドです。 サービス名で絞る -u、流れるログを追いかける -f、時間で区切る --since、重要度で絞る -p を組み合わせれば、数十万行のログから目的の数行だけをすぐに取り出せます。

この記事では、やりたいことからコマンドを引ける逆引き表を先頭に置き、それぞれのコマンドについて実際に出力された文字列を載せています。後半では --disk-usage で容量を調べるところから、--vacuum-size と --vacuum-time での削除、journald.conf の SystemMaxUse・Storage による上限設定までを一連の手順で確かめます。Ubuntu/Debian系とRHEL系の違い、「No journal files were found」や権限不足のメッセージが出たときの対処もまとめました。

journalctlの早見表(やりたいこと→コマンド)

やりたいこと コマンド ポイント
最新のログを50行だけ見る journalctl -n 50 -n は末尾から数える。省略時は10行
末尾から開く journalctl -e ページャーの最後へ移動した状態で開く
特定のサービスだけ見る journalctl -u nginx .service は省略できる
流れるログを追いかける journalctl -u myapp -f Ctrl+C で終了。tail -f と同じ感覚
今日の分だけ見る journalctl --since today yesterday、"1 hour ago" も使える
時刻の範囲で絞る journalctl --since "2026-10-03 09:40" --until "2026-10-03 09:45" 引用符で囲む
エラー以上だけ見る journalctl -p err err(3)とそれより重いものを表示
警告とエラーだけ見る journalctl -p 3..4 範囲指定
今回の起動分だけ見る journalctl -b 前回の起動分は -b -1
起動の一覧を見る journalctl --list-boots 番号とIDと期間
カーネルのログを見る journalctl -k dmesg に相当。-b と併用が基本
JSONで取り出す journalctl -u myapp -o json 1行1件。jq に渡しやすい
メッセージ本文だけ出す journalctl -u myapp -o cat 日時やホスト名を省く
文字列で検索する journalctl -g "refused" 正規表現で本文を検索
新しい順に並べる journalctl -r 逆順
ページャーなしで出す journalctl --no-pager スクリプトやパイプ向け
使用容量を調べる journalctl --disk-usage 合計サイズを1行で表示
容量を指定して削る sudo journalctl --vacuum-size=500M 合計がこのサイズ以下になるまで削除
期間を指定して削る sudo journalctl --vacuum-time=2weeks これより前のファイルを削除
上限を恒久的に決める journald.conf の SystemMaxUse=500M 自動で上限内に保たれる

この記事で確かめた環境と出力の読み方

出力はすべて Ubuntu 24.04.4 LTS(systemd 255.4)で実際に実行したものです。確かめ方は次の2通りです。

範囲 確かめ方
絞り込みと表示(-u、--since、-p、-b、-k、-o など) 検証用に作ったジャーナルファイル(ホスト名 web01、nginx・myapp・sshd・kernel のサンプルログ19件、2回分の起動)を journalctl -D ディレクトリ --no-pager で読んだ出力。タイムゾーンは日本時間
容量管理(--disk-usage、--rotate、--vacuum-*、SystemMaxUse、Storage) 切り離した検証用の領域で systemd-journald 255 を起動し、約12万件のログを書き込んで実行した出力(ホスト名 vm)

記事中のコマンドは読みやすさのため -D と --no-pager を省いて書いています。ふだんのサーバーでは、書いてあるとおりに打てば同じ形の出力になります。 systemctl restart を使う手順と RHEL 系での動作は今回動かしていないため、該当箇所に「未実行」と書いています。

journalctlの基本:まず覚える4つの使い方

最新のログを見る(-n と -e)

オプションなしの journalctl は、保存されている一番前のログから表示します。調査では新しいほうから見ることが多いので、まず -n 行数 か -e を付けるのが近道です。

journalctl -n 5
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Failed with result 'exit-code'.
Oct 03 09:41:30 web01 nginx[690]: 2026/10/03 09:41:30 [error] 690#690: *12 connect() failed (111: Connection refused) while connecting to upstream
Oct 03 09:50:00 web01 systemd[1]: Started myapp.service - My App.
Oct 03 09:50:01 web01 myapp[1502]: listening on port 8080

1行は「日時 ホスト名 プログラム名[プロセスID]: メッセージ」の順に並びます。systemd[1] はサービスの起動や停止を記録した行、myapp[1502] はアプリ自身が出した行です。

サービス単位で見る(-u)

journalctl -u myapp.service
Oct 02 14:12:40 web01 myapp[812]: slow query: 1532 ms (GET /orders)
Oct 02 23:59:50 web01 systemd[1]: Stopped myapp.service - My App.
-- Boot 9a8b7c6d5e4f40312a1b0c9d8e7f6a5b --
Oct 03 08:00:07 web01 systemd[1]: Started myapp.service - My App.
Oct 03 08:00:08 web01 myapp[745]: listening on port 8080
Oct 03 09:40:03 web01 myapp[745]: retrying connection to db (attempt 2)
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Failed with result 'exit-code'.
Oct 03 09:50:00 web01 systemd[1]: Started myapp.service - My App.
Oct 03 09:50:01 web01 myapp[1502]: listening on port 8080

-- Boot ... -- の行は、そこで再起動があった印です。-u myapp のように .service を省いても同じ結果になります。-u を2つ並べると「どちらかに当てはまるもの」になり、関係するサービスを時系列でまとめて見られます(後述)。

流れるログを追いかける(-f)

journalctl -u myapp -f

-f は直近の10行を出したあと、新しいログが届くたびに1行ずつ表示し続けます。別の端末からログを1件書き込むと、次のように即座に現れました(-n 0 を付けて過去分を出さないようにした例です)。

# 端末A
journalctl -f -n 0 -t demo
# 端末B
echo "live line" | systemd-cat -t demo
Oct 03 17:32:41 vm demo[1017]: live line

systemd-cat は標準入力や任意のコマンドの出力をジャーナルに書き込む道具です。自作スクリプトのログを journalctl で読めるようにしたいときにも使えます。

時間で絞る(--since と --until)

journalctl -u myapp --since "2026-10-03 09:40" --until "2026-10-03 09:45"
Oct 03 09:40:03 web01 myapp[745]: retrying connection to db (attempt 2)
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Failed with result 'exit-code'.

指定できる書き方は次のとおりです。

書き方 意味
--since today 今日の0時から
--since yesterday --until today 昨日1日分
--since "1 hour ago" 1時間前から
--since "10 min ago" 10分前から
--since "2026-10-03 09:40" 日時を指定(秒は省略可)
--since 09:40 今日のその時刻から

綴りを誤ると次のメッセージが返ります。空白を含む値は引用符で囲むのが確実です。

$ journalctl --since "yesterdayy"
Failed to parse timestamp: yesterdayy

重要度で絞る(-p)

-p はログの重要度(priority)で絞ります。指定したレベルと、それより重いものすべてが表示されます。

番号 名前 意味
0 emerg システムが使えない
1 alert すぐに対応が必要
2 crit 致命的な状態
3 err エラー
4 warning 警告
5 notice 通常だが注目すべき情報
6 info 情報
7 debug デバッグ用
journalctl -p warning -b
Oct 03 08:00:02 web01 kernel: ACPI: \_SB_.PCI0: _OSC evaluation failed
Oct 03 09:40:03 web01 myapp[745]: retrying connection to db (attempt 2)
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Failed with result 'exit-code'.
Oct 03 09:41:30 web01 nginx[690]: 2026/10/03 09:41:30 [error] 690#690: *12 connect() failed (111: Connection refused) while connecting to upstream

-p err に変えると warning の行が消え、err の行だけになります。-p 3..4 のように範囲でも書けます。存在しない名前を渡したときのメッセージは次のとおりです。

$ journalctl -p foo
Unknown log level foo

アプリが重要度を付けずに標準出力へ書いた行は info(6) として扱われます。 そのため -p err で何も出ないときは、アプリ側のログが info で届いている可能性があります。その場合は -p を外し、-g で文字列検索するほうが見つけやすくなります。

起動単位で見る(-b と --list-boots)とカーネルログ(-k)

journalctl --list-boots
IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY
 -1 1f0c3a7e5d2b4c6f8a9b0c1d2e3f4a5b Fri 2026-10-02 09:00:01 JST Fri 2026-10-02 23:59:50 JST
  0 9a8b7c6d5e4f40312a1b0c9d8e7f6a5b Sat 2026-10-03 08:00:01 JST Sat 2026-10-03 09:50:01 JST

IDX の 0 が今回の起動、-1 が1つ前です。再起動の直前に何が起きたかを見るなら -b -1 を使います。

journalctl -b -1 -n 3
Oct 02 14:12:40 web01 myapp[812]: slow query: 1532 ms (GET /orders)
Oct 02 18:30:11 web01 kernel: EXT4-fs error (device sdb1): ext4_find_entry:1678: inode #2: comm ls: reading directory lblock 0
Oct 02 23:59:50 web01 systemd[1]: Stopped myapp.service - My App.

-k はカーネルが出したログだけを表示します。-b と組み合わせて「今回の起動のカーネルログ」を見る形がよく使われます。

journalctl -k -b
Oct 03 08:00:01 web01 kernel: Linux version 6.8.0-45-generic (buildd@lcy02-amd64-075)
Oct 03 08:00:02 web01 kernel: ACPI: \_SB_.PCI0: _OSC evaluation failed

保存されていない起動番号を指定すると、次のメッセージになります。

$ journalctl -b -5
No journal boot entry found from the specified boot offset (-5).

出力形式を変える(-o json ほか)

指定 出力の形 向いている用途
-o short(既定) 日時 ホスト プログラム: 本文 目で読む
-o short-iso 日時が ISO 8601 形式 他のログと時刻を突き合わせる
-o short-precise マイクロ秒まで表示 前後関係を細かく見る
-o cat 本文だけ アプリのログをそのまま取り出す
-o with-unit プログラム名の代わりにユニット名 どのサービス由来かを明示
-o json 1行1件のJSON jq や集計スクリプトに渡す
-o json-pretty 整形したJSON 持っている項目を確かめる
-o verbose 全項目を「名前=値」で表示 絞り込みに使える項目を探す
journalctl -u myapp -n 2 -o short-iso
2026-10-03T09:50:00+09:00 web01 systemd[1]: Started myapp.service - My App.
2026-10-03T09:50:01+09:00 web01 myapp[1502]: listening on port 8080
journalctl -u myapp -n 2 -o cat
Started myapp.service - My App.
listening on port 8080
journalctl -u myapp -n 1 -o json-pretty
{
    "_UID" : "0",
    "__CURSOR" : "s=04d45ada89cb401c8abc83c82355251c;i=13;b=9a8b7c6d5e4f40312a1b0c9d8e7f6a5b;m=189734440;t=65ce5075c0040;x=6cfe014133ff0d3",
    "_MACHINE_ID" : "0123456789abcdef0123456789abcdef",
    "_COMM" : "myapp",
    "__SEQNUM_ID" : "04d45ada89cb401c8abc83c82355251c",
    "__SEQNUM" : "19",
    "_HOSTNAME" : "web01",
    "MESSAGE" : "listening on port 8080",
    "_PID" : "1502",
    "__REALTIME_TIMESTAMP" : "1790988601000000",
    "__MONOTONIC_TIMESTAMP" : "6601000000",
    "_TRANSPORT" : "journal",
    "PRIORITY" : "6",
    "_SYSTEMD_UNIT" : "myapp.service",
    "SYSLOG_IDENTIFIER" : "myapp",
    "_BOOT_ID" : "9a8b7c6d5e4f40312a1b0c9d8e7f6a5b"
}

JSONを見ると、ジャーナルの1件が「項目名と値の集まり」であることがわかります。-u は _SYSTEMD_UNIT、-p は PRIORITY、-t は SYSLOG_IDENTIFIER、-b は _BOOT_ID を見ている、と対応づけると、オプションの意味がつかみやすくなります。__REALTIME_TIMESTAMP は1970年からのマイクロ秒で、数値も文字列として出力される点に気をつけます。

項目名を直接書いて絞ることもできます。

journalctl _PID=745
Oct 03 08:00:08 web01 myapp[745]: listening on port 8080
Oct 03 09:40:03 web01 myapp[745]: retrying connection to db (attempt 2)
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432

記録されているユニット名の一覧は -F で取り出せます。-u に渡す名前がわからないときに便利です。

$ journalctl -F _SYSTEMD_UNIT
ssh.service
myapp.service
nginx.service

オプションを組み合わせる逆引き(実際の出力つき)

journalctl のオプションは、種類の違うもの同士は「かつ」、同じ種類を並べると「または」として働きます。この規則を知っておくと、組み合わせを自分で作れます。

やりたいこと コマンド
あるサービスのエラーだけ journalctl -u myapp -p err
2つのサービスのエラーを時系列で、今回の起動分 journalctl -u nginx -u myapp -p err -b
あるサービスの直近10分を追い続ける journalctl -u myapp --since "10 min ago" -f
今回の起動のカーネル警告以上 journalctl -k -b -p warning
前回の起動の最後の100行 journalctl -b -1 -n 100
特定の時間帯の本文だけをファイルに保存 journalctl -u myapp --since 09:40 --until 09:45 -o cat --no-pager > app.log
文字列を含む行を全体から探す journalctl -g "refused" -b
プログラム名で絞る(ユニットがないもの) journalctl -t sshd
エラーの件数を数える journalctl -u myapp -p err -b -o cat --no-pager | wc -l
JSONから本文だけ取り出す journalctl -u myapp -o json --no-pager | jq -r .MESSAGE
journalctl -u nginx -u myapp -p err -b
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432
Oct 03 09:41:30 web01 nginx[690]: 2026/10/03 09:41:30 [error] 690#690: *12 connect() failed (111: Connection refused) while connecting to upstream

アプリがDBにつながらなくなり、その約80秒後に nginx 側でも接続エラーが出た、という流れが2行で読み取れます。原因と結果を1つの時系列に並べられるのが、-u を複数並べる利点です。

journalctl -g "refused"
-- Boot 9a8b7c6d5e4f40312a1b0c9d8e7f6a5b --
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432
Oct 03 09:41:30 web01 nginx[690]: 2026/10/03 09:41:30 [error] 690#690: *12 connect() failed (111: Connection refused) while connecting to upstream

-g に小文字だけを渡すと大文字小文字を区別せずに探すため、nginx の「Connection refused」も一致しています。

journalctl -p 3..4 -b -u myapp
Oct 03 09:40:03 web01 myapp[745]: retrying connection to db (attempt 2)
Oct 03 09:40:09 web01 myapp[745]: database connection refused: 127.0.0.1:5432
Oct 03 09:40:09 web01 systemd[1]: myapp.service: Failed with result 'exit-code'.

サービスが起動しないときの定番は、次の2つを順に実行する形です(systemctl は今回未実行です)。

systemctl status myapp        # 状態と直近の数行
journalctl -u myapp -b -e     # 今回の起動分を末尾から

journalctl -xe もよく紹介されます。-x は一部のメッセージに説明文を添えるオプション、-e は末尾へ移動するオプションです。全サービスのログが混ざるので、対象が決まっているなら -u を足すと読みやすくなります。

ログの容量を調べて削除する手順

ここからは、ジャーナルがディスクを使いすぎているときの対処を順番に進めます。検証用の領域で約12万件(1件およそ900バイト)のログを書き込み、その状態から始めます。

手順1:使用量を調べる(--disk-usage)

journalctl --disk-usage
Archived and active journals take up 71.9M in the file system.

実体は /var/log/journal/マシンID/ の下にあります。

$ ls -la /var/log/journal/*/
-rw-r----- 1 root systemd-journal 16777216 Oct  3 17:32 system.journal
-rw-r----- 1 root systemd-journal 25165824 Oct  3 17:32 system@4b2997c0...-0000000000000174-00065ceb7dc43b9e.journal
-rw-r----- 1 root systemd-journal 25165824 Oct  3 17:32 system@4b2997c0...-0000000000008761-00065ceb7e55c39b.journal
-rw-r----- 1 root systemd-journal 25165824 Oct  3 17:32 system@4b2997c0...-0000000000010d3e-00065ceb7e897afe.journal

(ファイル名は途中を省略しています。)system.journal が今書き込み中のファイル(アクティブ)、system@...journal が書き終えたファイル(アーカイブ)です。この区別が次の手順で効いてきます。

手順2:書き込み中のファイルを区切る(--rotate)

--vacuum-* が削除するのはアーカイブ済みのファイルだけです。書き込み中のファイルも対象に含めたいときは、先に --rotate で区切ります。

sudo journalctl --rotate

実行すると、それまでの system.journal が system@...journal に名前を変え、新しい system.journal(8MB)が作られました。

手順3:サイズを指定して削除する(--vacuum-size)

sudo journalctl --vacuum-size=50M
Deleted archived journal /var/log/journal/c1d60f590676409fadd11ab338e333b8/system@4b2997c01c1640458c3fb1aae5b65d26-0000000000000174-00065ceb7dc43b9e.journal (18.6M).
Deleted archived journal /var/log/journal/c1d60f590676409fadd11ab338e333b8/system@4b2997c01c1640458c3fb1aae5b65d26-0000000000008761-00065ceb7e55c39b.journal (18.6M).
Vacuuming done, freed 37.2M of archived journals from /var/log/journal/c1d60f590676409fadd11ab338e333b8.
Vacuuming done, freed 0B of archived journals from /run/log/journal.
Vacuuming done, freed 0B of archived journals from /var/log/journal.
$ journalctl --disk-usage
Archived and active journals take up 35.9M in the file system.

50M を指定して、結果は 35.9M になりました。削除はファイル単位で前のものから行われるため、指定値ちょうどではなく「指定値以下になるところまで」減ります。 行単位で消す機能はなく、特定のサービスのログだけを消すこともできません。

手順4:期間を指定して削除する(--vacuum-time)

sudo journalctl --vacuum-time=2weeks

「2週間より前のログだけを含むアーカイブ」を削除します。検証では結果を見やすくするために 1s を指定し、直前に --rotate を実行しました。

$ sudo journalctl --rotate
$ sudo journalctl --vacuum-time=1s
Deleted archived journal /var/log/journal/c1d6.../system@4b29...-0000000000010d3e-00065ceb7e897afe.journal (18.6M).
Deleted archived journal /var/log/journal/c1d6.../system@4b29...-0000000000019323-00065ceb7ebcf46d.journal (9.3M).
Deleted archived journal /var/log/journal/c1d6.../system@4b29...-000000000001d7ad-00065ceb7ef81d5c.journal (1.4M).
Vacuuming done, freed 29.3M of archived journals from /var/log/journal/c1d60f590676409fadd11ab338e333b8.
$ journalctl --disk-usage
Archived and active journals take up 8.0M in the file system.

(パスは途中を省略しています。)アーカイブがすべて消えても 8.0M が残ります。これは書き込み中の system.journal の分で、journald が動いている限り存在します。「全部消したのに 0 にならない」と感じたときは、この仕組みを思い出してください。

オプション 意味 例
--vacuum-size= 合計が指定サイズ以下になるまで削除 500M、1G
--vacuum-time= 指定より前のアーカイブを削除 2weeks、30d、1month
--vacuum-files= アーカイブを指定個数まで減らす 5
--rotate 書き込み中のファイルを区切ってアーカイブにする 上の3つと同時に書ける

sudo journalctl --rotate --vacuum-time=2weeks のように1行で書くこともできます。/var/log/journal の中のファイルを rm で直接消す方法は、journald が開いているファイルを消すことになるため、--vacuum-* を使うほうが安心です。

journald.confで上限を決めて自動で保つ

手作業の削除は一度きりです。上限を設定しておけば、journald が自動で前のファイルから削除して範囲内に保ちます。

設定ファイルの場所と書き方

Ubuntu 24.04 の /etc/systemd/journald.conf は、すべての行が # で始まっています。これは「組み込みの既定値の一覧」で、変更したい項目だけを別ファイルに書くのがおすすめです。

sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/size.conf <<'EOF'
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=1month
EOF
sudo systemctl restart systemd-journald

journald.conf.d/ に置いた .conf は本体の設定に上書きで適用されるため、パッケージ更新で本体が置き換わっても自分の設定が残ります。今の設定全体は systemd-analyze cat-config systemd/journald.conf で確認できます。

上限が効くことを確かめる

SystemMaxUse=30M、SystemMaxFileSize=8M を設定して journald を起動し直すと、起動時のログに上限が表示されました(検証環境では systemctl が使えないため、journald のプロセスを直接起動し直しています。systemctl restart systemd-journald は未実行です)。

Oct 03 17:33:00 vm systemd-journald[1667]: Journal started
Oct 03 17:33:00 vm systemd-journald[1667]: System Journal (/var/log/journal/c1d60f590676409fadd11ab338e333b8) is 8.0M, max 30.0M, 22.0M free.

この状態で再び約12万件を書き込んだ結果です。

$ journalctl --disk-usage
Archived and active journals take up 24.3M in the file system.
$ du -sh /var/log/journal
25M /var/log/journal

設定前は同じ量で 71.9M まで増えていましたが、設定後は 30M の範囲に収まり、ファイルも8MBごとに区切られました。現在の上限は journalctl -u systemd-journald で max の値を見れば確かめられます。

主な設定項目

既定値は、手元の journald.conf のコメントと、今回開いた journald.conf(5) の man ページ(man7.org 掲載版)で確認した内容です。

項目 意味 既定
Storage= 保存先。persistent(ディスク)、volatile(メモリ上、再起動で消える)、auto、none Ubuntu 24.04(systemd 255)のコメントは auto
SystemMaxUse= ディスク上のジャーナルの合計上限 ファイルシステムの10%(最大4G)
SystemKeepFree= 他の用途に空けておく量 ファイルシステムの15%(最大4G)
SystemMaxFileSize= 1ファイルの上限。超えると区切られる SystemMaxUse の8分の1(最大128M)
SystemMaxFiles= 保持するファイル数の上限 100
RuntimeMaxUse= /run/log/journal(メモリ上)の上限 ファイルシステムの10%(最大4G)
MaxRetentionSec= これより前のログを含むファイルを削除 0(無効)
MaxFileSec= 1ファイルに書き続ける最長期間 1month
ForwardToSyslog= rsyslog などへ転送するか 組み込みの既定は no(Ubuntu は yes に上書き。後述)
Compress= 大きな項目を圧縮するか yes

Storage=auto は「/var/log/journal ディレクトリがあればディスクに保存、なければ /run/log/journal(メモリ上)に保存」という動作です。今回開いた man ページ(systemd 262 の開発版の文書)では既定が persistent と書かれており、systemd の版によって既定が異なります。手元の journald.conf のコメントを見るのが確実です。

Storage=volatile を設定して起動し直すと、新しいログは /run/log/journal/ に書かれることを確かめました。

$ ls /run/log/journal/*/
system.journal

定期的に削除したいとき

多くの場合は SystemMaxUse と MaxRetentionSec の設定だけで足ります。設定ファイルを変えずに日次で整理したい場合は、cron に1行足す方法もあります(次の例は未実行です)。

# /etc/cron.d/journal-vacuum(毎日 3:30 に2週間より前を削除)
30 3 * * * root /usr/bin/journalctl --rotate --vacuum-time=2weeks
方法 向いている場面
SystemMaxUse= ディスクの空きを守りたい(容量が基準)
MaxRetentionSec= 保存期間の決まりがある(期間が基準)
cron で --vacuum-time 設定ファイルを変えずに運用で対応したい
手動の --vacuum-size 今すぐ空きを作りたい

Ubuntu/Debian系とRHEL系の違い

Ubuntu 24.04 については今回確認した内容、RHEL 系については一般に知られた仕様(今回は未実行)です。手元の環境では、表の「確かめ方」のコマンドで実際の状態を見てください。

項目 Ubuntu 24.04(確認済み) RHEL系(未実行・一般に知られた仕様) 確かめ方
ジャーナルの保存先 /var/log/journal が最初からあり、ディスクに保存 /var/log/journal がない構成では /run/log/journal に保存され、再起動で消える ls -d /var/log/journal
syslog への転送 /usr/lib/systemd/journald.conf.d/syslog.conf で ForwardToSyslog=yes rsyslog がジャーナルを読み取る構成が一般的 systemd-analyze cat-config systemd/journald.conf
テキストのログ /var/log/syslog /var/log/messages ls /var/log
sudo なしで全ログを読めるグループ systemd-journal と adm(ACL で付与) systemd-journal、wheel、adm getfacl /var/log/journal
SSH のユニット名 ssh.service sshd.service systemctl list-units
Web サーバー(Apache) apache2.service httpd.service 同上
cron cron.service crond.service 同上

Ubuntu 24.04 で確認した ACL は次のとおりで、adm グループに読み取りが付いています。

$ getfacl /var/log/journal
# owner: root
# group: systemd-journal
user::rwx
group::r-x
group:adm:r-x

「再起動したらログが消えていた」ときは、保存先がメモリ上になっていることが考えられます。次の手順でディスク保存に切り替えられます(systemd-tmpfiles と systemctl の部分は未実行です)。

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

ログが出ないときの対処

「No journal files were found.」と表示される

ジャーナルファイルが1つも見つからないときのメッセージです。今回の検証環境(journald が動いていないコンテナ)で、実際に次のように表示されました。

$ journalctl -n 3
No journal files were found.
-- No entries --
$ journalctl --disk-usage
No journal files were found.
Archived and active journals take up 0B in the file system.
考えられる理由 確かめ方 対処
journald が動いていない(コンテナなど) ps -e | grep journald コンテナではアプリのログを標準出力に出し、ホスト側のログ機能で見る
Storage=none になっている systemd-analyze cat-config systemd/journald.conf Storage=persistent か auto にして再起動
読む場所が違う(-D の指定など) ls /var/log/journal /run/log/journal 正しいディレクトリを指定
起動直後でまだファイルがない journalctl --header 少し待って再実行

権限が足りないときのメッセージ

一般ユーザーで実行すると、次の表示になることがあります。

$ journalctl -n 2
Hint: You are currently not seeing messages from other users and the system.
      Users in the 'systemd-journal' group can see all messages. Pass -q to
      turn off this notice.
No journal files were opened due to insufficient permissions.

対処は2通りです。

# その場で読む
sudo journalctl -u myapp -n 50

# 毎回 sudo を付けずに読めるようにする(一度ログアウトして入り直すと有効になる)
sudo usermod -aG systemd-journal taro

(ユーザー名は例です。usermod は今回未実行です。)なお、--vacuum-* や --rotate はファイルを変更する操作なので、グループに入っていても sudo が必要です。

-u で何も出ないとき

ユニット名が違っていてもエラーにはならず、-- No entries -- だけが返ります。

$ journalctl -u x
-- No entries --
状況 確かめること
-- No entries -- だけ出る ユニット名の綴り。journalctl -F _SYSTEMD_UNIT や systemctl list-units --type=service で正しい名前を探す
起動時刻は出るがアプリの行がない アプリがファイルに直接ログを書いている可能性。アプリ側のログ出力先を確認
途中で途切れている 上限に達して前のファイルが削除された可能性。--disk-usage と SystemMaxUse を確認
-p err で出ない アプリのログが info として届いている可能性。-p を外して -g で検索
時刻がずれて見える --utc を付けると UTC 表示。サーバーのタイムゾーンは timedatectl で確認

よくある質問

Q. journalctl と /var/log/syslog(または /var/log/messages)はどう使い分けますか? A. 内容は多くが重なります。サービス名・時間・重要度で絞りたいときは journalctl、grep や既存のログ収集の仕組みで扱いたいときはテキストのログが向いています。ジャーナルは容量の上限で前のものから消えるため、長期保存が必要なログは別の仕組みに転送しておくと安心です。

Q. --vacuum-size を実行しても容量があまり減りません。なぜですか? A. 削除されるのはアーカイブ済みのファイルだけで、書き込み中の system.journal は残るためです。sudo journalctl --rotate --vacuum-size=100M のように --rotate を先に付けると、直前までの分も削除の対象になります。

Q. 特定のサービスのログだけを削除できますか? A. できません。削除はファイル単位で、1つのファイルに複数のサービスのログが混ざって入っています。見たくないサービスがあるときは、削除ではなく -u で表示側を絞ります。

Q. ページャー(less)で開かれるのを止めたいです。 A. --no-pager を付けます。パイプやリダイレクトにつないだ場合は自動でページャーなしになります。長い行が右で切れて見えるときは、ページャーの中で矢印キーの右を押すか、--no-pager で折り返して表示します。

まとめ

  • まず -u サービス名、-n 行数、-f、--since の4つを覚えると、日常の確認はほぼ足ります。
  • 種類の違うオプションは「かつ」、同じオプションを並べると「または」。-u nginx -u myapp -p err -b で関係するサービスのエラーを時系列に並べられます。
  • -o json と -o cat で取り出し方を変えられます。 -u は _SYSTEMD_UNIT、-p は PRIORITY を見ています。
  • 容量は --disk-usage で調べ、--rotate のあと --vacuum-size か --vacuum-time で削除します。削除はアーカイブ単位で、書き込み中のファイルは残ります。
  • 恒久的な対策は journald.conf.d/ に SystemMaxUse= を書くこと。 30M に設定した検証では、同じ量を書き込んでも 24.3M に収まりました。
  • Ubuntu 24.04 は最初からディスクに保存されます。再起動でログが消える環境では /var/log/journal の有無を確かめます。
  • 「No journal files were found」は保存先と journald の状態、権限のメッセージは systemd-journal グループを確認します。

参考・出典

  • journald.conf(5) man ページ(man7.org 掲載版。今回開いて既定値を確認)
  • Ubuntu 24.04.4 LTS に含まれる /etc/systemd/journald.conf と /usr/lib/systemd/journald.conf.d/syslog.conf(systemd 255.4)

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?