「受信したログを送信元ごとのファイルに分けたいんですが、ホスト名が機器によってばらばらで……」
「障害の時間帯のログだけ、なぜか抜けています」
第4回(前編)では、rsyslogの構成とキュー、受信・転送の設定を見ました。第5回(後編)では、受け取ったログをどんな形で、どこに書くか(テンプレート・振り分け)、どう守るか(TLS・RELP)、そしてログが突然消える原因(レート制限)を扱います。
テンプレート
| 組み込みテンプレート | 出力の形 | 主な用途 |
|---|---|---|
| RSYSLOG_TraditionalFileFormat | Sep 26 10:15:01 web01 sshd[812]: …(秒まで、年とタイムゾーンなし) | RHEL の既定(ファイル) |
| RSYSLOG_FileFormat | 2026-09-26T10:15:01.123456+09:00 web01 sshd[812]: … | omfile の本来の既定。集約先ではこちらを推奨 |
| RSYSLOG_TraditionalForwardFormat | <PRI> + RFC 3164 の形 | omfwd の既定 |
| RSYSLOG_SyslogProtocol23Format | <PRI>1 時刻 ホスト名 アプリ名 PROCID MSGID 構造化データ MSG +改行 | RFC 5424 で転送する |
# 送信元のホスト名と日付でファイルを分ける(動的ファイル)
template(name="PerHostDaily" type="string"
string="/var/log/remote/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%.log")
ruleset(name="remote") {
action(type="omfile" dynaFile="PerHostDaily" template="RSYSLOG_FileFormat")
}
# RFC 5424 の形式で転送する
action(type="omfwd" target="192.0.2.50" port="514" protocol="tcp"
template="RSYSLOG_SyslogProtocol23Format")
- テンプレートには、ファイル名を決めるもの(
dynaFile=)と、1行の形を決めるもの(template=)の2つの使い道がある %HOSTNAME%はメッセージの中のホスト名で、送信元が自由に書ける(後の節)type="list"で、項目を1つずつ並べる書き方もある。組み込みと同じ名前で定義するとエラーになる- 年とタイムゾーンのない形式は、集約先での突き合わせを難しくする(第7回、連載「NTP入門」)。集約先では
RSYSLOG_FileFormatを使う
フィルターの3つの書き方
| 書き方 | 例 | 向いている場面 |
|---|---|---|
| セレクター | mail.warning、*.info;mail.none | facility と severity だけで分ける |
| プロパティベース | :programname, isequal, “sshd” | 1つの項目を1つの条件で比べる |
| RainerScript の if | if $programname == “sshd” and $syslogseverity <= 4 then | 複数の条件、入れ子、正規表現。推奨 |
mail.warning action(type="omfile" file="/var/log/mail-warn.log")
:programname, isequal, "sshd" action(type="omfile" file="/var/log/sshd.log")
:msg, contains, "I/O error" action(type="omfile" file="/var/log/io-error.log")
if $programname == "sshd" and $syslogseverity <= 4 then {
action(type="omfile" file="/var/log/sshd-warn.log")
}
if re_match($msg, "Failed password for .* from") then {
action(type="omfile" file="/var/log/ssh-fail.log")
}
- severityは数値が小さいほど重大で、
$syslogseverity <= 4はwarning以上。数値で比べるときは引用符を付けない $syslogseverity-textはinfoのような文字列なので、大小を比べられない- セレクターの
mail.warningはwarning以上、mail.=warningはwarningだけ
送信元・文字列で振り分ける
ruleset(name="remote") {
if $fromhost-ip == "192.0.2.21" or $fromhost-ip == "192.0.2.22" then {
if $syslogseverity <= 6 then action(type="omfile" file="/var/log/remote/web.log")
stop
}
if $syslogfacility-text == "mail" then {
if $programname == "postfix" then action(type="omfile" file="/var/log/remote/postfix.log")
else if $programname == "dovecot" then action(type="omfile" file="/var/log/remote/dovecot.log")
else action(type="omfile" file="/var/log/remote/maillog")
stop
}
action(type="omfile" file="/var/log/remote/others.log")
}

- 「送信元で分類」「文字列で分類」を1つのルールセットにまとめた例。上から順に評価される
stopは、そのメッセージの処理をそこで終える(旧形式の& ~に当たる)。書かないと下のothers.logにも書かれる- Webサーバー2台からのdebug(7)は捨て、info以上だけを残す。stopをifの外に置くことで、捨てる分も下へ流れない
- postfixのタグ
postfix/smtpd[1234]:の$programnameはpostfix(既定では/の前まで) - 比較の演算子:
==・!=・contains・startswith・<=など。正規表現はre_match()
送信元ごとのファイルに保存する
冒頭の「ホスト名がばらばら」は、どのプロパティを使うかの問題です。
| プロパティ | 値の出どころ | 注意 |
|---|---|---|
| %HOSTNAME% | メッセージの中のホスト名 | 送信元が自由に書ける(偽れる)。ホスト名を入れない機器もある |
| %FROMHOST% | 直接の送信元の IP アドレスを逆引きした名前 | 逆引きの待ち時間。中継を挟むと中継の名前になる |
| %FROMHOST-IP% | 直接の送信元の IP アドレス | 確実だが、中継を挟むと中継の IP になる |
template(name="PerHostFile" type="string"
string="/var/log/remote/%FROMHOST-IP%/%$YEAR%%$MONTH%%$DAY%.log")
ruleset(name="remote") {
action(type="omfile" dynaFile="PerHostFile"
dirCreateMode="0750" fileCreateMode="0640"
dynaFileCacheSize="200")
}
module(load="imudp")
input(type="imudp" port="514" ruleset="remote")
- 中継を挟まないなら、%FROMHOST-IP%が確実
dynaFileCacheSize(開いておくファイルの数、既定10)が送信元の数より少ないと、開閉を繰り返して遅くなる- 日付入りのファイルはlogrotateでは消えないため、古いファイルを消す仕組みを別に用意する(第7回)
TLSの設定(受信側)
# ログサーバー logsv01(rsyslog-gnutls が必要)
global(
DefaultNetstreamDriverCAFile="/etc/pki/rsyslog/ca.pem"
DefaultNetstreamDriverCertFile="/etc/pki/rsyslog/logsv01-cert.pem"
DefaultNetstreamDriverKeyFile="/etc/pki/rsyslog/logsv01-key.pem"
)
module(load="imtcp"
StreamDriver.Name="gtls" # OpenSSL を使うなら "ossl"
StreamDriver.Mode="1" # 1 = TLS だけを受け付ける
StreamDriver.AuthMode="x509/name" # 相手の証明書の名前を確かめる
PermittedPeer=["*.corp.example.jp"])
input(type="imtcp" port="6514" ruleset="remote")

- 用意するもの:ログサーバーの証明書と秘密鍵、送信元の証明書を確かめるためのCA証明書。社内CAで発行するのが一般的(連載「証明書入門」第6回・第9回)。秘密鍵はrootだけが読めるようにする
- 暗号化の仕組み(ドライバー)は、gtls(GnuTLS、rsyslog-gnutls)かossl(OpenSSL、rsyslog-openssl)を選ぶ
x509/nameとPermittedPeerで、許可した名前の証明書を持つ送信元だけを受け付ける(送信元にも証明書が要る=相互認証。連載「証明書入門」第7回)module()に書いたTLSの設定は、すべてのimtcpの入力に効く。平文の514とTLSの6514を1台で受けるときは、TLSの項目(StreamDriver.Modeなど)をinput()側に書く(8.2310以降)- ポートは6514/tcp(RFC 5425)。firewalldとSELinuxは第4回
TLSの設定(送信側)と認証モード
# 送信側 web01
global(
DefaultNetstreamDriverCAFile="/etc/pki/rsyslog/ca.pem"
DefaultNetstreamDriverCertFile="/etc/pki/rsyslog/web01-cert.pem"
DefaultNetstreamDriverKeyFile="/etc/pki/rsyslog/web01-key.pem"
)
action(type="omfwd" target="logsv01.corp.example.jp" port="6514" protocol="tcp"
StreamDriver="gtls" StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
StreamDriverPermittedPeers="logsv01.corp.example.jp"
template="RSYSLOG_SyslogProtocol23Format"
queue.type="LinkedList" queue.filename="fwd_tls"
queue.maxDiskSpace="1g" queue.saveOnShutdown="on"
action.resumeRetryCount="-1")
| 認証モード | 確かめること | 使いどころ |
|---|---|---|
| anon | 何も確かめない(暗号化だけ) | 検証用。なりすましを防げない |
| x509/certvalid | 信頼する CA が発行した有効な証明書か | 社内 CA の証明書なら誰でもよい場合 |
| x509/name | 上に加え、証明書の名前(SAN・CN)が許可した名前か | 推奨。許可する名前を PermittedPeer で指定 |
| x509/fingerprint | 証明書のフィンガープリントが一致するか | CA を使わない少数の構成 |
接続はopenssl s_client -connect logsv01.corp.example.jp:6514 -CAfile ca.pem -cert web01-cert.pem -key web01-key.pemで確かめます(連載「証明書入門」第7回)。Windowsでは、Test-NetConnectionと、連載「証明書入門」第7回のPowerShellの方法を使います。TLSが防ぐのは盗聴となりすましで、到達の保証ではありません(次の節)。
RELP(到達を保証する)
# 受信側 logsv01(rsyslog-relp が必要)
module(load="imrelp")
input(type="imrelp" port="20514" ruleset="remote" tls="on"
tls.caCert="/etc/pki/rsyslog/ca.pem"
tls.myCert="/etc/pki/rsyslog/logsv01-cert.pem"
tls.myPrivKey="/etc/pki/rsyslog/logsv01-key.pem"
tls.authMode="name" tls.permittedPeer=["*.corp.example.jp"])
# 送信側 web01
module(load="omrelp")
action(type="omrelp" target="logsv01.corp.example.jp" port="20514" tls="on"
tls.caCert="/etc/pki/rsyslog/ca.pem"
tls.myCert="/etc/pki/rsyslog/web01-cert.pem"
tls.myPrivKey="/etc/pki/rsyslog/web01-key.pem"
tls.authMode="name" tls.permittedPeer=["logsv01.corp.example.jp"]
queue.type="LinkedList" queue.filename="fwd_relp" action.resumeRetryCount="-1")

- RELP(Reliable Event Logging Protocol)は、rsyslogの開発元が作ったプロトコル(RFCではない)。受信側がアプリケーションの層で受け取りを応答し、応答の無い分を再送する
- TCPだけでは、切断の瞬間に送信バッファーにあった分が失われうる。RELPはこれを防ぐ(再送により、まれに重複はありうる)
- RELP自体は暗号化しない。
tls="on"でRELP over TLSにする。到達保証はRELP、暗号化はTLS(第2回) - 標準のポート番号は無い。20514は、RHELのSELinuxで
syslogd_port_tに含まれる(第4回) - 送信側と受信側の両方が対応している必要がある(rsyslog同士、vCenterなど。第6回)。送信側のキューは第4回と同じく付ける
メール発報(ommail)
module(load="ommail")
template(name="mailSubject" type="string" string="[syslog] disk error on %hostname%")
template(name="mailBody" type="string"
string="RSYSLOG Alert\r\nhost: %hostname%\r\nmsg: %msg%")
if $msg contains "I/O error" then {
action(type="ommail" server="mail.corp.example.jp" port="25"
mailFrom="rsyslog@logsv01.corp.example.jp"
mailTo=["infra-alert@corp.example.jp"]
subject.template="mailSubject"
template="mailBody"
action.execOnlyOnceEveryInterval="21600")
}

- 本文のテンプレートは
template=で指定する。body.templateというパラメーターは無く、-N1でエラーになる action.execOnlyOnceEveryInterval="21600":6時間に1通まで。同じ障害で大量のメールが届くのを防ぐ- ommailはSMTP認証とTLSに対応しない。社内の中継用SMTPサーバー(25/tcp)に渡す(連載「メール入門」第8回)
- 条件は文字列の一致なので、メッセージの文言が変わると検知できない。本格的な監視は、監視システムやSIEMで行う(第8回)
レート制限 ― ログが突然消える原因
冒頭の「障害の時間帯のログだけ抜ける」の、よくある原因です。
| どこで | 既定の上限 | 捨てたときの記録 |
|---|---|---|
| journald(サービスごと) | 30秒に 10,000件 | Suppressed N messages from … |
| imjournal(journal → rsyslog) | 600秒に 20,000件 | imjournal: N messages lost due to rate-limiting (20000 allowed within 600 seconds) |
| imuxsock(/dev/log) | 既定は無効(有効時の既定 200件) | … begin to drop messages due to rate-limiting |
| imudp・imtcp の入力 | 既定は無効 | — |
# RHEL の /etc/rsyslog.conf にある imjournal の行を書き換える(2回目の module() は書かない)
module(load="imjournal" StateFile="imjournal.state" UsePid="system"
Ratelimit.Interval="600" Ratelimit.Burst="50000")
$ sudo journalctl --since today | grep -E "Suppressed|rate-limiting"

大量のログを出すサービスがあると、上限を超えた分は黙って捨てられ、集約先では「その時間だけログが無い」ように見えます。まず記録を探し、上限を上げる前に、出している側(デバッグ出力の出しっぱなしなど)を疑います。0にすると制限を外せますが、暴走したアプリケーションにディスクとCPUを奪われるため勧めません。
考えてみよう
- 自分の環境の転送設定で、ログサーバーが1時間止まったらログはどうなりますか。UDP、TCP(キューなし)、TCP+ディスクへの退避、RELPで比べてください。
- 受信したログを送信元ごとのファイルに分けるとき、
%HOSTNAME%と%FROMHOST-IP%のどちらを使いますか。中継サーバーを挟む場合はどうしますか。 - 「ログを暗号化したい」「1件も落とさず届けたい」と言われたら、それぞれ何を設定しますか。両方のときはどうしますか。
ヒント:第4回のDirectとアクションキュー、欠損させない仕組みの限界、この記事のプロパティの表、TLSの認証モード、RELPの図が手がかりです。
まとめ
- テンプレートはファイル名(dynaFile)と1行の形(template)。集約先はRSYSLOG_FileFormat、転送はRFC 5424
- フィルターはRainerScriptのifが推奨。数値は
$syslogseverity <= 4、stopで重複を防ぐ - 送信元ごとのファイルは%FROMHOST-IP%が確実。
dynaFileCacheSizeと古いファイルの削除も - TLSはx509/name+PermittedPeerで相互認証。暗号化するが、到達は保証しない
- 到達保証はRELP(RFCではない)。暗号化も要るならRELP over TLS
- ommailは間隔を空けて1通に。本格的な監視はSIEMで
- 「その時間だけ無い」はレート制限を疑い、記録を探してから出している側を直す
次回は、Windows・ネットワーク機器・ESXiなど、Linux以外のログをどう集めるかを扱います。
連載「syslog入門」全11回
全回の目次と、読む順番・目的別の読み方は、syslog入門の入口のページにまとめています。
- ログとは・なぜ集めるか
- syslogの基本
- Linuxのログの仕組み
- rsyslog 前編
- rsyslog 後編(この記事)
- Windows・ネットワーク機器のログ
- ログ集約基盤の設計
- 分析と監視・SIEM
- クラウドのログ
- syslogのトラブルシュート
- ログ管理の設計演習

コメント