- 技術 💻
journalctlの使い方|目的別コマンド逆引き一覧と絞り込み例
journalctlとは、systemd のログ収集サービス(systemd-journald)が保存したログ=ジャーナルを検索・表示するコマンドです。 サービス名・優先度・時間・起動回ごとに絞り込めるので、/var/log のテキストを grep するより早く目的のログにたどり着けます。
この記事では、「やりたいこと」から引ける逆引き一覧とオプションの早見表を最初にまとめ、続けて絞り込み・出力形式・jq での集計・journald.conf の容量設定・よくあるつまずきを解説します。表示例はすべて、Ubuntu 24.04 の systemd 255 に含まれる systemd-journal-remote でサンプルのジャーナルファイルを作り、journalctl --file で実際に実行した結果です(作り方も載せているので、手元で同じ結果を再現できます)。
journalctlの目的別コマンド逆引き一覧
| やりたいこと | コマンド |
|---|---|
| サービスが起動しない原因を見る | journalctl -xeu nginx.service |
| 特定サービスのログだけ見る | journalctl -u nginx.service |
| 複数サービスをまとめて見る | journalctl -u nginx.service -u myapp.service |
| 直近1時間のエラーだけ見る | journalctl -p err --since "1 hour ago" |
| 警告〜エラーの範囲だけ見る | journalctl -p warning..err |
| 日時の範囲で見る | journalctl --since "2026-10-01 22:00" --until "2026-10-01 22:30" |
| 今回の起動以降だけ見る | journalctl -b |
| 前回の起動時(再起動前)を見る | journalctl -b -1 |
| 起動の一覧を見る | journalctl --list-boots |
| リアルタイムで追いかける(tail -f) | journalctl -f -u myapp.service |
| 最新の20行だけ見る | journalctl -n 20 |
| 新しい順に表示する | journalctl -r |
| 本文を正規表現で検索する | journalctl -g "time(d )?out" |
| プログラム名(識別子)で絞る | journalctl -t CRON |
| PIDで絞る | journalctl _PID=1201 |
| カーネルのログを見る | journalctl -k |
| ISO形式の時刻で表示する | journalctl -o short-iso |
| 本文だけ出す(スクリプト用) | journalctl -o cat |
| JSONで出してjqで集計する | journalctl -o json | jq ... |
| 使える値の一覧(ユニット名など)を見る | journalctl -F _SYSTEMD_UNIT |
| ディスク使用量を見る | journalctl --disk-usage |
| 古いログを削除して容量を減らす | sudo journalctl --vacuum-size=500M / --vacuum-time=2weeks |
| ログを永続化する | /etc/systemd/journald.conf.d/ に Storage=persistent |
| 別サーバーから持ってきたファイルを読む | journalctl --file=./system.journal / -D ./dir |
迷ったら journalctl -xeu サービス名 から始めると、最新のログ末尾に移動した状態で、そのサービスのログが説明つきで表示されます。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「journalctlの使い方|目的別コマンド逆引き一覧と絞り込み例」
journalctlオプション早見表
| オプション | 長い形 | 意味 |
|---|---|---|
-u |
--unit= |
ユニット(サービス)で絞る。複数指定はOR |
-p |
--priority= |
優先度で絞る。err なら err 以上(crit, alert, emerg を含む)。warning..err で範囲 |
-S / -U |
--since= / --until= |
開始・終了日時。"1 hour ago"、yesterday、today、"2026-10-01 22:00" |
-b |
--boot= |
起動回で絞る。-b は今回、-b -1 は前回 |
--list-boots |
記録されている起動の一覧 | |
-f |
--follow |
新しいログを追いかけて表示 |
-n |
--lines= |
末尾から指定行数 |
-r |
--reverse |
新しい順 |
-x |
--catalog |
説明文(カタログ)があるメッセージに解説を付ける |
-g |
--grep= |
MESSAGE を正規表現で検索(大文字小文字は自動判定) |
-t |
--identifier= |
SYSLOG_IDENTIFIER(プログラム名)で絞る |
-k |
--dmesg |
カーネルのログだけ(今回の起動分。-b を含む) |
-o |
--output= |
出力形式(short、short-iso、short-precise、cat、verbose、json、json-pretty など) |
--output-fields= |
json・verbose で出すフィールドを限定 | |
-F |
--field= |
指定フィールドに入っている値の一覧 |
-D |
--directory= |
ジャーナルのディレクトリを指定 |
--file= |
ジャーナルファイルを直接指定 | |
-q |
--quiet |
権限の注意書きなどを出さない |
--no-pager |
ページャーを使わず標準出力へ | |
--user |
ログイン中ユーザーのユーザージャーナル | |
--disk-usage |
ジャーナルの使用量 | |
--vacuum-size= / --vacuum-time= / --vacuum-files= |
アーカイブ済みファイルを削除して縮める | |
--rotate |
現在のファイルをアーカイブ化(journald 稼働中のみ) | |
--flush |
/run の一時ログを /var へ移す | |
--verify |
ジャーナルファイルの整合性チェック | |
フィールド=値 |
_PID=1201、_SYSTEMD_UNIT=x.service のように直接条件指定。+ でOR |
優先度(-p)の数値と名前
| 数値 | 名前 | 目安 |
|---|---|---|
| 0 | emerg | システムが使えない |
| 1 | alert | すぐ対応が必要 |
| 2 | crit | 重大 |
| 3 | err | エラー |
| 4 | warning | 警告 |
| 5 | notice | 通常だが注目 |
| 6 | info | 情報 |
| 7 | debug | デバッグ |
-p err は「3以下(err・crit・alert・emerg)」を表示します。数値で -p 3 と書いても同じです。
検証用のジャーナルファイルを作る
ジャーナルは journald が書くバイナリファイルなので、テキストエディタでは作れません。そこで、journald が動いていない環境(コンテナなど)でも試せるよう、ジャーナルの書き出し形式(export形式)のテキストを systemd-journal-remote で変換しました。
環境
sudo apt-get install -y systemd systemd-journal-remote jq
journalctl --version | head -1
systemd 255 (255.4-1ubuntu8.17)
検証したコンテナは PID 1 が systemd ではなく、journald も動いていません。この状態で journalctl を実行すると次のようになります。
$ journalctl
No journal files were found.
-- No entries --
サンプルデータの作成(Python 3.11)
export形式は「フィールド名=値 を1行ずつ並べ、空行でエントリを区切る」テキストです。2回分の起動(boot)にまたがる10件のログを作ります。
# gen_export.py: journal export形式でサンプルを作る
import time, uuid
boot1, boot2 = uuid.uuid4().hex, uuid.uuid4().hex
mid = uuid.uuid4().hex
base = int(time.time() * 1_000_000) - 3 * 3600 * 1_000_000 # 3時間前から
rows = [
# (秒後, boot, unit, priority, ident, message)
(0, boot1, "myapp.service", 6, "myapp", "Started order worker"),
(60, boot1, "myapp.service", 3, "myapp", "DB connection refused: 127.0.0.1:5432"),
(120, boot1, "nginx.service", 6, "nginx", "GET /api/orders 200"),
(4000, boot2, "myapp.service", 6, "myapp", "Started order worker"),
(7300, boot2, "myapp.service", 4, "myapp", "slow query 1830ms: SELECT * FROM orders"),
(7400, boot2, "nginx.service", 3, "nginx", "upstream timed out (110: Connection timed out)"),
(8000, boot2, "myapp.service", 3, "myapp", "Failed to send mail: timeout"),
(9000, boot2, "myapp.service", 6, "myapp", "order id=1024 created"),
(9500, boot2, "cron.service", 6, "CRON", "(root) CMD (/usr/local/bin/backup.sh)"),
(10000,boot2, "myapp.service", 2, "myapp", "Out of disk space on /var"),
]
pid = 1200
out = []
for i,(sec,boot,unit,pri,ident,msg) in enumerate(rows):
ts = base + sec * 1_000_000
out.append("\n".join([
f"__CURSOR=s=0;i={i+1}",
f"__REALTIME_TIMESTAMP={ts}",
f"__MONOTONIC_TIMESTAMP={sec*1_000_000 + 5_000_000}",
f"_BOOT_ID={boot}",
f"_MACHINE_ID={mid}",
"_HOSTNAME=demo-host",
f"_SYSTEMD_UNIT={unit}",
f"PRIORITY={pri}",
f"SYSLOG_IDENTIFIER={ident}",
f"_PID={pid+i}",
"_TRANSPORT=journal",
f"MESSAGE={msg}",
]) + "\n")
open("sample.export","w").write("\n".join(out) + "\n")
python3 gen_export.py
/lib/systemd/systemd-journal-remote --output=/tmp/t89jr/demo.journal /tmp/t89jr/sample.export
Finishing after writing 10 entries
最初は最後のエントリの後ろに空行を入れ忘れ、Premature EOF. 3255 bytes lost. と出て9件しか書かれませんでした。export形式は最後のエントリも空行で終える必要があります。
以降は、次の形で実行しています(J は長いコマンドを短く書くための変数です)。出力に入る -- Boot ... -- の行は起動の区切りで、実際のサーバーでも再起動をまたぐとこの行が入ります。
J="journalctl --file=/tmp/t89jr/demo.journal --no-pager"
サービス別に見る(-u)
-u myapp.service でそのサービスだけになります。-u を複数並べると OR、-p と組み合わせると AND です。
$J -u myapp.service -u nginx.service -p err
Oct 01 19:58:29 demo-host myapp[1201]: DB connection refused: 127.0.0.1:5432
-- Boot c0ed600dfb174b13a1b1d6f8d7595860 --
Oct 01 22:00:49 demo-host nginx[1205]: upstream timed out (110: Connection timed out)
Oct 01 22:10:49 demo-host myapp[1206]: Failed to send mail: timeout
Oct 01 22:44:09 demo-host myapp[1209]: Out of disk space on /var
存在しないユニット名を指定してもエラーにはならず -- No entries -- で終了コード0でした。名前の打ち間違いに気づきにくいので、-F _SYSTEMD_UNIT で実際の名前を確認すると確実です。
$J -F _SYSTEMD_UNIT
cron.service
nginx.service
myapp.service
サービスが起動しないときの調べ方
| 手順 | コマンド | 見るところ |
|---|---|---|
| 1. 状態と直近のログ | systemctl status myapp.service |
Active の行、末尾の数行 |
| 2. 説明つきで末尾から | journalctl -xeu myapp.service |
最後の Failed・error の直前 |
| 3. 今回の起動に限定 | journalctl -b -u myapp.service -p warning |
警告以上だけに絞る |
| 4. 再起動前と比べる | journalctl -b -1 -u myapp.service |
前回は正常だったか |
-x の解説は、systemd 自身のメッセージなど「カタログ(説明文)が登録されたメッセージ」にだけ付きます。アプリが出した普通のログには付かないので、サンプルで -xe を付けても表示は通常と同じでした。systemctl status はこのコンテナでは systemd が動いていないため未実行です。
優先度で絞る(-p)
上の -u ... -p err の結果で、最後の行は PRIORITY=2(crit)ですが表示されています。-p err は「err だけ」ではなく「err 以上」です。範囲指定にすると、warning(4)の slow query が加わり、crit(2)は外れます。
$J -p warning..err
Oct 01 19:58:29 demo-host myapp[1201]: DB connection refused: 127.0.0.1:5432
-- Boot c0ed600dfb174b13a1b1d6f8d7595860 --
Oct 01 21:59:09 demo-host myapp[1204]: slow query 1830ms: SELECT * FROM orders
Oct 01 22:00:49 demo-host nginx[1205]: upstream timed out (110: Connection timed out)
Oct 01 22:10:49 demo-host myapp[1206]: Failed to send mail: timeout
名前を打ち間違えると Unknown log level errr と表示されます。
時間で絞る(--since / --until)
$J --since "1 hour ago"
Oct 01 21:59:09 demo-host myapp[1204]: slow query 1830ms: SELECT * FROM orders
Oct 01 22:00:49 demo-host nginx[1205]: upstream timed out (110: Connection timed out)
Oct 01 22:10:49 demo-host myapp[1206]: Failed to send mail: timeout
Oct 01 22:27:29 demo-host myapp[1207]: order id=1024 created
Oct 01 22:35:49 demo-host CRON[1208]: (root) CMD (/usr/local/bin/backup.sh)
Oct 01 22:44:09 demo-host myapp[1209]: Out of disk space on /var
日時で範囲を決める場合は --since "2026-10-01 22:00" --until "2026-10-01 22:30" と書きます(このサンプルでは22:00:49〜22:27:29の3件が表示されました)。
| 書き方 | 意味 |
|---|---|
"2026-10-01 22:00" |
その日時(秒は省略可) |
today / yesterday |
今日・昨日の0時 |
"1 hour ago" / "30 min ago" / -2h |
今から相対 |
"yesterday 12:00" |
昨日の12時 |
時刻はローカルタイムゾーンで解釈されます(この検証環境は Asia/Tokyo)。解釈できない書き方は Failed to parse timestamp: yesterday 25:00 のように表示されます。
起動回で絞る(-b / --list-boots)
$J --list-boots
IDX BOOT ID FIRST ENTRY LAST ENTRY
-1 dcd108aa28e942f89acb2d4bb347f08d Thu 2026-10-01 19:57:29 JST Thu 2026-10-01 19:59:29 JST
0 c0ed600dfb174b13a1b1d6f8d7595860 Thu 2026-10-01 21:04:09 JST Thu 2026-10-01 22:44:09 JST
$J -b -1
Oct 01 19:57:29 demo-host myapp[1200]: Started order worker
Oct 01 19:58:29 demo-host myapp[1201]: DB connection refused: 127.0.0.1:5432
Oct 01 19:59:29 demo-host nginx[1202]: GET /api/orders 200
-b -1 は「再起動の直前に何が起きていたか」を見るときの定番です。ただし、ジャーナルが永続化されていない(/run に置かれている)環境では、再起動で前回分が消えるため -b -1 は表示できません。永続化は後述の journald.conf で設定します。
件数・順番・検索(-n / -r / -f / -g / -t)
$J -n 2 # 末尾2件
$J -r -n 2 # 新しい順に2件
Oct 01 22:44:09 demo-host myapp[1209]: Out of disk space on /var
Oct 01 22:35:49 demo-host CRON[1208]: (root) CMD (/usr/local/bin/backup.sh)
(上は -r -n 2 の結果。-n 2 だけなら同じ2件が古い順に出ます)
$J -g 'time(d )?out'
-- Boot c0ed600dfb174b13a1b1d6f8d7595860 --
Oct 01 22:00:49 demo-host nginx[1205]: upstream timed out (110: Connection timed out)
Oct 01 22:10:49 demo-host myapp[1206]: Failed to send mail: timeout
-g は MESSAGE の中だけを正規表現で検索します。パターンに大文字が無ければ大文字小文字を区別せず、大文字を含めば区別します(--case-sensitive= で明示も可)。
-t CRON のようにプログラム名(SYSLOG_IDENTIFIER)で絞ることもできます。
-f(追従)はジャーナルを書き続ける journald が必要なため、この環境では未実行です。実際のサーバーでは journalctl -f -u myapp.service で、tail -f と同じように新しい行が流れてきます(Ctrl+C で終了)。
フィールドで直接絞る
$J _PID=1201
$J _SYSTEMD_UNIT=nginx.service + SYSLOG_IDENTIFIER=CRON
Oct 01 19:58:29 demo-host myapp[1201]: DB connection refused: 127.0.0.1:5432
Oct 01 19:59:29 demo-host nginx[1202]: GET /api/orders 200
-- Boot c0ed600dfb174b13a1b1d6f8d7595860 --
Oct 01 22:00:49 demo-host nginx[1205]: upstream timed out (110: Connection timed out)
Oct 01 22:35:49 demo-host CRON[1208]: (root) CMD (/usr/local/bin/backup.sh)
別のフィールドを並べると AND、+ で区切ると OR になります。よく使うフィールドは _SYSTEMD_UNIT、_PID、_COMM(実行ファイル名)、_UID、SYSLOG_IDENTIFIER、PRIORITY、_BOOT_ID です。
出力形式を変える(-o)
| 形式 | 用途 | 例(同じ1件) |
|---|---|---|
| short(既定) | 人が読む | Oct 01 22:44:09 demo-host myapp[1209]: Out of disk space on /var |
| short-iso | 年とタイムゾーンを入れる | 2026-10-01T22:44:09+09:00 demo-host myapp[1209]: Out of disk space on /var |
| cat | 本文だけ | Out of disk space on /var |
| verbose | 全フィールド | 下の出力 |
| json | 1行1JSON(jq向け) | 下の出力 |
| json-pretty | 整形JSON | 下の出力 |
$J -o verbose -n 1
Thu 2026-10-01 22:44:09.699986 JST [s=e3161c78c8ac4ed79af4b61c5bb6b09b;i=a;b=c0ed600dfb174b13a1b1d6f8d7595860;m=254582f40;t=65cc79c3c2a92;x=3b1c9e543e845c6e]
_MACHINE_ID=3c0397bdf797464c9fced46296ed5e4d
_HOSTNAME=demo-host
_SYSTEMD_UNIT=myapp.service
SYSLOG_IDENTIFIER=myapp
_TRANSPORT=journal
_BOOT_ID=c0ed600dfb174b13a1b1d6f8d7595860
PRIORITY=2
_PID=1209
MESSAGE=Out of disk space on /var
verbose で「どんなフィールドがあるか」を確認してから、フィールド=値 や jq で絞ると効率よく探せます。
$J -o json -n 1
{"PRIORITY":"2","_SYSTEMD_UNIT":"myapp.service","_PID":"1209","_TRANSPORT":"journal","MESSAGE":"Out of disk space on /var","__REALTIME_TIMESTAMP":"1790862249699986","_HOSTNAME":"demo-host", ...(__CURSOR・_BOOT_ID などが続く)}
ここで2つ注意点があります。PRIORITY も _PID も文字列("2")で、__REALTIME_TIMESTAMP はマイクロ秒(1970年からの経過)です。jq で比較・計算するときは tonumber が必要です。
-o json-pretty にすると整形して表示され、--output-fields=MESSAGE,PRIORITY で出すフィールドを減らせます(カーソル・時刻・ブートIDなどの基本フィールドは常に付きました)。
-o jsonとjqで集計する(コピペ用)
jq 1.7 で実行しました。
エラー件数をサービス別に数える
$J -p err -o json | jq -s 'group_by(._SYSTEMD_UNIT) | map({unit: .[0]._SYSTEMD_UNIT, count: length}) | sort_by(-.count)'
[
{
"unit": "myapp.service",
"count": 3
},
{
"unit": "nginx.service",
"count": 1
}
]
-s(slurp)で1行1JSONを配列にまとめてから group_by するのがポイントです。
時刻・優先度・ユニット・本文をTSVで出す
$J -p warning -o json | jq -r '[(.__REALTIME_TIMESTAMP|tonumber/1000000|strflocaltime("%H:%M:%S")), .PRIORITY, ._SYSTEMD_UNIT, .MESSAGE] | @tsv'
19:58:29 3 myapp.service DB connection refused: 127.0.0.1:5432
21:59:09 4 myapp.service slow query 1830ms: SELECT * FROM orders
22:00:49 3 nginx.service upstream timed out (110: Connection timed out)
22:10:49 3 myapp.service Failed to send mail: timeout
22:44:09 2 myapp.service Out of disk space on /var
TSVにしておくと、スプレッドシートに貼ったり sort・uniq -c に渡したりできます。
1時間ごとの件数を数える
$J -o json | jq -rs 'map(.__REALTIME_TIMESTAMP|tonumber/1000000|strflocaltime("%Y-%m-%d %H:00")) | group_by(.) | map("\(.[0])\t\(length)")[]'
2026-10-01 19:00 3
2026-10-01 21:00 2
2026-10-01 22:00 5
本文の条件で抜き出して必要な項目だけ出す
$J -o json -u myapp.service | jq -c 'select(.MESSAGE|test("slow query")) | {pid: ._PID, msg: .MESSAGE}'
{"pid":"1204","msg":"slow query 1830ms: SELECT * FROM orders"}
| jqの書き方 | 意味 |
|---|---|
jq -s |
全行を1つの配列にまとめる(集計用) |
jq -r |
文字列を引用符なしで出す |
select(条件) |
条件に合う行だけ残す |
test("正規表現") |
文字列の正規表現マッチ |
tonumber |
"2" を数値 2 に |
strflocaltime("%H:%M") |
UNIX秒をローカル時刻の文字列に |
大量のログを処理するときは、先に -u・-p・--since で journalctl 側を絞ってから jq に渡すと速く済みます。
容量の確認と削減(--disk-usage / --vacuum)
journalctl --disk-usage
Archived and active journals take up 16.0M in the file system.
ジャーナルは「現在書き込み中のファイル(active:system.journal)」と「切り替え済みのファイル(archived:system@...journal)」に分かれます。上の状態(active と archived が各8MB)で削除を試しました。
sudo journalctl --vacuum-files=1
Vacuuming done, freed 0B of archived journals from /var/log/journal.
Deleted archived journal /var/log/journal/c1d60f590676409fadd11ab338e333b8/system@e3161c78c8ac4ed79af4b61c5bb6b09b-0000000000000001-00065cc6f0a8e000.journal (8.0M).
Vacuuming done, freed 8.0M of archived journals from /var/log/journal/c1d60f590676409fadd11ab338e333b8.
続けて --vacuum-size=1M を実行しても、freed 0B で active の8MBは残りました。vacuum が消すのはアーカイブ済みファイルだけです。今のファイルも対象にしたい場合は、journald が動いている環境で --rotate と組み合わせます。
sudo journalctl --rotate --vacuum-time=2weeks
| コマンド | 意味 |
|---|---|
--vacuum-size=500M |
合計が500MB以下になるまで古い順に削除 |
--vacuum-time=2weeks |
2週間より古いファイルを削除(1d、6h、3months なども可) |
--vacuum-files=5 |
アーカイブ済みファイルを5個まで残す |
--rotate |
active をアーカイブ化(journald 稼働中のみ。この環境では未実行) |
一時的に減らすのは vacuum、ずっと上限を決めておくのは journald.conf と使い分けます。
journald.confで永続化と容量を設定する
設定は /etc/systemd/journald.conf を直接編集するより、/etc/systemd/journald.conf.d/ にドロップインファイルを置く方法が推奨されています(Ubuntu 24.04 の journald.conf 冒頭のコメントにもそう書かれています)。
# /etc/systemd/journald.conf.d/50-retention.conf
[Journal]
Storage=persistent
SystemMaxUse=1G
SystemKeepFree=2G
SystemMaxFileSize=128M
MaxRetentionSec=1month
sudo mkdir -p /etc/systemd/journald.conf.d
sudo nano /etc/systemd/journald.conf.d/50-retention.conf
sudo systemctl restart systemd-journald
journalctl --disk-usage
この反映手順は journald が動いていないためこの環境では未実行です。設定項目の意味と既定値は次のとおりです(systemd 255 の journald.conf に書かれた既定値と、journald.conf の man ページによる)。
| 項目 | 既定値 | 意味 |
|---|---|---|
| Storage | auto | persistent=/var/log/journal に保存、volatile=/run(再起動で消える)、auto=/var/log/journal があれば永続、none=保存しない |
| SystemMaxUse | 空(ファイルシステムの10%、上限4G) | /var/log/journal の合計上限 |
| SystemKeepFree | 空(ファイルシステムの15%、上限4G) | 最低限残す空き容量 |
| SystemMaxFileSize | 空(SystemMaxUse の1/8) | 1ファイルの上限。超えるとアーカイブ化 |
| RuntimeMaxUse | 空(/run の10%、上限4G) | /run/log/journal(一時保存)の上限 |
| MaxRetentionSec | 空(無制限) | これより古いエントリを含むファイルを削除 |
| MaxFileSec | 1month | 1ファイルに入れる期間の上限 |
| RateLimitIntervalSec / RateLimitBurst | 30s / 10000 | 一定時間に一定件数を超えたログを間引く |
| ForwardToSyslog | no | rsyslog などへ転送 |
Storage=auto は「/var/log/journal ディレクトリがあれば永続化」という意味です。ディレクトリが無いディストリビューションでは /run に保存され、再起動で前回分が消えます。その場合は Storage=persistent を書くか、sudo mkdir -p /var/log/journal してから journald を再起動します。
flowchart LR
A["サービスの標準出力・syslog・カーネル"] --> B[systemd-journald]
B -->|Storage=volatile| C["/run/log/journal(再起動で消える)"]
B -->|Storage=persistent| D["/var/log/journal(残る)"]
D --> E[journalctl で検索]
C --> E
B -->|ForwardToSyslog=yes| F["rsyslog → /var/log/syslog"]
よくあるつまずきと対処
No journal files were found.
$ journalctl
No journal files were found.
-- No entries --
| 原因 | 確認 | 対処 |
|---|---|---|
| journald が動いていない(コンテナ、WSLの一部構成など) | ps -p 1 -o comm= が systemd でない |
アプリのログはファイル・標準出力・docker logs で見る |
| 保存先が無い・Storage=none | ls /var/log/journal /run/log/journal |
Storage を設定して journald 再起動 |
| 別のファイルを読みたい | — | --file= / -D を指定 |
この記事の検証用コンテナでは PID 1 が systemd ではないため、実際にこの表示になりました。
一般ユーザーだと一部しか見えない(systemd-journal グループ)
ジャーナルファイルを root:systemd-journal・権限 640 で置き、一般ユーザー(t89user)で実行しました。
$ journalctl -n 2
Hint: You are currently not seeing messages from other users and the system.
Users in groups 'adm', 'systemd-journal' can see all messages.
Pass -q to turn off this notice.
No journal files were opened due to insufficient permissions.
systemd-journal または adm グループに入れると、全体のログが読めるようになります。
sudo usermod -aG systemd-journal t89user
$ journalctl -n 2
Oct 01 22:35:49 demo-host CRON[1208]: (root) CMD (/usr/local/bin/backup.sh)
Oct 01 22:44:09 demo-host myapp[1209]: Out of disk space on /var
グループ追加は次回ログイン(新しいセッション)から有効です。今のシェルで試すなら newgrp systemd-journal か、いったんログアウトします。
その他のつまずき
| 症状 | 原因 | 対処 |
|---|---|---|
-b -1 で前回分が出ない |
永続化されていない | Storage=persistent |
-u で何も出ない |
ユニット名の誤り、または別のユーザーサービス | -F _SYSTEMD_UNIT で確認。ユーザーサービスは --user -u |
| 時刻が9時間ずれて見える | UTC で書いた、または --utc 指定 |
--since はローカル時刻で書く |
| 出力が画面ごとに止まる | ページャー(less)が使われている | --no-pager、またはパイプで渡す |
ログが間引かれる(Suppressed N messages) |
RateLimitBurst を超えた | アプリの出力量を見直すか、ユニットごとに LogRateLimitIntervalSec= 等で調整 |
| ディスクを圧迫している | 上限が大きい | --vacuum-size で減らし、SystemMaxUse を設定 |
よくある質問
Q. Docker コンテナのログを journalctl で見られますか?
A. Docker のログドライバーを journald に設定すると、journalctl CONTAINER_NAME=コンテナ名 のように見られます。既定の json-file ドライバーの場合は docker logs を使います。
Q. 別のサーバーのジャーナルを手元で調べられますか?
A. はい。/var/log/journal/<machine-id>/ のファイルをコピーし、journalctl -D コピー先 または --file=ファイル で読めます。この記事の実行結果もすべて --file で読んだものです。壊れていないかは journalctl --file=... --verify(結果は PASS: ...)で確認できます。
Q. ログを全部消すにはどうすればよいですか?
A. sudo journalctl --rotate のあと sudo journalctl --vacuum-time=1s を実行すると、アーカイブ化されたファイルがすべて削除されます。調査に必要なログが残っていないか確認してから実行してください。
まとめ
- まずは
journalctl -xeu サービス名。絞り込みは-u(サービス)・-p(優先度)・--since(時間)・-b(起動回)の組み合わせ -p errは err 以上(crit なども含む)。範囲は-p warning..err-u同士・+は OR、種類の違う条件は AND。存在しないユニット名でもエラーにならないので-F _SYSTEMD_UNITで確認-o jsonの値は文字列、時刻はマイクロ秒。jq ではtonumberと-s(slurp)で集計する- vacuum はアーカイブ済みファイルだけを削除。上限は journald.conf の
SystemMaxUseなどで決める - 前回起動のログを残すには
Storage=persistent(または /var/log/journal を作る) - 一般ユーザーで見えないときは systemd-journal グループに追加し、再ログイン
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「journalctlの使い方|目的別コマンド逆引き一覧と絞り込み例」
株式会社RJCでは、ログ調査の手順を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。