rsyslog | ||
---|---|---|
HOME |
RHEL/CentOS 6に標準でインストールされる rsyslog は 5.8.x。しかし、rsyslog7 という名称で rsyslog 7.4.x のパッケージも用意されていて、5.8.x からアップグレードすることが可能だ。rsyslogのドキュメントでも言われているが、バージョン5 は機能が甚だ中途半端。処理速度も遅い。当ページでは、rsyslog 7.4.10 で Syslogサーバを仕立てる上で分かった rsyslog の機能やコツについて述べる。ちなみに RHEL/CentOS 7 では最初から rsyslog 7.4.x が標準となっている。
RHEL/CentOS 6でも rsyslog 7.4 が rsyslog7 という名称で選択可能パッケージとして利用できるようになった。2014年10月、RHEL/CentOS 6.6 の時期からだ。このエラータ情報を見ると、Red Hat社は rsyslog7 へのアップグレードを推奨しているようだ。ただし、単に `yum update rsyslog7' とやっても依存関係(コンフリクト)のため入れ替えできない。yumシェルを使うとできる。
root# yum shell > install rsyslog7 > remove rsyslog > run > exit root# rpm -qa |grep rsyslog rsyslog7-7.4.10-x.el6.x86_64 root# chkconfig --add rsyslog <- 一旦スタートアップが解除されるので再登録が必要
バージョン7用の /etc/rsyslog.conf.rpmnew、/etc/sysconfig/rsyslog.rpmnew が新たに作られるので、バージョン5用の rsyslog.conf, sysconfig/rsyslog を退避させるなどして、正規のファイル名に置き換えてカスタマイズのベースにする。/etc/rsyslog.d/ 配下のファイルは置き換えや追加はされない。
ここでは 514/UDP でのリモートログ受け入れを基本とし、TCPについては補足的に述べるに留める。TCPの方がログ欠落の可能性は低いが、ファイヤーウォールアプライアンスなど、未だにUDPでしかログを送れない機器が多く存在するからだ。
同時オープンファイル上限数やエフェメラルポート範囲の拡大は基本中の基本。以下のファイルに下記の記述が含まれるように編集。
/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シェルセッションから反映される。
バージョン7 では設定の書き方が大幅に変わった。バージョン5 までログ仕分けルールの条件文などごく一部で使われていた レイナースクリプト (RainerScript) が、コンフィグ全体のパーサーエンジンになったようだ。ただし、ディレクティブの頭が $ で始まるバージョン5 の書き方 (以降「レガシー」と呼ぶ) もそのほとんどが混在で使え、一部、レガシーなディレクティブしか用意されていない設定機能さえある。以下のコンフィグ例では、新記述法で置き換えられるものはなるべく新記述法で書くようにしている。RuleSet を意識した構造とインクルードコンフィグファイルを使うと、きれいで変更もしやすい設定ができる。
レガシー記述法と新記述法の混在には多少注意が必要だ。新記述法で定義したルールセットに対してはレガシー式でオプションを唱えても反映されなかったり、レガシー式で定義したテンプレートが CALL ステートメントで呼べないなどの落とし穴があるからだ。そういったことを避けるためにも、特に理由のない限り新記述法で貫き通した方がよい。
module(load="imuxsock") module(load="imklog") module(load="imudp") <- UDPインプットモジュールのロード #module(load="imptcp") <- TCPをリスニングする場合はこちらをロード(TLS機能なし版) #module(load="imtcp") #### 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リモートロギングの設定 template(name="Centos6uPerProg" type="string" string="/rlog/centos6u/%programname%.log") <- バージョンによっては templateをruleset()内に書くと設定パースエラーになるようなのでここへ移した。 ruleset(name="RemoteUDP" <- UDPリモートロギング用RuleSetへのコンテキスト切り替え。まだ存在しないのでここで生成される queue.type="FixedArray" <- パフォーマンスと信頼性向上のためルールセット専用のインプットキューを設ける ) { $IncludeConfig /etc/rsyslog.d/remote-udp.conf_r <- フィルタはインクルードコンフィグファイルに書く。ローカルとは別の拡張子にするとよい } #### Remote server log RuleSet for TCP ### #ruleset(name="RemoteTCP" <- TCPリモートロギングRuleSetのコンテキスト(使うなら) # queue.type="FixedArray" # ) { # $IncludeConfig /etc/rsyslog.d/remote-tcp.conf_r #} input(type="imudp" port="514" ruleset="RemoteUDP") <- UDPのリッスンを有効化 #input(type="imudp" address="192.168.1.25" port="10514" ruleset="RemoteUDP") <- 追加で複数のUDPポートで待ち受けることも可能 #input(type="imptcp" address="192.168.1.25" port="514" ruleset="RemoteTCP") <- TCPのリッスンを有効化(使うなら)
input ステートメントで address オプションを使うと、リッスンするネットワークインターフェイスを限定することもできる。普通は書かないので `address="*"' を指定したのと同じなわけだ。ただし、7.4 のドキュメントを見る限り、imtcp モジュールには address オプションが欠けている(v8のドキュメントには載っている)。
TCPで待ち受ける場合、通信をTLSで保護するつもりがないのなら、imtcpモジュールより、平文通信に機能を絞った imptcpモジュールを使った方が理屈的に言って処理速度が速いはずだ。自分で測定してみたわけではないが、GitHubに"Receiving massive amounts of messages with high performance"というガイドもある。その他のチューニングポイントは後述の CALLステートメントによるルールセットの階層化+チューニング を参照いただきたい。
IPアドレス 192.168.1.24 のリモートサーバから送信されてくるログのうち、ntpd のログを /rlog/centos6u/ntpd.log に、Syslogファシリティ AUTHPRIV のログを /rlog/centos6u/secure に記録する例。書き方はいろいろある(ありすぎて困る)が、
$AllowedSender UDP, 192.168.1.24/32 if $fromhost-ip == '192.168.1.24' then { if $programname startswith 'ntpd' then -?Centos6uPerProg if $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure stop }
条件文は、波括弧 {} を使うとネストできる(※Note参照)。?テンプレート名 やファイル名の前の '-`は、従来の syslogd と同様、遅延書き込みを有効にすることを意味する。最後の行のアクションである stop は、バージョン5 の `~' (discard) に代わるもの。rsyslog のルールセットは、書かれている順番に、STOP ステートメントが現れるまで全フィルタが評価される。`&' は「直前の条件と同じ」の意味だ。それ以上どこにも記録しないログをしっかり STOP するように心掛ければ、上記ルール群の下に例えば他のサーバからのログを処理するフィルタ群があった場合でも、もうそこから後へは流れず、間違って他のログファイルへ流れ込んだり無用なリソースを処理に費やしたりせずに済む。
一番上の $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' then { if $programname startswith 'ntpd' then -/rlog/centos6u/ntpd.log if $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure stop }
実は、この例ではわざと`$programname == 'ntpd'' と書かずに startswith で評価しているので、前記のテンプレートパターンでは ntpdate のログが来ると ntpdate.log という別のファイルに書かれてしまう。意図によってはこのように固定ファイル名にした方がすっきりするだろう。ごちゃ混ぜにして `... then -/rlog/centos6u/%programname%.log' とは書けない - やってみると、そのものズバリの %programname%.log というログファイルが出来上がってしまった。
ルールセットには必ず Action() セクションかそれと同等なものが必要だ。でないとコンフィグのパース時にエラーとなって、rsyslogd は起動しない。書き方として一番明解なのは、後述の 第二階層の汎用化 のところで出てくる perserver2nd.conf_o の例だろう。しかし、明示的に Action() が書かれていなくても、`if ... then /log/file' や `mail.info /log/file' といったフィルタルールは実はアクションオブジェクトとしてパースされているのでエラーにならない。
かたや、上の例の `if $fromhost-ip == 'x.x.x.x' then { ... }' ブロック全体はアクションではない。波括弧は、`if ... then' 条件制御ステートメントの一部というよりも、アクションのリストを意味するものと解釈するとレイナースクリプトの挙動の説明がつく。それが証拠に、{} の中の個々のフィルタルールを `if $programname startswith 'ntpd' then { -/rlog/centos6u/ntpd.log }' とは書けないからだ。「直前の条件と同じメッセージを」を意味する & はフィルタアクション命令の続きでのみ機能するものなので、三段論法の行き着くところ、下記の構造は成り立たない。
if $fromhost-ip == 'x.x.x.x' then { if $programname startswith 'ntpd' then /log/file if $syslogfacility-text == 'authpriv' then /log/otherfile } & stop
stop はまた、アクションではない。他のプログラミング言語やシェルスクリプトの break に近い、制御ステートメントである(ただしレガシーの discard 同等の機能を含む)。よって、今のところ、
ruleset(name="RemoteUDP" queue.type="FixedArray" ) { stop }
という空のルールセットを定義しようとするとエラーになる。「今のところ」と言ったのは、rsyslogのメーリングリストに "[rsyslog] ruleset with only stop" というスレッドを見つけたから。Rainer Gerhards氏は、空のルールセットが時として有用であることを認めていて、ruleset() に `permitEmpty=on' なるオプションを設けることを検討しているようだ。
rsyslog 7 では、CALL ステートメントでルールセットを階層化することができる。iptables のユーザ定義チェーンのように、ルールセットからルールセットへと処理を飛ばすことができるのだ。バージョン5 ではあらかじめ omruleset モジュールをロードしておく必要があったが、v7では標準機能であり、モジュールをロードする必要もない。CALL は新たに書き加えられた機能で、omruleset とは別ものであり、処理速度も速くなっているのだという。v7でも omruleset はまだ使えるが、下位互換性のためだけに残されているにすぎない。面白いので CALL を使った例も示しておこう。
module(load="imuxsock") module(load="imklog") module(load="imudp") #module(load="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(name="Centos6uRuleSet" <- 2段目のRuleSetを先に作っておく queue.type="FixedArray" <- RuleSet専用のインプットキューを設ける ) { $IncludeConfig /etc/rsyslog.d/centos6u.conf_o <- フィルタはインクルードコンフィグファイルに書く } #### Remote server log RuleSet ### ruleset(name="RemoteUDP" queue.type="FixedArray" ) { $IncludeConfig /etc/rsyslog.d/remote-udp.conf_r } input(type="imudp" port="514" ruleset="RemoteUDP")
$AllowedSender UDP, 192.168.1.24 if $fromhost-ip == '192.168.1.24' then call Centos6uRuleSet <- Centos6uRuleSetつまりcentos6u.conf_oの内容へ処理が飛ばされる #& -/rlog/centos6u/messages <- Centos6uRuleSetでstopされなかったエントリはここへ帰ってくるのだが... & stop
if $programname startswith 'ntpd' then -/rlog/centos6u/ntpd.log & stop if $syslogfacility-text == 'authpriv' then -/rlog/centos6u/secure & stop *.* -/rlog/centos6u/messages
ちょっとだけ構造が複雑になるが、その分、ログエントリの通過する評価処理が少なくなる。リモートサーバ毎にキューが分けられるのも利点だ。複雑な振り分けをしたくなった時のために、頭の隅においておくといい技かもしれない。
ただし、Centos6uRuleSet のように独自インプットキューを備えたルールセットへ飛ばす時にはちょっと注意が必要だ。フィルタした残りのログエントリを centos6u/messages に記録するというルールを centos6u.conf_o 末尾でなく remote-udp.conf_r (コメントを付けた位置)に書くと、ntpdやauthprivファシリティを除いた残りのログが記録されるはずだが、独自キュー付き(つまり非同期処理) のルールセットは CALL されると即座にリターンを返すため、そうなるとは限らないらしい (The rsyslog “call” statement)。加えてもうひとつ- ルールセット名についてだ。CALL 先のルールセット名が "xxx-001" のようにハイフォン+数字で終わっていると、それらが断ち切られて "xxx" へ飛ぼうとしてしまうのだ。仕様だかバグだか知らないが、それを経験してから、全てのルールセット名はハイフォンを使わないことにした。
CALLによるルールセットの階層化をもう一歩推し進めると、第二階層の汎用化というところに行き着く。
module(load="imuxsock") module(load="imklog") module(load="imudp" timeRequery="100") #module(load="imptcp") #### GLOBAL DIRECTIVES #### $Umask 0000 $MaxOpenFiles 65535 #### RULES #### $FileCreateMode 0600 #kern.* /dev/console *.info;mail.none;authpriv.none;cron.none /var/log/messages # <-- 中略 --> $FileCreateMode 0644 local7.* /var/log/boot.log $FileCreateMode 0600 :programname, startswith, "spice-vdagent" /var/log/spice-vdagent.log;SpiceTmpl #### Per-server 2nd stage RuleSet ### template(name="PerServerNtpLogfileTpl" type="string" string="/rlog/%hostname%/ntpd.log") template(name="PerServerAuthLogfileTpl" type="string" string="/rlog/%hostname%/secure") template(name="PerServerMainLogfileTpl" type="string" string="/rlog/%hostname%/messages") ruleset(name="PerServer2ndStage" queue.size=250000 queue.dequeueBatchSize="4096" queue.workerThreads="4" queue.workerThreadMinimumMessages="5000" queue.type="FixedArray" ) { $IncludeConfig /etc/rsyslog.d/perserver2nd.conf_o } #### Remote server log RuleSet ### ruleset(name="RemoteUDP" queue.type="FixedArray" ) { $IncludeConfig /etc/rsyslog.d/remote-udp.conf_r } input(type="imudp" port="514" ruleset="RemoteUDP")
ついでながら、$FileCreateMode も入れ込んでみた。コツが要ることが分かったからだ。`$FileCreateMode 0xxx' (ビットは必ず0で始まる4オクテット) が現れてから次の $FileCreateMode が現れるまで、新規に作られるログファイルのパーミッションは 0xxx になるのだが、単に 0644 を指定しただけでは実際に作られるログは 0600 になってしまう。これは rsyslogd プロセスの umask である 0077 に規制されてしまうから。ログファイルを思い通りのパーミッションビットで作りたければ、最初のルールの現れるより手前で `$Umask 0000' でマスクをリセットしてやる必要がある ($Umask は $FileCreateMode と違って1度しか書いてはいけない-何度も書くと予期せぬ動作をする可能性があると述べられている)。また、逆に、$Umask 0000 を書いたからには、/var/log/messages などがワールドリータブルにならないよう、必ずすぐに $FileCreateMode 600 を唱えなければいけない。下の perserver2nd.conf_o で例を示すように新記述法では omfile モジュールアクション毎の属性として指定するのだが、そちらも同様に umask の影響を受ける。
$AllowedSender UDP, 192.168.1.24, 192.168.1.23 if $fromhost-ip == '192.168.1.24' then call PerServer2ndStage & stop if $fromhost-ip == '192.168.1.23' then call PerServer2ndStage <- 別のエージェントも簡単に追加できる & stop
if $programname startswith 'ntpd' then action(type="omfile" dynaFile="PerServerNtpLogfileTpl" fileCreateMode="0600" dirCreateMode="0700" ioBufferSize="64k" flushOnTXEnd="off" asyncWriting="on" ) & stop if $syslogfacility-text == 'authpriv' then action(type="omfile" dynaFile="PerServerAuthLogfileTpl" fileCreateMode="0600" dirCreateMode="0700" ioBufferSize="64k" flushOnTXEnd="off" asyncWriting="on" ) & stop action(type="omfile" dynaFile="PerServerMainLogfileTpl" fileCreateMode="0600" dirCreateMode="0700" ioBufferSize="64k" flushOnTXEnd="off" asyncWriting="on" )
テンプレートの働きと相まって (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や予備電源を備えていない環境の場合はリスクもある。
perserver2nd.conf_o では omfile モジュールにチューニングを加えている。omfile とは、否応なしにロードされる、ローカルファイルシステム(NFSマウントも含む)へのアウトプットモジュールのこと。v5ではグローバルに設定するしかなかったが、v7ではログファイル毎に設定できる(するしかない?)ようになった。fileCeateMode と dirCreateMode は、指定するならここだということを示したかっただけで、とくに必要はない。指定するなら "600" のような3オクテット表記ではダメで必ず4オクテットで指定しなくてはならない。
以下は、グローバルディレクティブセクションに書くステートメント。レガシーディレクティブしか見つからない。
同じくグローバルセクションで使っている timeRequery は次項で。
キューやバッファ絡みの他にも、チューニングの要素はある。きわめてリモートログ取扱量の多いSyslogサーバなら、検討する価値がある。
自分の書いたコンフィグが意図通りに解釈されているか確かめるには、rsyslogd をデバグモードで起動してみる。
root# service rsyslog stop root# RSYSLOG_DEBUG=DEBUG RSYSLOG_DEBUGLOG=/var/tmp/rsyslog-debug.log /sbin/rsyslogd -x root# kill -TERM $(cat /var/run/syslogd.pid) root# ps axw |grep rsyslogd
ログは標準出力にも出力されるので RSYSLOG_DEBUGLOG変数は指定しなくてもいいが、指定すればファイルにも記録されるので調査がしやすい。RHEL/CentOS だと、普段 SysVinit から起動する時には /etc/sysconfig/rsyslog の SYSLOGD_OPTIONS に入れてあるコマンドラインオプションが拾われて付加されるので、正確を期すならデバグの時にも指定した方がよい(上記の例での -x)。
比較演算子 | 説明 |
== | 等しい。文字列でも数値でも有効。プロパティベース形式にある 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')" と書くべきと思われる。
Syslogもひとつのプロトコルである。好き勝手な文字や数字の羅列が送られてくるわけではないし、我々が普段ログファイルで見るままのカタチで送られてくるわけでもない。例えば、ファシリティとシビアリティは然るべき計算をもって1~3桁の数字にまとめて '<' と '>' で挟んで送れ(このフィールドを PRI [プライオリティ] と呼ぶ)とか、そういった種々のフィールドを何をデリミタにしてどういう順番で並べろという規格が決まっている。RFC5424 (RFC3164を置き換え) が Syslogプロトコルの基本定義。RFC5426 が Syslog over UDPの仕様。さらに RFC5425 で TLS による暗号化送受信の規格が定義されている。
RFC5424を書いたのは、何を隠そう、rsyslog 開発の中心人物 レイナー・ゲルハルト氏その人である。ゲルハルト氏はドイツのシステムコンサルタント/ソフトウェア会社 Adiscon の代表でもある。
とはいえ、現在も、そして今後もかなり長らく、実世界では、RFC5424フォーマットとRFC3164フォーマットのメッセージが入り乱れて使用されていくだろう。そこで rsyslog は、複数のパーサーモジュールで順繰りにメッセージを評価して、RFC5424形式のメッセージなのかRFC3164のメッセージなのかを判定してフィールドをプロパティに割り当てる。デフォルトでは、先に評価するのは pmrfc5424 パーサーモジュールで、それが失敗すると pmrfc3164 でパースが行われる。RFC3164は5424よりずっと規則が緩いので、先に pmrfc3164 で評価するとどのメッセージもRFC3164フォーマットと判定されてしまうからだという。
プロパティ名 | 説明 |
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 | 自ホスト名。ドメイン部なしになる可能性が高い |
$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) 経過すると、遂に最後の手段として、新着のログを破棄し始める。
rsyslog v5 の時から既にあったようなのだが、imfile という面白いインプットモジュールがある。これは、タイムスタンプも伴わない平易なテキスト出力ファイルを定期的にポーリングし、エントリを syslog へインポートする働きをする。もちろん、通常のログ同様にフィルタを使用してログファイルの振り分けができ、ログエントリは立派に syslog のフォーマットに則って書かれる。ログエントリの TIMESTAMP は、imfileモジュールが監視先ファイルからそのエントリを読み取った日時だ。さらに興味深いのは、監視先ファイルがローテーションされることを見越して作られている点だ。
例えば、2つのインターネットサイトを10分間隔でプローブしてHTTPレスポンスコードをそれぞれ /var/cache/siteprobe/myportal と /var/cache/siteprobe/myhome というファイルに出力しているとしよう。テキストの出力フォーマットは下記のようなものだとする。フィールドの区切りはスペース。第2フィールドにこのサイト試験のタイトルである "myportal" と "myhome" が必ず入るのがキモで、これを基準に rsyslog のテンプレート機能でログを振り分けるという趣向だ。
監視先ファイル siteprobe/myportalに記録されるエントリ:
200 myportal http://www.myportal.cxm/index.html
監視先ファイル siteprobe/myhomeファイルに記録されるエントリ:
200 myhome http://www.myhome.cxm/index.html
rsyslog のコンフィグはこんな塩梅になる。
module(load="imuxsock") module(load="imklog") module(load="imfile" pollingInterval="20") <-監視先ファイルのポーリング間隔の既定値は10秒。20秒にするならこのように書く #### GLOBAL DIRECTIVES #### $Umask 0000 <-前述の「第2階層の汎用化」のところを参照のこと $WorkDirectory /var/lib/rsyslog <-必要。下記 siteprobe.conf_f の中で解説する #### RULES #### $FileCreateMode 0600 #kern.* /dev/console *.info;mail.none;authpriv.none;cron.none /var/log/messages # <-- 中略 --> #### File import module demo ### $IncludeConfig /etc/rsyslog.d/siteprobe.conf_f
template(name="siteprobeLogfileTpl" type="string" string="/var/log/siteprobe/%msg:F,32:2%") ruleset(name="siteprobeRuleset" queue.type="FixedArray" ) { if $programname == 'siteprobe' then action(type="omfile" dynaFile="siteprobeLogfileTpl" fileCreateMode="0644" dirCreateMode="0755" flushOnTXEnd="off" asyncWriting="on" ) & stop } input(type="imfile" file="/var/cache/siteprobe/myportal" tag="siteprobe:" statefile="siteprobe-myportal" ruleset="siteprobeRuleset") input(type="imfile" file="/var/cache/siteprobe/myhome" tag="siteprobe:" statefile="siteprobe-myhome" ruleset="siteprobeRuleset")
最後に、監視先ファイルのローテーションについて触れておく。imfile は監視先のファイルをポインタで追跡しており、ローテーションによってファイル名が代わるとそれを検知し、前のファイルの内容を全てインポートし終えてから新しいファイルへポインタを切り替える。それ故、注意しなくてはいけないのは、監視先ファイルのローテーションは rsyslogd が稼働している時に行わなくてはいけないという点だ。エントリはインポート先syslogファイルへどんどん保存されていくわけで、監視先ファイルは短期間でローテーションしたほうがディスクが節約できる。ローテーション世代もカレント+1世代で充分だ。ここで題材にしている仮想のサイトプローブシェルスクリプトに組み込むなら、例えば下記のような処理でよい。
if [ $LOGCLEARINTVL -gt 0 -a "$COUNT" -gt $LOGCLEARINTVL ]; then [ -f ${LOG}.1 ] && mv -f ${LOG}.{1,2} mv -f $LOG{,.1} &>/dev/null rm -f ${LOG}.2 COUNT=1 fi