TechQuant Blog

journalctl を本気で使いこなす: systemd 時代のログ調査実践ガイド

8分で読める

きっかけは深夜2時の障害対応だった。Raspberry Pi 5 で動かしている自動化ジョブが静かに止まっていて、原因がさっぱり分からない。/var/log/ を漁っても、お目当てのログがない。systemd ユーザータイマーで動かしているのだから当たり前なのだが、普段 tail でしかログを見ていなかった自分には盲点だった。

その日から journalctl に本気で向き合うことになった。3週間ほど使い倒して、ようやく「これがないと困る」レベルまで手に馴染んだので、自分の備忘を兼ねて実践的な使い方を書き残しておく。

対象は Ubuntu / Debian 系で systemd を使っている人。Raspberry Pi OS でも同じ。

なぜ journalctl なのか

結論から言うと、systemd の時代にログファイルを手で探し回る方が異常だった、という話に尽きる。/var/log/syslog/var/log/auth.loggrep するのは、もはや古い作法に近い。systemd 配下のユニットはすべて journald が吸い上げていて、journalctl 一本でアクセスできる。

何が嬉しいか。ざっくり3つ。

  • ユニット単位で絞れる(-u)
  • 時間範囲で切れる(--since / --until)
  • 優先度でフィルタできる(-p)

特にユニット単位で絞れるのが大きい。cron の時代、複数のジョブのログが /var/log/syslog に全部混ざって流れてきて、grep の腕力で戦うしかなかった。以前書いたcron から systemd timer への移行の記事でも触れたが、このログ分離こそが systemd に切り替えた一番の見返りかもしれない。

毎日使うコマンド10個

特定ユニットの今日のログを見る

一番よく打つやつ。

journalctl --user -u make_money-daily_content.service --since=today

--user はユーザー単位の systemd ユニットを見るためのフラグ。system 側のユニット(ssh.service など)を見るなら sudo journalctl -u ssh でよい。

追従する(tail -f 相当)

journalctl --user -u make_money-daily_content.service -f

-f は follow。ジョブ実行中にリアルタイムで流したい時はこれ。ちなみに -n 50 を付けると直近50行を表示してから追従してくれる。

エラーだけ抽出

journalctl --user -p err --since=today

-p は priority。値は syslog のレベルと同じで、emerg(0)から debug(7)まで。-p warning にすると warning 以上が全部出る。

時間範囲で切る

journalctl --user -u make_money-hourly_strategy.service \
  --since "2026-04-20 09:00" --until "2026-04-20 12:00"

相対時刻も使える。--since "2 hours ago" とか --since yesterday。このあたりは systemd の時刻パーサーが優秀で、英語表記ならほぼ通る。

直近の起動セッションだけ

journalctl -b

前回の起動以降のログ全部。-b -1 で1つ前のブート、-b -2 でさらにその前。Raspberry Pi が勝手に再起動していた時の原因調査で何度か助かった。

容量を確認する

journalctl --disk-usage

これを忘れていて、Raspberry Pi の microSD が気付いたら2GB くらい journal で埋まっていたことがある。後述するが永続化の設定を入れると、そこそこ食う。

現場で刺さる応用テクニック

JSON で吐いて jq で料理する

これが意外と便利。

journalctl --user -u make_money-daily_content.service \
  --since=today -o json | jq -r 'select(.PRIORITY <= "3") | .MESSAGE'

-o json を付けると構造化ログとして取り出せる。スクリプトで集計したい時、テキスト出力を正規表現でごねるよりずっと楽。ログ解析を自動化したいなら、軽量なサーバーで動かしてしまうのも手だ。お名前.comの高性能VPS のような月額数百円の環境でも十分に回る。

複数ユニットを一度に

journalctl --user -u "make_money-*" --since=today

ワイルドカードが効く。プロジェクト prefix を統一しておくと、ここが一気に楽になる。自分の環境では make_money-* で10個のタイマーを一括で見ている。

特定プロセスのログを追いかける

journalctl _PID=12345

アンダースコア始まりのフィールドは journal のネイティブフィールド。_SYSTEMD_UNIT, _COMM(コマンド名), _UID あたりをよく使う。journalctl _COMM=python3 で Python プロセスのログだけ拾える。

カーネルログだけ

journalctl -k --since=today

dmesg の代替。-k は kernel。OOM killer が走った時とか、USB デバイスが落ちた時とか、ハードウェア寄りの問題はここに出る。

永続化の設定(これをやらないと意味が半減する)

デフォルトでは、多くのディストリで journal は揮発(再起動で消える)になっている。以下のコマンドで確認できる。

cat /etc/systemd/journald.conf | grep Storage

#Storage=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 を編集。

[Journal]
Storage=persistent
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=2week

上限500MB、2週間で自動削除。Raspberry Pi のような microSD で動かす機器では特に重要だ。microSD の寿命は書き込み量に直結するので、ここを野放しにするのはよろしくない。この手のエッジ運用については以前Raspberry Pi 5 をホームサーバーにする Tipsでも触れた。

手動で古いログを削除する

sudo journalctl --vacuum-time=7d
sudo journalctl --vacuum-size=200M

7日より古いものを削除、あるいは合計サイズが200MBを超えないように削除。障害調査後に一気に吐き出されたログを畳みたい時に使う。

失敗談: ログが見えない時に疑うこと

手が滑って3時間溶かした話を書いておく。

ある日、journalctl --user -u make_money-hourly_strategy.service で何も出なかった。systemctl --user status では active (running) と言っている。なのにログがない。

結論から言うと、ExecStart で起動したスクリプト内部で exec > /dev/null 2>&1 していた。過去の cron 時代の名残で、標準出力を捨てる行が残っていたのだ。cron 運用では「cron がメールを送らないように」出力を潰す作法が一般的だが、systemd では journald が stdout/stderr を拾ってくれるのでむしろ邪魔になる。

同じような罠として、以下も一度ハマった。

  • --user を付け忘れて system journal を見に行き「何もない」と焦る
  • ユニット名のタイポ(.service.timer か)
  • 時刻パーサが解釈した範囲が想定とズレている(--since "yesterday" は昨日の 00:00 から)

いずれも基本的なことだが、夜中の障害対応中は見落とす。指差し確認するクセを付けた方がいい。

もう一歩踏み込むなら

journalctl 単体でかなり戦えるが、運用が長期化すると外部への転送を考えたくなる。選択肢としては:

  • systemd-journal-remote で別ホストに集約する
  • Promtail + Loki に流して Grafana で可視化する
  • 軽量なフィルタスクリプトで Slack / ntfy に通知する

自分の運用では、エラーレベルのログを journalctl -p err -f で拾って ntfy.sh に飛ばす薄いスクリプトを走らせている。これだけでも、障害に気付くまでの時間がだいぶ縮んだ。この辺りの通知まわりのツール詰め合わせはDevTools に整理しているので、興味があれば覗いてみてほしい。

結び

journalctl は「触ったことはあるけど本気では使っていない」人がかなり多いコマンドだと思う。自分もその一人だった。ただ、-u--since-p の3つだけでも覚えて常用すると、障害対応の速度が明らかに変わる。

あとは永続化の設定だけは絶対に入れておいてほしい。揮発状態のまま運用していて、再起動後に「さっきのエラー、もう一度見せて」となる瞬間の徒労感は本当にきつい。経験者は語る。

ここに書いた内容は全部、自分の Raspberry Pi と VPS で現役で使っているものだ。もっと効率的な方法があれば教えてほしい。journalctl の沼は、掘れば掘るほど出てくる。