オフィシャルサイト: rsyslog

rsyslog 5

移転しました

独自ドメインサイトへ移行しました。5秒後に

https://straypenguin.winfield-net.com/

へジャンプします。

RHEL/CentOS 6の標準の rsyslog は 5.8.x。rsyslogのドキュメントでも言われているが甚だ中途半端なバージョンだ。Syslogサーバに仕立てるために調べていたらコツや癖がいろいろと分かってきたので、まとめておくことにした。なお、RHEL/CentOS 6でも rsyslog7 という名称で rsyslog 7.4.x のパッケージも用意されていて、5.8.x からアップグレードすることが可能だ。ちなみに RHEL/CentOS 7 では rsyslog 7.4.x が元来標準となっている。

バージョン7 の検証は別ページにまとめた。

Table of Contents

リモートロギングのための設定

ここでは 514/UDP でのリモートログ受け入れを基本とし、TCPについては補足的に述べるに留める。TCPの方がログ欠落の可能性は低いが、ファイヤーウォールアプライアンスなど、未だにUDPでしかログを送れない機器が多く存在するからだ。

Syslogサーバ側の設定

これだけはやっておきたいシステム設定

同時オープンファイル上限数やエフェメラルポート範囲の拡大は基本中の基本。以下のファイルに下記の記述が含まれるように編集。

/etc/sysctl.conf

fs.file-max                   = 6815744
fs.aio-max-nr                 = 1048576
net.ipv4.ip_local_port_range  = 9000 65500

`sysctl -p` で反映。

/etc/security/limits.d/91-nofile.conf

root       soft    nofile    4096
root       hard    nofile    65536

/etc/security/limits.d/90-nproc.conf (RHEL/CentOS 6.x では元々こうなっているはず)

*          soft    nproc     1024
root       soft    nproc     unlimited

ulimit関係の設定変更は次回のrootシェルセッションから反映される。

主設定ファイル /etc/rsyslog.conf

頭が $ で始まる語句は、変数ではなく rsyslog のディレクティブ。RuleSet を意識した構造とインクルードコンフィグファイルを使うと、きれいで変更もしやすい設定ができる。

$ModLoad imuxsock
$ModLoad imklog
$ModLoad imudp          <- UDPインプットモジュールのロード
#$ModLoad imtcp
#$ModLoad imptcp        <- TCPをリスニングする場合はこちらをロード(TLS機能なし版)
 
#### GLOBAL DIRECTIVES ####
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$IncludeConfig /etc/rsyslog.d/*.conf
 
#### RULES ####         <- ここは暗黙のデフォルトRuleSet "RSYSLOG_DefaultRuleset" のコンテキスト
#kern.*                                                 /dev/console
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
# <-- 通常のローカルログフィルタ記述が続く。略 -->
 
# A template to for higher precision timestamps + severity logging
$template SpiceTmpl,"%TIMESTAMP%.%TIMESTAMP:::date-subseconds% %syslogtag% %syslogseverity-text%:%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
 
:programname, startswith, "spice-vdagent"	/var/log/spice-vdagent.log;SpiceTmpl
 
#### Remote server log RuleSet ###       <- ここからがUDPリモートロギングの設定
$Ruleset RemoteUDP                      <- UDPリモートロギング用RuleSetへのコンテキスト切り替え。まだ存在しないのでここで生成される
$RulesetCreateMainQueue on               <- パフォーマンスと信頼性向上のためルールセット専用のインプットキューを設ける
$InputUDPServerBindRuleset RemoteUDP    <- UDPインプットリスナーをルールセットに結びつける
#$UDPServerAddress 192.168.1.25          <- リッスンするネットワークIFを限定することも可能
$UDPServerRun 514                        <- ここでUDPのリッスンを有効化。UDP用は"Input"が付かないことに注意
#$UDPServerRun 10514                     <- 複数のUDPポートでリッスンしたい場合は複数回唱えればよい
$IncludeConfig /etc/rsyslog.d/remote-udp.conf_r   <- フィルタはインクルードコンフィグファイルに書く。ローカルとは別の拡張子にするとよい
 
#### Remote server log RuleSet for TCP ###
#$Ruleset RemoteTCP                     <- TCPリモートロギングRuleSetのコンテキスト(使うなら)
#$InputPTCPServerBindRuleset RemoteTCP  <- 平文専用TCPモジュール用なので"P"が入る。下も同様
#$InputPTCPServerRun 514
#$IncludeConfig /etc/rsyslog.d/remote-tcp.conf_r

$UDPServerAddress を使うと、リッスンするネットワークインターフェイスを限定することができる。普通は書かないので `$UDPServerAddress *' を指定したのと同じなわけだ。 プレインTCPモジュールの場合も同様の(しかし名前が全く違う)ディレクティブがあり確かに機能するのだが、imptcpモジュールの説明のバグ欄に "module always binds to all interfaces" と書いてあるのはドキュメントのバグか?

リモートログをUDPでなくTCPで待ち受ける場合、通信をTLSで保護するつもりがないのなら、imtcpモジュールより、平文通信に機能を絞った imptcpモジュールを使った方が理屈的に言って処理速度が速いはずだ。自分で測定してみたわけではないが、GitHubに"Receiving massive amounts of messages with high performance"というガイドもある。その他のチューニングポイントは後述の omrulesetモジュールによるルールセットの階層化 を参照いただきたい。

UDPリモートログ用インクルードコンフィグ /etc/rsyslog.d/remote-udp.conf_r

IPアドレス 192.168.1.24 のリモートサーバから送信されてくるログのうち、ntpd のログを /rlog/centos6u/ntpd.log に、Syslogファシリティ AUTHPRIV のログを /rlog/centos6u/secure に記録する例。書き方はいろいろある(ありすぎて困る)が、

$AllowedSender UDP, 192.168.1.24/32
 
$Template centos6u-perprog,"/rlog/centos6u/%programname%.log"
 
if $fromhost-ip == '192.168.1.24' and $programname startswith 'ntpd' then -?centos6u-perprog
if $fromhost-ip == '192.168.1.24' and $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure
if $fromhost-ip == '192.168.1.24' then ~

フィルタはレイナースクリプト (RainerScript) 形式というやつで書いてある。?テンプレート名 やファイル名の前の '-`は、従来の syslogd と同様、遅延書き込みを有効にすることを意味する。最後の行のアクションである `~' は discard つまり破棄。rsyslog のルールセットは、書かれている順番に、基本的にはいつも全フィルタが評価される。ただし、discard の結果通過しているログエントリが消えてしまえば、評価はそこで終わりとなる。それ以上どこにも記録しないログをしっかり discard するように心掛ければ、上記ルール群の下に例えば他のサーバからのログを処理するフィルタ群があった場合でも、もうそこから後へは流れず、間違って他のログファイルへ流れ込んだり無用なリソースを処理に費やしたりせずに済む。

一番上の $AllowedSender は、ソースアドレスによる受け付け制限。誰かが勝手に Syslogサーバへログを送る設定をして、知らぬ間にCPUやディスクを食い潰されてはたまらない。'UDP' のところはもちろん、TCPインプットモジュールなら 'TCP' に置き換えていただきたい。エージェントアドレスは書き方の見本として /32 を付けたが、単一のIPアドレスなら /prefix は書く必要はない。名前解決のできる環境ならホスト名や *.hoge.cxm のようなワイルドカード指定もできる。複数指定したい時は、カンマ区切りで列挙するか、$AllowedSender ステートメントを複数回唱えてもよいとされている。

2行目は rsyslog 独特のテンプレート という機能で、ファイル名やディレクトリ名をプロパティを使って動的に発生させる用途の他、ログフォーマットをカスタマイズしたり、データベースにログを格納する場合の insertクエリを定義したりでき、使い回しができる。テンプレートを使わずに書くと次のようになる。

$AllowedSender UDP, 192.168.1.24/32
 
if $fromhost-ip == '192.168.1.24' and $programname startswith 'ntpd' then -/rlog/centos6u/ntpd.log
if $fromhost-ip == '192.168.1.24' and $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure
:fromhost-ip,isequal,"192.168.1.24" ~

実は、この例ではわざと`$programname == 'ntpd'' と書かずに startswith で評価しているので、前記のテンプレートパターンでは ntpdate のログが来ると ntpdate.log という別のファイルに書かれてしまう。意図によってはこのように固定ファイル名にした方がすっきりするだろう。ごちゃ混ぜにして `... then -/rlog/centos6u/%programname%.log' とは書けない - やってみると、そのものズバリの %programname%.log というログファイルが出来上がってしまった。最後の行は、もうひとつのフィルタ記述形式であるプロパティベース形式を使ってみた - 意味は前の例と全く同じだ。ただし rsyslog のサイトではもうプロパティベース形式を推奨していないということも申し添えておこう。下記は、やらかしがちな間違いだ。

if $fromhost-ip == '192.168.1.24' and $programname startswith 'ntpd' then -/rlog/centos6u/ntpd.log
if $fromhost-ip == '192.168.1.24' and $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure
& ~

`&' は「直前の条件と同じものを」を表す短縮形。単一条件ならこれでよいが、すぐ上の条件は and による複数条件指定なので、ファシリティ=authpriv 以外の 192.168.1.24 からのログ(ntpdのものも含む) はこれより下にも流れてしまう。とはいえ、ルールセットを使ってローカルログとUDPリモートログ(と使うならTCPログ) を隔離しているので、UDPルールセットのログが他のルールセットに処理されるおそれはない。

omrulesetモジュールによるルールセットの階層化 + チューニング

レイナースクリプトが一応の完成を見た rsyslog バージョン7 以降なら `if ... then { if ... then ... }' という風に波括弧を使って評価文がネストできるようになったためもう少し論理的にルールが組み立てられるのだが、5.8 では仕方がない。

その代用というにはちょっと仕掛けが大袈裟すぎる気もするが、omruleset というモジュールがある。これを使うとルールセットを階層化することができる。iptablesユーザ定義チェーンのように、ルールセットからルールセットへと処理を飛ばすことができるのだ。面白いのでその例も示しておこう。

/etc/rsyslog.conf
$ModLoad imuxsock
$ModLoad imklog
$ModLoad omruleset
$ModLoad imudp
#$ModLoad imptcp
 
#### GLOBAL DIRECTIVES ####
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$IncludeConfig /etc/rsyslog.d/*.conf
 
# <-- 中略 -->
 
:programname, startswith, "spice-vdagent"	/var/log/spice-vdagent.log;SpiceTmpl
 
#### RuleSet for a specific server ###
$Ruleset Centos6uRuleSet                      <- 2段目のRuleSetを先に作っておく
$RulesetCreateMainQueue on                    <- RuleSet専用のインプットキューを設ける
$IncludeConfig /etc/rsyslog.d/centos6u.conf_o <- フィルタはインクルードコンフィグファイルに書く
  
#### Remote server log RuleSet ###
$Ruleset RemoteUDP
$RulesetCreateMainQueue on
$InputUDPServerBindRuleset RemoteUDP
$UDPServerRun 514
$IncludeConfig /etc/rsyslog.d/remote-udp.conf_r
/etc/rsyslog.d/remote-udp.conf_r
$AllowedSender UDP, 192.168.1.24
$ActionOmrulesetRulesetName Centos6uRuleSet         <- omrulesetモジュールのジャンプ先RuleSetをセットする
if $fromhost-ip == '192.168.1.24' then :omruleset:  <- ここでCentos6uRuleSetつまりcentos6u.conf_oの内容へ処理が飛ばされる
& -/rlog/centos6u/messages                          <- Centos6uRuleSetでdiscardされなかったエントリはここへ帰ってくる
& ~
/etc/rsyslog.d/centos6u.conf_o
if $programname startswith 'ntpd' then -/rlog/centos6u/ntpd.log
& ~
if $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure
& ~

remote-udp.conf_r で全破棄の手前で振り向けている centos6u/messages ログファイルには、ntpdauthprivファシリティを除いた残りのログが記録されることになる。ちょっとだけ構造が複雑になるが、その分、ログエントリの通過する評価処理は軽くなり、`& ~' も心おきなくバンバン使える。リモートサーバ毎にキューが分けられるのも利点だ。複雑な振り分けをしたくなった時のために、頭の隅においておくといい技かもしれない。

これをもう一歩推し進めると、第二階層の汎用化というところに行き着く。

/etc/rsyslog.conf
$ModLoad imuxsock
$ModLoad imklog
$ModLoad omruleset
$ModLoad imudp
#$ModLoad imptcp
 
#### GLOBAL DIRECTIVES ####
#$MaxOpenFiles 65535
#$OMFileAsyncWriting on
#$OMFileFlushOnTXEnd off
#$OMFileIOBufferSize 64k
 
# <-- 中略 -->
 
:programname, startswith, "spice-vdagent"	/var/log/spice-vdagent.log;SpiceTmpl
 
#### Per-server 2nd stage RuleSet ###
$Template PerServerNtpLogfileTpl,"/rlog/%hostname%/ntpd.log"
$Template PerServerAuthLogfileTpl,"/rlog/%hostname%/secure"
$Template PerServerMainLogfileTpl,"/rlog/%hostname%/messages"
 
$Ruleset PerServer2ndStage
#$MainMsgQueueSize 250000
#$MainMsgQueueDequeueBatchSize 4096
#$MainMsgQueueWorkerThreads 4
#$MainMsgQueueWorkerThreadMinimumMessages 60000
#$MainMsgQueueType FixedArray
$RulesetCreateMainQueue on
$IncludeConfig /etc/rsyslog.d/perserver2nd.conf_o
  
#### Remote server log RuleSet ###
$Ruleset RemoteUDP
#$MainMsgQueueSize 10000
#$MainMsgQueueDequeueBatchSize 16
#$MainMsgQueueWorkerThreads 1
$RulesetCreateMainQueue on
$InputUDPServerBindRuleset RemoteUDP
$UDPServerRun 514
$IncludeConfig /etc/rsyslog.d/remote-udp.conf_r
/etc/rsyslog.d/mremote-udp.conf_r
$AllowedSender UDP, 192.168.1.24, 192.168.1.23
$ActionOmrulesetRulesetName PerServer2ndStage
if $fromhost-ip == '192.168.1.24' then :omruleset:
& ~
if $fromhost-ip == '192.168.1.23' then :omruleset:  <- 別のエージェントも簡単に追加できる
& ~
/etc/rsyslog.d/perserver2nd.conf_o
if $programname startswith 'ntpd' then -?PerServerNtpLogfileTpl
& ~
if $syslogfacility-text == 'authpriv' then -?PerServerAuthLogfileTpl
& ~
*.* -?PerServerMainLogfileTpl

テンプレートの働きと相まって (192.168.1.24のサーバ名が centos6u、.23がcentos6u2 だったとすると)、

/rlog/
    \_ centos6u/
        \_ ntpd.log
           secure
           messages
    \_ centos6u2/
        \_ ntpd.log
           secure
           messages

という構造がオートマチックにできてしまうのだ。サーバ名は大文字にしたい? はいはい、テンプレート定義の "/rlog/%hostname%/ntpd.log" を "/rlog/%hostname:::uppercase%/ntpd.log" に変えてください。rsyslogのプロパティ置換機能 (PropertyReplacer) というやつだ。なぜコロンが3つも並んでいるかというと、リプレーサーの書式は

%PropName:[StartPos]:[EndPos][:Option]%

となっているから。ホスト名が centos6u2 なら、%hostname:1:7% は "centos6"、%hostname:5:$% は "os6u2" といった具合。他にも様々な変換ができるようなので興味があれば覗いてみてはいかがだろうか。

ただ、この 2ndステージの汎用化構造だと、どのエージェント発のログも、終着地であるディスクに書く手前で結局 PerServer2ndStage ルールセットに集中してしまい、エージェント毎にキューを別々にできるというメリットは犠牲になる。そこで、ここでもまた"Receiving massive amounts of messages with high performance"を参考にして、主設定ファイルにインプットキューのチューニングを入れてみた。"Understanding rsyslog Queues"も参考になる。ただし、例はただの受け売りであって、(今のところ)値を詳細に評価したわけではないのでコメントアウトしてある。UPSや予備電源を備えていない環境の場合はリスクもある。$Ruleset 宣言の中で $RulesetCreateMainQueue の手前で $MainMsgQueue* を唱えると、そのルールセット固有のインプットキューパラメータをカスタマイズすることができるのだが、デバグしてみると、変更したパラメータはそれ以降に作成するルールセットキュー全部に反映されてしまうので、RemoteUDP ルールセットセクションに示したように、デフォルトのキュー設定で作りたい最初のルールセットで元の値を宣言しなおしてやる必要がある。

$MainMsgQueueSize 250000
メモリキューのサイズ(単位はメッセージ数)。Syslogメッセージ1つの大きさは普通 512バイトから 1kバイトの間なので、上記では 122MB~245MB のメモリが使われる計算になる。デフォルトは 10000 メッセージ。
$MainMsgQueueDequeueBatchSize 4096
ドキュメントではデフォルト32と書かれているが CentOS 6.4 でデバグしたところ 16。
$MainMsgQueueWorkerThreads 4
生成するキューWorkerの最大数。デフォルトは 1。
$MainMsgQueueWorkerThreadMinumumMessages 60000
rsyslogdのキューWorkerは必要に応じて生成されるもので、最初にメッセージがやってきた時にはひとつだけ生成され、キューに溜まったメッセージがこのパラメータの数を超えると Worker が追加される。この例だと、次には 120000 メッセージを超えるとさらに Worker が立ち上がる。Workerが手すきになって $MainMsgQueueWorkerTimeoutThreadShutdown ミリ秒(デフォルトは60000つまり1分) 経つと、その Worker はターミネートされる。当パラメータの既定値は 100 で、$MainMsgQueueWorkerThreads が 1のままなら毒にも薬にもならないが、複数Workerスレッドを許した忙しいSyslogサーバでは、スレッド生成という重い処理が頻繁に発生すると却ってオーバーヘッドになる。
$MainMsgQueueType FixedArray
メモリキューのタイプ。これはデフォルト。エージェント側の設定で挙げる LinkedList タイプは必要な時に必要な分だけ採られるのに対して、FixedArray タイプは用がなくても或る程度メモリ領域を占めるが、パフォーマンスが高くCPUサイクルの消費も少ない。

以下は、グローバルディレクティブセクションに書いたステートメント。$OMFile* パラメータは、rsyslog 7以降だとルールセット毎に設定できるようだが、5.8 ではグローバルに設定するしかなさそう。omfile とは、否応なしにロードされる、ローカルファイルシステム(NFSマウントも含む)へのアウトプットモジュールのこと。

$MaxOpenFiles 65535
文字通り。このステートメントに基づいて、rsyslogd は起動時に setrlimit() システムコールを使い `ulimit -Sn xxx' 相当の設定を行う。当然ながら、ソフトリミットはあらかじめ設定されたハードリミットを超えることはできない。あらかじめシステムの ulimit設定で nofile を充分大きくしておく必要がある (これだけはやっておきたいシステム設定 参照)。オープンファイルには、実際に書き出すログファイルだけでなくネットワークソケットなども含まれる。
$OMFileAsyncWriting on
非同期書き込みを生かすことで、バッファがキューとの2段構えにできる。デフォルト off。
$OMFileFlushOnTXEnd off
Off にすると、メッセージ毎(?)にバッファをフラッシュするのはやめて、バッファが満たされてからファイルへ吐き出す。デフォルト on。
$OMFileIOBufferSize 64k
バッファサイズ。デフォルトはわずか 4k。

さらに他のチューニング方法

キューやバッファ絡みの他にも、チューニングの要素はある。きわめてリモートログ取扱量の多いSyslogサーバなら、検討する価値がある。

$UDPServerTimeRequery 100
UDPインプットモジュール特有のパラメータ。Syslogソフトウェアにとって、ローカルのシステム時刻を取得する行為は馬鹿にならないオーバーヘッドを伴うもののようだ。このパラメータによって、メッセージ何本毎にシステム時刻を取得し直すかを制御できる。デフォルトは 2メッセージに 1回。既定で使われる、rsyslog にハードコードされた RSYSLOG_TraditionalFileFormat テンプレートでは、冒頭の日時は rsyslogd への着信日時 (%timegenerated%) ではなく、Syslogメッセージ内に格納された生成日時 (%timestamp% つまりSyslogメッセージのTIMESTAMPフィールド) なので、実際にファイルに記録される日時に影響はないはず。なお、RSYSLOG_TraditionalFileFormat テンプレートはソースコードの tools/smtradfile.c で定義されている。
syslogd起動オプション -x の使用
syslogd起動時に -x オプションを渡すと、syslogd のDNS検索を抑止できる。ただし、コンフィグも名前解決が発生しないように留意して書く必要が生じる。使うなら /etc/sysconfig/rsyslogSYSLOGD_OPTIONS 変数に加えておけばよい。
DNSキャッシュの実装
-x オプションを利用する代わりに、Syslogサーバ上にDNSキャッシュを実装すれば、いちいち別のDNSサーバに問い合わせるよりはオーバーヘッドが小さくて済む。djbdnsdnscache や、標準パッケージの dnsmasq をセットアップすればよい。

コンフィグのデバグ

自分の書いたコンフィグが意図通りに解釈されているか確かめるには、rsyslogd をデバグモードで起動してみる。

root# service rsyslog stop
root# RSYSLOG_DEBUG=DEBUG RSYSLOG_DEBUGLOG=/var/tmp/rsyslog-debug.log /sbin/rsyslogd -c5
<ctl-c>

ログは標準出力にも出力されるので RSYSLOG_DEBUGLOG変数は指定しなくてもいいが、指定すればファイルにも記録されるので調査がしやすい。RHEL/CentOS だと、普段 SysVinit から起動する時には /etc/sysconfig/rsyslogSYSLOGD_OPTIONS に入れてあるコマンドラインオプションが拾われて付加されるので、正確を期すならデバグの時にも指定した方がよい(上記の例での -c5)。

記載法ミニリファレンス

大文字小文字の区別について
条件フィルタでの値のクォートについて
レイナースクリプトの比較演算子
比較演算子 説明
== 等しい。文字列でも数値でも有効。プロパティベース形式にある isequal は使えないことに注意
!=, <> 等しくない。文字列でも数値でも有効
< より小さい
> より大きい
<= 以下
>= 以上
contains 含む。文字列でのみ使える
contains_i 同上、大文字小文字を区別しない
startswith ~で始まる。文字列でのみ
startswith_i 同上、大文字小文字を区別しない

評価を反転する not も使える。ただし "not $A == 'B'" は (not $A) == 'B' と評価されてしまうため "not ($A == 'B')" と書かなければならず、だったら単純に "$A != 'B'" と書いた方がマシ、と注意書きあり。contains などと組み合わせる場合は "if not ($A contains 'B')" と書くべきと思われる。

rsyslogで使用できるプロパティ

Syslogもひとつのプロトコルである。好き勝手な文字や数字の羅列が送られてくるわけではないし、我々が普段ログファイルで見るままのカタチで送られてくるわけでもない。例えば、ファシリティとシビアリティは然るべき計算をもって1~3桁の数字にまとめて '<' と '>' で挟んで送れ(このフィールドを PRI [プライオリティ] と呼ぶ)とか、そういった種々のフィールドを何をデリミタにしてどういう順番で並べろという規格が決まっている。RFC5424 (RFC3164を置き換え) が Syslogプロトコルの基本定義。RFC5426 が Syslog over UDPの仕様。さらに RFC5425 で TLS による暗号化送受信の規格が定義されている。新しい方のSyslogプロトコルでは、UDPによるトランスポートが別文書になっていることからもうかがえるように、意外なことに、ネットワークによるSyslog送信はTCPが基本となっている。

RFC5424を書いたのは、何を隠そう、rsyslog 開発の中心人物 レイナー・ゲルハルト氏その人である。ゲルハルト氏はドイツのシステムコンサルタント/ソフトウェア会社 Adiscon の代表でもある。

とはいえ、現在も、そして今後もかなり長らく、実世界では、RFC5424フォーマットとRFC3164フォーマットのメッセージが入り乱れて使用されていくだろう。そこで rsyslog は、複数のパーサーモジュールで順繰りにメッセージを評価して、RFC5424形式のメッセージなのかRFC3164のメッセージなのかを判定してフィールドをプロパティに割り当てる。デフォルトでは、先に評価するのは pmrfc5424 パーサーモジュールで、それが失敗すると pmrfc3164 でパースが行われる。RFC3164は5424よりずっと規則が緩いので、先に pmrfc3164 で評価するとどのメッセージもRFC3164フォーマットと判定されてしまうからだという。

rsyslog のコンフィグで使えるプロパティは、Syslogメッセージから取り出したそういったフィールドが主だが、それ以外から取得するものもある。

プロパティ名 説明
msg SyslogメッセージのMSGフィールド。RFC3164フォーマットではMSGフィールドはTAG部(プログラム名等)とCONTENT部から成り、このプロパティはCONTENT部のみを指す。RFC5424ではMSGフィールド全体
rawmsg 同じくMSGフィールドだが、フィールドに格納されたそのままの形。RFC3164フォーマットのメッセージではTAG部も含んでいるようだ
hostname SyslogメッセージのHOSTNAMEフィールド
source 上記 hostname のエイリアス
fromhost Syslogパケットの送信元アドレスをDNSリゾルブしたもの。リゾルブ不能な場合はIPアドレスのまま。ログがリレーされている場合、これはログの発生元ではなく直前のSyslogリレーサーバとなることに注意
fromhost-ip Syslogパケットの送信元IPアドレス。リゾルブなし
syslogtag SyslogメッセージのTAG部。TAGはまたプログラム名+PID/MSGIDから成る。例: named[12345]
programname TAGのプログラム名のみ
pri SyslogメッセージのPRIフィールド。(ファシリティ x 8 + シビアリティ) の計算による1~3桁の数字の状態
pri-text PRIにそこから解釈したを文字列を付けたもの。例:local0.err<133>
iut MonitorWare InfoUnitType よく分からん
syslogfacility PRIをデコードした結果得られたファシリティの数字表記。つまり 0~23 のいずれか
syslogfacility-text 上記の文字表記。kern, mail, authpriv, local0 など
syslogseverity PRIをデコードした結果のシビアリティ数字表記。つまり 0~7 のいずれか
syslogseverity-text 上記の文字表記。emerg, warning, notice, info など
syslogpriority 上記 syslogseverity のエイリアス。下位互換のために残っているだけで、前者を使うべき。PRIそのものではないことに注意
syslogpriority-text 上記 syslogsevierity-text のエイリアス。下位互換のために残っているだけで、なるべく前者を使うべき
timegenerated Syslogメッセージ受信時のタイムスタンプ
timereported SyslogメッセージのTIMESTAMPフィールド
timestamp 上記 timereported のエイリアス
protocol-version SyslogメッセージのPROTOCOL-VERSIONフィールド
structured-data SyslogメッセージのSTRUCTURED-DATAフィールド
app-name SyslogメッセージのAPP-NAMEフィールド
procid SyslogメッセージのPROCIDフィールド
msgid SyslogメッセージのMSGIDフィールド
inputname メッセージを生成したインプットモジュールの名前。imuxsock, imudp など。rsyslogd自体の出したログを他と区別するために考案されたものらしい

Syslogメッセージの属性とは直接関係のないその他のプロパティ。頭の $ もプロパティ名の一部であり、例えばテンプレートでなら %$myhostname% といった具合に使う。

プロパティ名 説明
$bom UTF-8でエンコードされたUnicodeのBOM(byte-order mask)
$now 現在の YYYY-MM-DD
$year YYYY
$month MM
$day DD
$hour 現在の HH (24時間表記)
$hhour 1時間のうちの前半後半。今が x時00分~29分なら 0、30~59分なら 1
$qhour こちらはクォーター時間。上記同様に 0, 1, 2, 3 のいずれかとなる
$minute 現在の mm
$myhostname 自ホスト名。ドメイン部なしになる可能性が高い

エージェント側の設定

/etc/rsyslog.conf
$ModLoad imuxsock
$ModLoad imklog
 
#### GLOBAL DIRECTIVES ####
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$IncludeConfig /etc/rsyslog.d/*.conf
 
#### RULES ####
#kern.*                                                 /dev/console
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
# <-- 通常のローカルログフィルタ記述が続く。略 -->
 
# ### begin forwarding rule ###
$WorkDirectory /var/lib/rsyslog #<- ディスクキューとして使うディレクトリ
$ActionQueueFileName fwdRule1   #<- キューチャンクファイルの接頭句。実際のファイルはfwdRule1.0000001といった名前で作られる
$ActionQueueMaxDiskSpace 200m   #<- 補助キュー用ディスクスペースの容量制限。本番サーバなら数g などできるだけ大きい方がよい
$ActionQueueSaveOnShutdown on   #<- キューWorkerの終了時にまだメモリ上に処理残のキューがあればディスクキューに保存する
#$ActionQueueHighWaterMark 8000 #<- 補足説明参照
#$ActionQueueLowWaterMark 2000  #<- 補足説明参照
$ActionQueueType LinkedList     #<- LinkedLisタイプのtメモリキューを作成
#$ActionResumeInterval 60       #<- リトライ間隔の初期値(秒)
$ActionResumeRetryCount 60      #<- リトライ回数。ローカルにも書かれるので、Syslogサーバが長らくアクセス不能な時はあきらめる。デフォルト見本は -1(無制限)
*.* @192.168.1.25:514           #<- 全ログをSyslogサーバへUDP送信する
#*.* @@192.168.1.25:514         #<- TCPの場合は@を2つにする
#if $programname startswith 'ntpd' then @192.168.1.25:514   #<- ntpdとntpdateのログだけ送るならこんな感じ
# ### end of the forwarding rule ###
 
# A template to for higher precision timestamps + severity logging
$template SpiceTmpl,"%TIMESTAMP%.%TIMESTAMP:::date-subseconds% %syslogtag% %syslogseverity-text%:%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
 
:programname, startswith, "spice-vdagent"	/var/log/spice-vdagent.log;SpiceTmpl

核心の`*.* @192.168.1.25:514' については特に説明は要らないだろう。

その上の送信キューについて少し補足しておく。rsyslogオフィシャルドキュメントの他に、RHEL7 のドキュメントが参考になる。送信先のSyslogサーバがオフラインになると、送信すべきログは出力キューにバッファされる。RHEL/CentOS 6 でインストールされるサンプルコンフィグ(上記もそれを元にしている) に書いてある送信キューは、ディスク補助付きInメモリキュー(Disk-Assisted In-memory Queue) と呼ばれるタイプ。メインキューはメモリで、それが閾値に達した場合だけ補助キュー(=ディスクキュー) にバッファされ始める。閾値とはメモリ上のログメッセージの数が $ActionQueueHighWaterMark に達した時で、それが $ActionQueueLowWaterMark 値に下がるまで補助キューへ吐き出される。上でコメントとして書き添えた値は暗黙のデフォルト閾値だ。

では、キューが一杯になったらどうなるのか。rsyslogd は送信リトライ10回毎に $ActionResumeInterval (秒)を延ばしながら、最大 $ActionResumeRetryCount 回まで送信先の復帰を待つ。そしていよいよメモリキューがいっぱいになると、rsyslogd はまずログの受け入れ速度を落とし(スロットル)、ログのシビアリティなどに基づいて古いエントリを捨てつつ、どんどん補助キューへエントリを吐き出す。しかし、いつまでも logソケットなどをスロットルし続ければシステムのストールにつながりかねない。メモリキューも補助キューも満杯のまま状況が改善せず $ActionQueueTimeoutEnqueue ミリ秒 (デフォルト 2000) 経過すると、遂に最後の手段として、新着のログを破棄し始める。