※本ページには広告(アフィリエイトプログラム等)が含まれます。
※本ページには広告(アフィリエイトプログラム等)が含まれます。掲載しているログと件数は 2026年8月16日時点で運用中の VPS(Debian 12・メモリ 958MB)から採取した実測値です。ユーザー名と IP はマスクしています。
🎯 結論:AI に投げる前に集計する。7 日分 157 件のエラーは、実際に見るべき 9 件まで減った
結論から書きます。サーバーのログを AI に読ませるとき、生ログをそのまま貼るのがいちばん効率が悪いです。
手元の VPS で直近 7 日間のエラーを数えたら 157 件ありました。ところが正規化して集計すると、137 件(87%)は SSH ポートへの総当たりスキャンで、対処のしようがないノイズでした。本当に人間が見るべきだったのは残りの 9 件です。
- ✅ まず `wc -l` で件数を数える → 規模が分からないと打ち手が決まらない
- ✅ IP・ポート・ユーザー名を正規化してから `uniq -c` → 157 行が 8 パターンに畳まれる
- ✅ ノイズを除いた残りだけ AI に投げる → トークンも時間も 1 桁減る
- ⚠️ ログには IP・ユーザー名・パスが混ざる → 外部の AI に投げる前にマスクする
- ⛔ 「このログを見て」と丸投げ → ノイズに引きずられた回答が返る
なぜ生ログをそのまま投げてはいけないのか
ログの大半は同じ 1 行の繰り返し
サーバーのエラーログは、種類が多いのではなく同じ行が大量に繰り返されるのが普通です。IP やポート番号だけが違うので、テキストとしては全部別行に見えます。
そのまま貼ると、AI は「大量に発生している事象」を重要だと解釈します。実際にはただのスキャンなのに、そこに引きずられた回答が返ってきます。
トークンを無駄に使う
157 行を貼るのと、8 パターンに畳んで貼るのとでは、消費するトークンが 1 桁違います。有料 API を使っているなら、そのまま費用差になります。
機密が混ざる
ログには接続元 IP、OS のユーザー名、ホームディレクトリのパスがそのまま出ます。外部のサービスに投げる前に、何が含まれているかを自分で把握しておく必要があります。
手順 1:まず件数を数える
優先度で絞って数える
最初にやるのは読むことではなく数えることです。`journalctl` は優先度で絞れるので、エラー以上だけを対象にします。
$ journalctl --since "-7d" -p err --no-pager | wc -l
157
7 日で 157 件。この数字が出た時点で「全部読む」という選択肢が消えます。人力で読む上限はせいぜい数十件です。
どのサービスが出しているのか
次に発生源を数えます。JSON 出力にすると機械的に集計できます。
$ journalctl --since "-7d" -p err --no-pager -o json \
| python3 -c "
import sys, json, collections
c = collections.Counter()
for line in sys.stdin:
d = json.loads(line)
c[d.get('_SYSTEMD_UNIT') or d.get('SYSLOG_IDENTIFIER') or '?'] += 1
for k, v in c.most_common(8):
print(f'{v:6d} {k}')
"
105 ssh.service
32 sshd
7 session-631657.scope
4 session-631659.scope
2 session-617752.scope
105 + 32 = 137 件が SSH 由来でした。全体 157 件の 87% です。この時点で「SSH のノイズを除いたら何が残るか」という問いに変わります。
ディスクの使用量も見ておく
$ journalctl --disk-usage
Archived and active journals take up 503.5M in the file system.
メモリ 958MB・ディスク 99GB の VPS で journal が 503.5MB。上限を設定していないと際限なく増えるので、`SystemMaxUse` を明示しておくと安全です。
手順 2:正規化してパターンに畳む
IP・ポート・ユーザー名を伏せてから数える
ここが一番効きます。変動する部分を置換してから `uniq -c` にかけると、157 行が一気に畳まれます。マスクを兼ねられるので、外部の AI に投げる前処理としても都合がいいです。
$ journalctl --since "-7d" -p err --no-pager -o cat \
| sed -E "s/[0-9]{1,3}(\.[0-9]{1,3}){3}/<IP>/g;
s/port [0-9]+/port <N>/g;
s/user [A-Za-z0-9_.-]+/user <USER>/g" \
| sort | uniq -c | sort -rn | head -8
実際に出てきた 8 パターン
手元の VPS で実行した結果がこれです。
| 件数 | メッセージ | 正体 |
|---|---|---|
| 76 | kex_exchange_identification: Connection closed by remote host | スキャン |
| 25 | kex_exchange_identification: read: Connection reset by peer | スキャン |
| 23 | banner line contains invalid characters | スキャン |
| 7 | pam_unix(sudo:auth): conversation failed | ⚠️ 要確認 |
| 7 | pam_unix(sudo:auth): auth could not identify password | ⚠️ 要確認 |
| 5 | client sent invalid protocol identifier "GET / HTTP/1.0" | スキャン |
| 4 | client sent invalid protocol identifier "\026\003\001\001" | スキャン |
| 2 | a password is required ; USER=root | ⚠️ 要確認 |
157 行が 8 行になりました。この 8 行なら人間がそのまま読めますし、AI に投げるコストもほぼゼロです。
ノイズの見分け方
上位 3 つの `kex_exchange_identification` は、SSH の鍵交換に入る前に切断された記録です。認証にすら到達していないので、鍵認証にしてある限り実害はありません。
面白いのは下のほうの 2 つです。`"GET / HTTP/1.0"` は SSH ポートに HTTP を投げてきたスキャナ、`"\026\003\001\001"` は TLS のハンドシェイク(0x16 0x03 0x01)を投げてきたスキャナです。ポート番号を変えていても、片っ端から総当たりされていることが分かります。
手順 3:残ったものだけを AI に投げる
ノイズを除外して抽出する
スキャン由来を除くと、残るのは sudo 関連の 9 件でした。ここだけ切り出します。
$ journalctl --since "-7d" -p err --no-pager -o cat \
| grep -v "kex_exchange_identification" \
| sed -E "s/\[[A-Za-z0-9_-]+\]/[<USER>]/g; s#/home/[A-Za-z0-9_-]+#/home/<user>#g"
置換をここでも噛ませておくのが要点です。ユーザー名とホームディレクトリのパスがそのまま出るので、外部の AI に渡すなら必須の一手間になります。
聞き方を具体的にする
投げるときは「見て」ではなく、判断してほしいことを明示します。
$ journalctl --since "-7d" -p err --no-pager -o cat \
| grep -v kex_exchange_identification \
| claude -p "このログのうち、対処が必要なものと、
無視してよいものに分類してください。
判断の根拠も 1 行ずつ付けてください。"
今回の 9 件は「非対話のシェルから `sudo` を実行してパスワードを求められ、入力できずに失敗した」記録でした。攻撃ではなく自分の運用の副作用です。ここまで絞れていれば、AI の回答も検証しやすくなります。
それでも自分で確かめる
AI の分類は出発点であって結論ではありません。「無視してよい」と言われたものこそ、1 件だけ手で裏を取るくらいでちょうどいいです。
機密ログはローカル LLM に投げる
外に出せないログがある
アクセスログには利用者の IP が入りますし、アプリケーションログにはメールアドレスやトークンが混ざることがあります。置換で消しきれる自信がないものは、そもそも外に出さないのが確実です。
Ollama をローカルに置く
その場合はローカル LLM を使います。手元のマシンで動かして、ログはネットワークの外に出しません。
$ ollama run qwen2.5-coder:7b "次のログで対処が必要なものを挙げて" < errors.txt
⚠️ VPS 上で動かすなら容量に注意
今回ログを採取した VPS はメモリ 958MBです。7B クラスのモデルは載りません。ローカル LLM を動かすなら、ログを収集するサーバーとは別に、メモリに余裕のある環境を用意してください。
丸投げしないための鉄則
件数を先に出す
読む前に数える。157 件なのか 5 件なのかで、打ち手がまったく変わります。
正規化してから渡す
変動部分を置換して `uniq -c`。マスクと圧縮を同時にやれます。今回は 157 行 → 8 行まで畳めました。
AI の答えを別経路で確かめる
「無視してよい」という回答をそのまま信じない。1 件でいいので元のログを開いて突き合わせます。ログ調査でいちばん高くつくのは、ノイズを重大事だと誤認することと、その逆です。
よくある質問
Q1. journalctl のエラーは何件くらいが正常ですか?
結論:件数ではなく内訳で判断します。今回の VPS は 7 日で 157 件ありましたが、137 件(87%)は SSH ポートへのスキャンでした。インターネットに露出したサーバーなら、この種のノイズは日常的に出ます。
Q2. kex_exchange_identification のエラーは危険ですか?
結論:鍵認証のみにしてあるなら実害はありません。SSH の鍵交換に入る前に切断された記録で、認証にすら到達していません。ただし件数が急増したら、遮断の設定を見直す合図にはなります。
Q3. ログを AI に投げるとき何をマスクすべきですか?
結論:IP アドレス・OS のユーザー名・ホームディレクトリのパス・トークンの 4 つが最低ラインです。`sed` で置換してから渡せば、マスクとログの圧縮を同時に達成できます。
Q4. ローカル LLM は VPS 上で動かせますか?
結論:メモリ次第です。今回の VPS はメモリ 958MB で、7B クラスのモデルは載りません。ログ収集用のサーバーと、モデルを動かす環境は分けて考えてください。
Q5. journal が肥大化したらどうすればいいですか?
結論:`SystemMaxUse` を明示します。今回の環境では journal が 503.5MB を占めていました。上限を設定しておかないと、ディスクを圧迫してから気づくことになります。
まとめ
AI にサーバーのログを読ませるときは、投げる前に集計するかどうかで結果がまったく変わります。今回の実測では 7 日 157 件 → 8 パターン → 要対処 9 件まで絞れました。
- 🎯 まず数える → `journalctl -p err | wc -l`
- 🎯 正規化して畳む → `sed` で置換してから `uniq -c`(マスクも兼ねる)
- 🎯 残りだけ投げる → 判断してほしいことを明示して聞く
数値は 2026年8月16日時点で運用中の VPS から採取したものです。環境が違えば内訳も変わるので、まずは自分のサーバーで同じコマンドを 1 回叩いてみてください。サーバーの初期構築から見直すならさくらの VPS の初期セットアップ、常駐プロセスの管理はsystemd のユニットファイル、遮断の設定はufw の設定にまとめています。
