多機能なログ管理システム「rsyslog」の基本的な設定
多くのLinuxディストリビューションで採用されているsyslogサービス「rsyslog」は現在でも活発に開発が進められており、ネットワーク経由でのログ転送だけでなくログの整形や柔軟な条件分岐、さまざまなデータベースへのログ出力サポートといったさまざまな機能が追加されている。本記事ではまず入門編として、このrsyslogの基本的な機能や設定方法について紹介する。
クラウド環境ではログ収集手法の検討が必須
昨今ではサービスのインフラとしてクラウドサービスやコンテナを利用するケースが増えている。こういったクラウドサービスでは、インスタンスを削除すると、そのインスタンスに割り当てられていたストレージは消滅してしまうことが多い。一部のクラウドサービスではストレージを削除せずに残すことも可能だが、その場合別途コストがかかるのが一般的だ。Dockerなどのコンテナでも同様にコンテナの削除後はそのコンテナ内に格納されていたデータの永続性は保証されない。そのため、永続化したいデータは別途永続化ストレージを用意し、そこに記録しておく必要がある。
サーバーアプリケーションにおいては、生成・管理するデータをデータベースに格納することが一般的であるため、これらについて永続化を意識する必要はあまりないだろう。一方、ログについてはファイルに保存するアプリケーションが少なくないため、その扱いには工夫が必要となるケースが多い。また、ロードバランサを使って負荷分散を行うようなケースでは、ログ解析の際に各サーバーが生成したログを横断的に集計する必要がある。
こういった背景から、昨今では特定のサーバーにログデータを送信して集積・修正するようなアーキテクチャが広く採用されている。これを実現するソフトウェアとしてはさまざまなものがあるが、その1つに多くのLinuxシステムで標準でインストールされているsyslogがある。
syslogは1980年代から存在しており、さまざまなOSで標準のログ機能として採用されていた。また、その実装も複数存在するのだが、現在多くのLinuxディストリビューションでデフォルトで採用されているのが「rsyslog」だ。
rsyslogは以前広く使われていたsyslogdやsysklogdといったsyslog実装と設定ファイルの互換性があるため移行しやすく、さらにプラグイン機構によって機能を拡張できるという特徴がある。
rsyslogのアーキテクチャ
syslogというと単にログを集めてファイルに出力する機能しかないというイメージを持つ人もいるかもしれないが、昨今のrsyslogはもう少し複雑だ。rsyslogの構造や動作についてはTurning Lanes and Rsyslog Queuesというドキュメントが参考になるが(図2)、rsyslogは「input」「parser」「output」といったモジュールから構成されており、これらをつなぎ合わせるように設定を行うことでログをさまざまな方式で処理できるようになっている。
最近ではfluentdやlogstashといったログ収集基盤が注目されているが、rsyslogはこれらに劣らず多機能だ。最新バージョン(バージョン8系)での特徴的な機能はRSyslog - Featuresというページにまとめられているが、その中からいくつか特徴的なものを挙げると以下のようになる。
- MySQLやPostgresQL、SQLite、Oracleなどさまざまデータベースへの書き込みサポート
- TCP経由でのログ転送(圧縮しての転送やTLSによる暗号化通信もサポート)
- テキストファイルを監視してその内容をログに変換する機能
- バックアップサーバーによる冗長構成
- ログファイルの動的な生成
- ログのパースやテンプレートなどを用いた整形
- 設定ファイルの分割
- 動的に機能を追加できるプラグインアーキテクチャ
旧来のsyslogdやsysklog、そしてrsyslog自体の旧バージョンとの互換性維持のため設定ファイルの記述方法に一貫性が欠けていたり、ドキュメントが十分でない、分かりにくいといった問題もあるが、rsyslogはすでに十分な導入実績があることもあり、ログ転送・集積技術としての機能や信頼性は高い。
また、さまざまなログの入力経路を利用できる点もメリットだ。たとえばローカルファイルを監視し、そこに記録されたログを自動的に取り込んで転送する設定や、ログ出力用コマンド(loggerコマンド)経由でログを記録する、といったことが行えるほか、ログの出力先としてsyslogを利用できるアプリケーションも多い。たとえばWebサーバーのnginxや、プロクシソフトウェアのhaproxyではデフォルトでsyslog経由でのログ出力がサポートされている。これを利用して、たとえばnginxのログをそのサーバー上で稼動しているrsyslog経由で別のマシンに転送して集積する、といった設定が可能になる。
なお、syslogソフトウェアとしてはsyslog-ngも有名だ。syslog-ngはBalaBitが開発を主導するオープンソースのsyslog実装で、syslogとプロトコルレベルでは互換性があるが、設定ファイルなどの互換性はない。多くのLinuxディストリビューションでもパッケージが提供されているものの、デフォルトではrsyslogを採用しているディストリビューションが多いようだ。
rsyslogで扱えるメッセージ
syslogでは、「メッセージ」という形でログをやり取りする。syslogにおいては長らく標準的なメッセージフォーマットがなく、2001年のRFC3164(The BSD syslog Protocol)が数少ないフォーマット文書の1つだった。その後2009年にrsyslogの開発者であるRainer Gerhards氏によって、RFC3164を発展させたRFC5424(The Syslog Protocol)が公開された。こちらが現在のsyslogの標準規格となっている。
RFC3164とそれを拡張したRFC5424では若干メッセージ形式が異なっているが、syslogメッセージでまず重要となっているのが「Facility」(ファシリティ)と「Severity」(重要度)という値だ。まずFacilityだが、こちらはそのメッセージがどこから送信されたのかを大まかに分類するための値で、0から23までの数値が割り当てられている(表1)。
数値表記 | キーワード表記 | 対応する送信元 |
---|---|---|
0 | kern | カーネル関連 |
1 | user | ユーザー関連 |
2 | メール関連 | |
3 | daemon | デーモン関連 |
4 | auth | 認証関連(authprivの利用が推奨されている) |
5 | syslog | syslog関連 |
6 | lpr | lpr(プリンタ)関連 |
7 | news | news関連 |
8 | uucp | uucp関連 |
9 | cron | cron関連 |
10 | authpriv | 認証関連 |
11 | ftp | ftp関連 |
12 | NTP関連 | |
13 | ログ監査 | |
14 | ログ警告 | |
15 | クロックデーモン | |
16~23 | local0~local7 | その他 |
また、Severity(Priority、プライオリティ、優先度などとも呼ばれる)はそのログの重要度を示すもので、表2の7段階となっている。その数値が小さいものほど重要度が高いことになっている点に注意したい。
数値表記 | キーワード表記 | 説明 |
---|---|---|
0 | emerg | 緊急(emergencyの略) |
1 | alert | 警報 |
2 | crit | 致命的(criticalの略) |
3 | err | エラー(errorの略) |
4 | warning | 警告 |
5 | notice | 注意 |
6 | info | 通知 |
7 | debug | デバッグ |
syslogを使って生成されたメッセージはすべてこれらのFacilityおよびSeverityが付与されており、ユーザーはこれらの値を使ってメッセージごとにその保存先や転送先などの処理を切り替えることができるようになっている。ちなみに、syslogではファシリティの数値コードを8倍し、それに深刻度(Severity)を足し合わせたものを「Priority」から取った「PRI」と呼んでおり、この数値を使って優先度の指定を行う場合もある。たとえばファシリティが20(local4)、深刻度が5であればPRIの値は20×8+5で「<165>」となる。
さて、RFC3164ではsyslogで扱うメッセージとしてこのPRIとタイムスタンプ、ホスト名、「タグ」と呼ばれる分類用文字列、メッセージ本体のみが定義されていた。具体的には、メッセージは次のような形式となる。
<<PRIの値>> <タイムスタンプ> <送信元ホスト> <タグ><メッセージ本体>
タグには32文字以内の任意の英数字文字列が使用できるが、一般的にはログを生成したプロセス名が使われることが多い。たとえば次の例は、10月11日22:14:15に「mymachine」というホストの「su」プロセスが送信したメッセージで、PRIは34。ここからFacilityは4(「auth」:認証関連)、Severityは2(「crit」、致命的)であることが分かる(34=4×8+2)。
<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8
さらにRFC5424では、このフォーマットとの互換性を保ちつつ、より多くの情報をメッセージに格納できるようフォーマットが拡張されている。
RFC5424で定義されているフォーマットでは、syslogメッセージはヘッダと構造化データ、メッセージから構成されている。まずヘッダにはPRI(プライオリティ)、バージョン、タイムスタンプ、ホスト名、アプリケーション名、プロセスID、メッセージIDといった情報が格納されている(表3)。
格納される情報 | 説明 |
---|---|
PRI | Facilityの数値コードを8倍し、それにSeverityの数値コードを足し合わせた数値を「<」「>」で囲んだもの |
バージョン | 使用するsyslogプロトコルのバージョン |
タイムスタンプ | メッセージが生成された日時 |
ホスト名 | メッセージが生成されたホスト。FQDNだけでなく、IPアドレスやホスト名などが入る場合もある。 |
アプリケーション名 | メッセージの生成元アプリケーション名 |
プロセスID | メッセージやアプリケーションで任意に使用できるID |
メッセージID | メッセージの種別を識別するためのID |
また、構造化データには「<キー>=<値>」形式でさまざまな情報が格納できるようになっている。具体的には次のような角括弧でIDとキー、値が囲まれたフォーマットとなっている。
[<構造化データID> <キー1>=<値1> <キー2>=<値2>...]
構造化データIDは、その構造化データがどのような情報を格納しているかを示すIDだ。RFC5242では「timeQuality」や「origin」、「meta」などが例示されているが、これ以外のものも指定可能だ。この構造化データは複数を指定することもできるし、1つも指定しないことも許されている。
最後のメッセージには任意のデータもしくはUTF-8形式のテキストが格納できる。ただし、慣例上次のようなフォーマットが使われることが多い。
<タグ><コンテンツ>
「タグ」は前述のとおり32文字以内の英数字で、メッセージの発信元などの情報が記されることが多い。また、コンテンツはメッセージの内容を示すものだ。また、これも慣例だが、一般的にはタグはメッセージの生成元プロセスが格納され、コンテンツは次のフォーマットになっていることが多い。
[<プロセスID>]: <何らかのメッセージ>
rsyslogの基本的な設定
さて、それではrsyslogの具体的な設定方法について紹介していこう。なお、rsyslogは多くのディストリビューションで公式パッケージとしてバイナリパッケージが提供されているため、インストール方法についての説明は割愛する。
rsyslogの設定ファイル
rsyslogでは、設定ファイルにrsyslog自体の動作やログの処理方法を記述して設定を行っていく。デフォルトの設定ファイルは/etc/rsyslog.confが一般的だ。
この設定ファイルでは「#」から行末までがコメントとなり、またC言語などで使われている「/* */」形式のコメントも利用可能だ(「/*」から「*/」までの部分はコメントとして無視される)。
rsyslogの設定ファイルでは、大きく分けて2種類の設定を行える。まず1つは使用するモジュールやrsyslogの挙動を設定するもの、もう1つは受信したログに対しどのようなアクションを実行するかを指定するものだ。
また、後者のアクション指定については、従来のsyslogと互換性のあるファシリティおよびプライオリティをベースとした設定方法(「Legacy Configuration Directives」などと呼ばれている)と、rsyslog独自のスクリプト言語(RainerScript)を用いた、if/else-if/else文やforeach文とaction()ディレクティブを使った設定方法(「new-style action definitions」と呼ばれている)の2種類がある。
前者はシンプルで簡単に記述できるというメリットがあり、後者は柔軟な設定が可能という特徴がある。これらは両方を組み合わせて使用可能なので、まずは前者の設定を使用し、もしこれで機能が不足しているようなら後者の設定方法を使用することをおすすめする。
モジュールのロード
それでは、まずrsyslog自体の挙動の設定について説明していこう。rsyslogでは、設定ファイル中に「$」で始まるディレクティブや「module()」、「input()」などのメソッドを記述することで各種設定を行うようになっている。設定できるパラメータは多岐にわたるが、ここでは比較的利用頻度の高いものを紹介していこう。
rsyslogでは、コア部分は最低限の機能のみを実装し、オプショナルな機能は別途モジュールとして実装するアーキテクチャを採用している。そのため、利用したい機能がモジュールとして実装されている場合は事前にそのモジュールをロードするよう設定しておく必要がある。モジュールのロードは「module()」メソッドで行える。
module(load="<モジュール名>" [[<パラメータ>=<値>] ...])
モジュールにはさまざまなものがあるが、よく使われるモジュールとしては表4のものが挙げられる。これ以外のモジュールについては、rsyslogのドキュメントが参考になる。
モジュール名 | 説明 | 備考 |
imuxsock | UNIXソケット経由でのログを受け取る | |
imklog | カーネルログを受け取る | |
imudp | UDP経由でのログを受け取る | |
imtcp | TCP経由でのログを受け取る | |
imfile | ログファイルを定期的にチェックしてログを受け取る | |
imjournal | systemdのjournal(ログ)を受け取る | |
omfile | ファイルにログを出力する | ビルトイン |
ompipe | パイプを使用してログを任意のプログラムに渡す | ビルトイン |
omjournal | systemdのjournalにログを出力する | |
omfwd | UDP/TCP経由でログを転送する | ビルトイン |
ommysql | MySQLにログを出力する | |
omelasticsearch | Elasticsearchにログを出力する | |
ompgsql | PostgreSQLにログを出力する |
ここで備考に「ビルトイン」となっているモジュールはデフォルトでロードされるモジュールで、特に明示的にロードしなくても有効になる。また、指定できるパラメータはモジュールごとに異なるので、それぞれのドキュメントを確認して欲しい。
ちなみに、rsyslogの旧バージョン(バージョン5以前)ではmodule()メソッドではなく「$ModLoad」というディレクティブでモジュールのロードを行うようになっていた。互換性維持のため、バージョン7以降でもこれらディレクティブはサポートされている。
$ModLoad <モジュール名>
$ModLoad形式でモジュールをロードする場合、パラメータの設定は別途用意されている設定ディレクティブを使って個別に設定する形となっている。これらパラメータは、たとえばimklogモジュール向けパラメータであれば「KLog*」、imjournalモジュール向けパラメータであれば「IMJournal*」など、各モジュールに関連したプレフィックスが付けられている。これらについて詳しくは各モジュールのドキュメントを参照して欲しい。
ログの入力ソースの設定
rsyslogではさまざまな経路を使ってログを受け取ることができるようになっており、各入力ソースごとの設定は「input()」ディレクティブで行う。たとえばUDP経由でログを受け取るには、「imudp」モジュールをロードした上で、次のようにinputディレクティブでその設定を行っておく必要がある。
module(load="imudp") input(type="imudp" port="<ポート番号>") もしくは $ModLoad imudp $UDPServerRun <ポート番号>
ここで「port=<ポート番号>」オプションでは、ログの受け取りに使用するポート番号を指定する。
同様にTCPでログを受け取るには、次のように設定する。
module(load="imtcp") input(type="imtcp" port="514") もしくは $ModLoad imtcp $InputTCPServerRun 514
このようにネットワーク経由でログを受け取る設定を有効にした場合、別途ファイアウォール等を使用して外部からのアクセスを適切に制限することが推奨されている。ログの送信先を制限する「$AllowedSender」という設定ディレクティブも用意されているが、これは後方互換性維持のためだけに残されており、使用が推奨されていない。
また、UNIXソケット経由でのログを受け付ける「imuxsock」モジュールやカーネルログを受け付ける「imklog」モジュールでは、特にinput()ディレクティブで設定を行わなくとも入力が有効になる。
別の設定ファイルをロードする
rsyslogでは、「$IncludeConfig」ディレクティブを使用することで、別の設定ファイルを読み込んでその設定を追加できる。
$IncludeConfig <設定ファイルのパス名>
ここで、設定ファイルのパス名にはワイルドカードを指定可能だ。たとえば次のように記述されていた場合、/etc/rsyslog.dディレクトリ内で拡張子が「.conf」のファイルすべてが読み込まれる。
$IncludeConfig /etc/rsyslog.d/*.conf
そのほかの設定
そのほかrsyslogの設定ファイルでよく使われているものとしては表5のものがある。いくつかの設定項目は新しいバージョンのrsyslogでは利用が非推奨となっているものもあるので注意したい。
ディレクティブ名 | 説明 |
---|---|
$PrivDropToUser | rsyslogプロセスを指定したユーザーで実行する |
$PrivDropToGroup | rsyslogプロセスを指定したグループで実行する |
$WorkDirectory | 指定したディレクトリを作業ディレクトリとして使用する |
$Umask | rsyslogdプロセスのumaskを指定 |
$RepeatedMsgReduction | 「on」に設定すると連続で発生した同一のログメッセージを省略する(非推奨) |
$FileOwner | ファイル作成時のオーナーを指定 |
$FileGroup | ファイル作成時のグループを指定 |
$DirOwner | ディレクトリ作成時のオーナーを指定 |
$DirGroup | ディレクトリ作成時のグループを指定 |
$FileCreateMode | ファイル作成時のパーミッションを指定 |
$DirCreateMode | ディレクトリ作成時のパーミッションを指定 |
ファシリティベースのアクション設定
続いて、受け取ったメッセージの保存や転送に関する設定について説明する。まずはsyslogと互換性のあるファシリティおよびプライオリティベースのアクション設定だが、これは次のような形式で記述する。
<フィルタ> <アクション>
「フィルタ」には対象とするメッセージを指定する条件式を記述するのだが、rsyslogでは次の3種類の表記方法が利用できる。今回はまず従来のsyslogと互換性のあるセレクタベースの表記について解説し、残りの2つについては記事後編で紹介する。
- 従来のsyslogと互換性のあるセレクタベースの表記
- メッセージのプロパティを対象した表記
- if~then式を使った表記
セレクタベースの表記では、「<Facility>.<Severity>」という形でFacilityとSeverityを指定する。ここで指定したFacilityを持ち、かつSeverityの数値が指定されたものよりも小さいものに対し、指定したアクションが実行される。
たとえば「kern.warning」のように指定すると、Facilityが「kern」(0)で、Severityが「warning」(4)以下のログに対し指定したアクションが実行される。
また、ファシリティはカンマを使って複数が指定可能だ。たとえば「local1,local2」のように指定すると、local1およびlocal2というファシリティを持つログが処理対象となる。これらに加え、FacilityおよびSeverityにはすべてにマッチするワイルドカード(「*」)も使用できる。さらに、「;」で連結することで複数のセレクタを指定可能だ。この場合、指定したいずれかのセレクタに該当した際に指定したアクションが実行されるようになる。
アクションの設定
続いて「アクション」部の設定だが、ここにはログの出力先もしくは転送先を指定する。たとえばここでファイル名をフルパスで指定すると、そのファイルにログが出力される。また、ファイル名の前に「-」を付けると、ログの書き込み後にsync(バッファのフラッシュ)が行われるようになる。なお、ログファイル作成時のパーミッションは$FileOwnerや$FileGroupなどのディレクティブで設定できる。
たとえば次の例は、kernel関連のログを/var/log/kern.logというファイルに出力するものだ。
kern.* -/var/log/kern.log
アクションとして「@<ホスト名/IPアドレス>」のように指定すると、指定したマシン上で稼動しているsyslogにUDPでメッセージが転送される。また、「@@<ホスト名/IPアドレス>」のように指定すると、そのマシン上で稼動しているsyslogにTCPでメッセージが転送される。なお、TCPでのメッセージ転送はオリジナルのsyslogではサポートされていない機能である点には注意が必要だ。ここでポート番号を指定したい場合は「@@<ホスト名/IPアドレス>:<ポート番号>」や「@@<ホスト名/IPアドレス>:<ポート番号>」のように記述する。
さらに、「@(z<数値>)」のように指定することでメッセージを圧縮して送信することもできる。ここで数値には数値には1~9までが指定可能で、大きいほど圧縮率が高くなる。なお、TCPで転送する場合はデフォルトで圧縮が有効になる。
アクションにはユーザー名を指定することも可能だ。この場合、そのユーザーのコンソールにメッセージが出力される。ユーザー名の代わりに「*」を指定すると、すべてのユーザーのコンソールにメッセージが出力されるようになる。
そのほか、「|<実行可能ファイル>」と指定すると、指定したファイルを実行し、パイプを使ってその標準入力にメッセージが渡される。また、「~」を指定すると、そのメッセージはどこにも出力されずに廃棄される。
アクションとしてモジュールを指定する
rsyslogではアクションとしてモジュールを指定することもできる。この場合、その書式は次のようになる。
:<プラグイン名>:<パラメータ> もしくは action(type="<プラグイン名>" [<パラメータ>=<値>...])
たとえばMySQLにメッセージを出力する「ommysql」モジュールを利用してMySQLデータベースにメッセージを出力する場合、次のようになる。
:ommysql:<サーバー名>:<データベース名>:<ユーザー名>:<パスワード> もしくは action(type="ommysql" server="<サーバー名>" serverport="<ポート番号>" db="<データベース名>" uid="<ユーザー名>" pwd="<パスワード>")
なお、MySQLデータベースにメッセージを出力する場合はあらかじめテーブル作成用スクリプト(createDB.sql)を実行して必要なテーブルを作成しておく必要がある。
rsyslogでは1つのセレクタに対し複数のアクションを指定することも可能だ。この場合、次のような書式となる。
<セレクタ> <アクション1> & <アクション2> & <アクション3> :
rsyslogのより発展的な機能を使う
さて、ここまでで説明してきたのは、ほぼ旧来のsyslogと互換性のある設定内容だった。前述のとおりrsyslogでは多くの機能拡張が行われており、新たに導入された記述スタイルを利用することで、より多くの機能が利用できるようになっている。記事後編ではこれらrsyslog独自の機能について紹介する。