「rsyslog」のデータベース出力機能やテンプレート機能、スクリプティング機能を活用する

ログ管理ソフトウェア「rsyslog」ではモジュール方式でさまざまな機能が追加されているほか、独自のスクリプト言語を使った柔軟な設定が行えるようになっている。前編に引き続き、これらrsyslog独自の機能について紹介する。

rsyslog独自の設定表記

rsyslogの設定ファイルは従来のsyslogと互換性があるようになっており、syslogを使っていたユーザーであればまったく同じ方式で基本的な設定が可能になっている。しかし、syslogの設定は基本的にはFacilityやSeverityで条件を指定する「セレクタ」と、実行する処理を指定する「アクション」の組み合わせだけで構成されており、複雑な条件やアクションは指定できなかった。rsyslogでは独自の新たな表記方法を導入することで、さまざまな条件分岐や複雑な処理を行えるようになっている。

rsyslog独自のフィルタ

rsyslogでは、処理対象とするメッセージを指定するフィルタには次の3種類の表記方法があることを前編記事で述べた。

  • 従来のsyslogと互換性のあるセレクタベースの表記
  • メッセージのプロパティを対象とした表記
  • if~then式を使った表記

続いては、前編では説明していなかったメッセージのプロパティを対象とした表記と、if~then式を使った表記方法について紹介しよう。

まず、メッセージのプロパティを対象とした表記方法(「Property-Based Filters」)だが、これはメッセージのFacilityやSeverityだけでなく、ヘッダ内の各データや構造化データ、メッセージ本体というメッセージを構成するすべての要素(プロパティ)を対象にして条件を記述できるというものだ。具体的には次のような書式となる。

:<プロパティ>, <条件文>, "<値>"

「プロパティ」はチェックする対象を指定するもので、たとえばメッセージ本文であれば「msg」を指定する。プロパティについてはドキュメントを参照して欲しいが、よく使われるプロパティとしては表1のものがある。

表1 よく使われるプロパティ
プロパティ名 説明
msg メッセージ本体
hostname 出力元のホスト名
source 出力元のホスト名(hostnameのエイリアス)
pri PRIの値
syslogtag タグ
programname タグ中のプロセス名
syslogfacility Facility(数値)
syslogfacility-text Facility(文字列)
syslogseverity Severity(数値)
syslogseverity-text Severity(文字列)
syslogpriority Severity(数値、syslogseverityのエイリアス)
syslogpriority-text Severity(文字列、syslogseverity-textのエイリアス)
timegenerated メッセージを受け取った時刻
timereported メッセージに含まれている時刻
timestamp メッセージに含まれている時刻(timereportedのエイリアス)

なお、rsyslogではメッセージに対し任意の独自プロパティを追加できるようになっており、これら独自プロパティは次のようにして参照できる。

$!<プロパティ名>

プロパティは文字列や数値だけでなく、キーとそれに対応した値を持つ、いわゆる辞書型の値も格納できる。この場合、その要素には次のようにしてアクセスできる。

$!<プロパティ名>!<キー名1>[!<キー名2>...]

JavaScriptでは「foo.bar.hoge」のように「.」と使ってオブジェクトの各プロパティにアクセスするが、rsyslogでは「.」の代わりに「!」を使用すると考えれば良い。たとえばメッセージに対し「foo」という名前で次のようなオブジェクトが格納されていた場合、「$!foo!bar」の値は「hello」、「$!foo!baz!hoge」の値は「world」となる。

{
  "bar": "hello",
  "baz": {
    "hoge": "world",
    "moge": 1
  }
}

「条件キーワード」はプロパティと値をどのように比較するのかを指定するもので、表2のものがサポートされている。

表2 サポートされている条件文
条件キーワード 説明
contains 指定した値を含む
isequal 指定した値と完全に一致する
startswith 指定した値で始まる
regex 指定した値を正規表現とし、それにマッチする
eregex 指定した値を拡張正規表現とし、それにマッチする
!<条件キーワード> 指定した条件キーワードを満たさない場合にアクションを実行する(否定)

たとえば次の例は、メッセージが「[UFW」という文字列を含むという意味のセレクタとなる。

:msg,contains,"[UFW"

if~then式を使った表記

if~then式を使った表記では、次のような形でフィルタとアクションを記述する。

if <式> then <アクション>

式部分には「==」や「!=」、「<=」、「>=」などの比較演算子、「+」や「-」、「*」、「/」、「%」などの四則演算子を行う演算子、文字列の結合を行う「&」演算子、「contains」、「startwith」、複数の式を結合する「and」や「or」、否定演算子の「!」といった演算子を利用して条件式を記述できる。

たとえば、Facilityが「kern」であるという条件は次のように記述できる。

if $syslogfacility-text == 'kern' then <アクション>

ここで、プロパティは「$<プロパティ名>」という表記になる点には注意したい。

ちなみに、否定条件を使用する場合は次のように括弧で条件式を囲む必要がある。たとえばメッセージが「foo」で始まらない、という条件は次のようになる。

if not ($msg startswith 'foo') then <アクション>

テンプレートの使用

rsyslogでは受け取ったメッセージを元にメッセージを整形して出力するテンプレート機能が搭載されている。テンプレートはtemplate()文で定義できるのだが、そのパラメータの指定方法は次のようなやや独特なものとなっている。

template(name=<テンプレート名> type=<テンプレートタイプ>) {
  <テンプレート定義本体>
  
  
}

テンプレートタイプとしては「list」もしくは「subtree」、「string」、「plugin」のいずれかを指定する。listを指定した場合、テンプレート定義本体は文字列を指定する「constant()」と、プロパティを指定する「property()」から構成されるリストとなり、テンプレートの出力結果はこれらを連結したものとなる。

たとえば次の例は、メッセージを「message is: <メッセージのメッセージ>\n」という形に整形するものだ。

template(name="sample1" type="list") {
  constant(value="message is: ")
  property(name="msg")
  constant(value="\n")
}

この例は、まず「constant(value="message is: ")」で指定された「message is: 」という文字列が出力され、続いて「property(name="msg")」で指定された「msg」プロパティの値(メッセージ本体)が出力され、最後に「constant(value="\n")」で指定された改行が出力されるというテンプレートになっている。

テンプレートタイプとして「subtree」を指定すると、そのテンプレートは指定したプロパティを取り出すというものになる。たとえば次のように指定すると、メッセージの「usr」プロパティに格納されているオブジェクトから、「foo」というキーに格納されている値を取り出して出力する処理が行われる。

template(name="foo" type="subtree" subtree="$!usr!foo")

また、テンプレートタイプとして「string」を指定すると、文字列中に「%<プロパティ名>%」という形式でプロパティを埋め込むフォーマットでテンプレートを指定できる。

次の例は、メッセージを「message is: <メッセージのメッセージ>」という形に整形するものだ。

template(name="sample3" type="string"
  string="message is: %MSG%\n"

ここでは、Property Replacerという表現も指定できる。Property Replacerは次のような表現で指定したプロパティに対し変換処理を行えるものだ。

%<プロパティ名>:<変換元文字>:<変換先文字>:<オプション>%

ここで、変換元文字/変換先文字には正規表現も利用可能だ。さらにオプションでは、大文字/小文字の変換やCSVなどさまざまなフォーマットへの変換もできる。これらについて詳しくはドキュメントを参照して欲しい。

プラグインを使ってメッセージを整形することも可能だ。これは、テンプレートタイプとして「plugin」を指定することで実現できる。次の例は、「foobar」というプラグインを使ってメッセージを整形するものだ。

template(name="smaple4" type="plugin" plugin="foobar")

テンプレートの利用

「<フィルタ> <アクション>」形式で条件とアクションを指定した場合、設定行の末尾に「;<テンプレート名>」を追加することで、出力を行う際に指定したテンプレートを使ってメッセージを整形できる。たとえば次の例は、facilityが「local1」のメッセージを、「template1」というテンプレートで整形した上で/var/log/sample1というファイルに出力するものだ。

local1.* /var/log/sample1;template1

また、action()文を使用してアクションを指定する場合は「template="<テンプレート名>"」というパラメータを追加することで使用するテンプレートを指定できる。

RainerScriptを用いたrsyslogの設定

rsyslog v5以降では、if/else if/else文やforeach文などの条件分岐/ループ文を使ってメッセージに対する処理を指定できるようになった。これによってスクリプト言語を使ったような設定が記述でき、これらの記述方法は「RainerScript」と呼ばれている。これを利用することで、処理するメッセージの条件を柔軟に記述したり、メッセージの整形といった処理をさらに詳しく行えるようになる。

ただ、記述が冗長になるほか、問題が起きた際のデバッグが難しくなるというデメリットもある。RainerScriptは従来の「<フィルタ> <アクション>」形式の設定と共存が可能なので、必要に応じての利用が望ましい。

if文を使った基本的な設定

RainerScriptを使った設定の基本は、次のようにif文を使って条件を指定したうえでaction()文を使ってアクションを実行する、という形になる。

if (<条件式>) then {
    action()

条件式は、先の「if~then式を使った表記」と同じく「==」や「!=」、「<>」、「<」、「>」、「<=」、「>=」、「and」、「or」、「not」などが利用可能だ。

たとえば次の例は、メッセージ内に「important」という文字列が含まれていた場合、これを「/var/log/important.log」というファイルに出力するというものだ。

if ($msg contains "important") then {
   action(type="omfile" file="/var/log/important.log")
}

また、if文をネストさせたり、else if文やelse文を組み合わせることで、より複雑な条件分岐も指定できる。次の例は、メッセージの送信元(hostname)によって出力先ファイルを切り替えるものだ。

if ($msg contains "important") then {
    if ($hostname  startswith "foo") {
        action(type="omfile" file="/var/log/important_foo.log")
    } else if ($hostname startswith "bar") then {
        action(type="omfile" file="/var/log/important_bar.log")
    } else {
       action(type="omfile" file="/var/log/important.log")
    }
}

変数の利用

RainerScriptでは、任意の値を格納しておけるローカル変数を定義できる。ローカル変数は「set」キーワードで定義できる。

set $.<変数名> = <値>

たとえば、「$.x」という変数に「foo」という文字列を代入するには、次のようにする。

set $.x = "foo"

RainerScriptでは変数にオブジェクトを格納することも可能だ。たとえば次の例は、$.x変数にオブジェクトを格納し、「foo」キーに対し「hoge」、「bar」キーに対し「moge」という文字列を格納している(「{ "foo": "hoge", "bar": "moge"}」に相当)。

set $.x!foo = "hoge"
set $.x!bar = "moge"

また、指定したキーに対応する要素を削除する「unset」キーワードや、変数をリセットしてから指定した値をセットする「reset」キーワードも用意されている。

unset $.<変数名>
reset $.<変数名> = <値>

setキーワードでは、ローカル変数だけでなくメッセージに新たなプロパティを追加するためにも利用できる。この場合次のように「$.」ではなく「$!」を使用する。

set $!<プロパティ> = <値>

たとえば次の例では、メッセージに対し「foo」という名前のプロパティを追加し、そこに「{ "count": 1, "message": <メッセージ本体>}」というオブジェクトを格納している。

set $!foo!count = 1
set $!foo!message = $msg;

これとテンプレートのsubtree機能を組み合わせることで、指定した要素や値のみを出力するといったことが可能になる。

foreach文

指定した配列やオブジェクトに格納されている各要素を対象に繰り返し処理を行うforeach文も用意されている。

foreach ($.<変数名> in $!<プロパティ>) do {
   <実行する処理>
}

RainerScriptのforeach文はさまざまなスクリプト言語で採用されているfor/foreacah文と同様、指定した要素内の要素を1つずつ指定した変数に代入して処理を実行する、というものだ。指定した要素がオブジェクトだった場合、変数には「{"<キー>": <値>}」というオブジェクトが代入される。

次の例は、メッセージ中のfooという要素に格納されている各要素を、「foobar」テンプレートを使って/var/log/foo.logに出力するものだ。なお、この例のように1つのメッセージに対して複数回のアクションを実行する場合は「action.copyMsg」パラメータを「on」に設定することが推奨されている。

foreach ($.work in $!foo) do {
    action(type="omfile" file="/var/log/foo.log" template="foobar" action.copyMsg="on")
}

組み込み関数の利用

RainerScriptではいくつかの組み込み関数も用意されている(表3)。

表3 利用できる組み込み関数(抜粋)
関数名 説明
getenv(str) 指定した環境変数の値を返す
strlen(str) 指定した文字列の長さを返す
tolower(str) 指定した文字列を小文字にして返す
cstr(expr) 指定した式を評価した結果を文字列として返す
cnum(expr) 指定した式を評価した結果を数値として返す
wrap(str, wrapper_str) strの前後にwrapper_strを付与した文字列を返す
wrap(str, wrapper_str, escaper_str) strの前後にwrapper_strを付与した文字列を返す。str中にwrapper_strと一致する文字が含まれていた場合、それをescaper_strに置換する
replace(str, substr_to_replace, replace_with) str中にsubstr_to_replaceと一致する文字列が含まれていた場合、それをreplace_withに置換する
re_match(expr, re) exprが拡張正規表現reにマッチしたら1を、そうでない場合は0を返す
re_extract(expr, re, match, submatch, no-found) exprが拡張正規表現reにマッチした場合、そのmatch回目のマッチ結果でsubmatch番目のサブマッチを返す。マッチしなかった場合no-foundで指定した値を返す。
field(str, delim, matchnbr) strをdelimで指定した文字列で分割し、そのmatchnbr番目の文字列を返す

これらに加えて、「+」や「-」、「*」、「/」など数値に対する四則演算なども提供される。

rsyslogを用いた設定例

最後に、RainerScriptを使った設定例をいくつか紹介しよう。

MySQLデータベースにログを出力する

次の例は、Facilityが「local0」で、タグ中のプログラム名が「test01」のメッセージをMySQLデータベースに出力するものだ。

module(load="ommysql")
if( syslogfacilty-text == "local0"
    and programname == "test01") then {
    action(type="ommysql"
              server="<MySQLが稼動しているマシンのIPアドレス/ホスト名"
              serverport="<ポート番号>"
              db="<データベース名>"
              uid="<接続に使用するユーザー名>"
              pwd="<パスワード>")
}

ちなみに、ここでは出力の際に使用するテンプレートを指定していないが、この場合デフォルトで次のようなテンプレートが使用される。

"insert into SystemEvents (Message, Facility, FromHost,
Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values
('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%,
'%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%,
'%syslogtag%')"

このとき各プロパティの値は適切にクォートされる。INSERT文を発行するテンプレートを独自に定義することで、独自に定義したテーブルにログを出力することももちろん可能だ。

ちなみに、設定が正しく行えているかのテストには「logger」コマンドが利用できる。たとえば次のように実行すると、「local0.info」というFacility/Severityのログをrsyslogに送信できる。

$ logger -p local0.info -t test01 --id=0 -- This is test.

ログの送信後にテーブルをSystemEventsテーブルを確認してみると、次のようにメッセージが格納されていることが確認できる。

mysql> select * from SystemEvents;
+----+------------+---------------------+---------------------+----------+----------+----------+----------------+------------+------------+-------------+-----------+---------------+---------+-----------------+--------------+-----------+----------+----------+------------+-----------+--------------+-----------------+----------+
| ID | CustomerID | ReceivedAt          | DeviceReportedTime  | Facility | Priority | FromHost | Message        | NTSeverity | Importance | EventSource | EventUser | EventCategory | EventID | EventBinaryData | MaxAvailable | CurrUsage | MinUsage | MaxUsage | InfoUnitID | SysLogTag | EventLogType | GenericFileName | SystemID |
+----+------------+---------------------+---------------------+----------+----------+----------+----------------+------------+------------+-------------+-----------+---------------+---------+-----------------+--------------+-----------+----------+----------+------------+-----------+--------------+-----------------+----------+
|  1 |       NULL | 2017-05-15 21:25:13 | 2017-05-15 21:25:13 |       16 |        6 | ubuntu   |  This is test. |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | test01:   | NULL         | NULL            |     NULL |
+----+------------+---------------------+---------------------+----------+----------+----------+----------------+------------+------------+-------------+-----------+---------------+---------+-----------------+--------------+-----------+----------+----------+------------+-----------+--------------+-----------------+----------+

Apache HTTP ServerのログをElasticsearchに出力する

続いては、Apache HTTP Server(httpd)のログを分散型データベース「Elasticsearch」に出力する設定例を紹介しよう。Elasticsearchは柔軟な検索機能を備えているのが特徴で、ログ解析などの用途で使われている。Elasticsearchについては以前「15分で作る、Logstash+Elasticsearchによるログ収集・解析環境」という記事で紹介しているので、詳しくはこちらの記事や公式サイトのドキュメントなどを参照して欲しい。

httpdは標準ではsyslogへのログ出力機能を備えていない。そのため、何らかの方法でログをsyslogに送信する必要がある。このための手段の1つとしては、ログ出力時にloggerコマンドを実行するよう設定する方法がある。これは、Apacheの設定ファイル内のログ設定(CustomLogディレクティブ)で次のように指定することで実現できる。

CustomLog "|/usr/bin/logger -t httpd -p <Facility>.<Severity>" <ログフォーマット>

ただし、この方法だとログを出力するたびにloggerコマンドが実行されるため、そのオーバーヘッドが発生する。そこで、今回はrsyslogが備える、指定したファイルを監視してそのファイルが変更されたらその内容を読み込んで処理する機能を利用し、httpdのログを取得してみよう。

この機能は、「imfile」モジュールで提供されている(rsyslogのドキュメント)。たとえば「/var/log/httpd/access_log」というログファイルを取り込み、「httpd」というタグを付けてFacilityが「local0」、Severityが「notice」のログとして扱うには以下のように記述する。

module(load="imfile")
input(type="imfile"
      file="/var/log/httpd/access_log"
      tag="httpd"
      facility="local0"
      severity="notice")

さて、このようにして取得したメッセージをそのままElasticsearchに格納しても良いのだが、Elasticsearchの検索機能を活用したい場合、メッセージ本体をパースし、各項目ごとに異なるフィールドに格納するほうが良い。このようなメッセージのパースは、rsyslogのmmnormalizeモジュールを利用することで実現できる。

mmnormalizeモジュールは、Linuxディストリビューションによってはrsyslogとは別のパッケージで提供されている場合があるので注意したい。たとえばCentOS 7では、「rsyslog-mmnormalize」というパッケージのインストールが必要になる。

mmnormalizeモジュールは、liblognormというライブラリを使用し、あらかじめ定義しておいたパースルールに基づいてメッセージを処理する機能を提供する。このパースルールは通常はrsyslogの設定ファイルとは別に用意しておくのが一般的だ。今回は/etc/rsyslogというディレクトリを作成し、そこに「combined_apache.rulebase」という名前でパースルールを記述したファイルを作成した。Apacheの「Combined」形式のログをパースする場合、このファイルの中身は以下のようになる。

rule=:%clientip:word% %ident:word% %auth:word% [%timestamp:char-to:]%] "%verb:word% %request:word% HTTP/%httpversion:char-to:"%" %response:number% %bytes:word% "%referrer:char-to:"%" "%agent:char-to:"%"

libnormalizeでは独自の表記方法でルールを記述するようになっている。詳しくはドキュメントを参照して欲しいが、基本的には次のようなフォーマットになっている。

%<格納するプロパティ名>:<読み取る文字種別>%

読み取る文字種列としては「word」(非空白文字)、「number」(数値)、「char-to:<文字>」(指定した文字が現れる直前まで)などが指定できる。

たとえば、上記のルールでは、まずメッセージの先頭から非空白文字が現れるまでを読み取り、それを「clientip」というプロパティに格納する。続いて空白文字を1文字読み飛ばし、続けてまた非空白文字が現れるまでを読み取ってそれを「ident」というプロパティに格納し……という処理を行う。

メッセージをパースするには、action()文を使用する。

action(type="mmnormalize" ruleBase="<ルールファイル>")

たとえば先ほど作成した/etc/rsyslog/combined_apache.rulebaseファイルを使用してパースを行う場合、次のようになる。

module(load="mmnormalize")
action(type="mmnormalize" ruleBase="/etc/rsyslog/combined_apache.rulebase")

ちなみに、ルールの作成・デバッグ時には指定したルールで任意の文字列をパースするコマンドラインツール「lognormalizer」が便利だ。このツールはCentOS 7やDebianでは「liblognorm-utils」というパッケージに含まれているもので、次のように実行することで指定したルールファイルを使って標準入力から指定した文字列を読み込み、そのパース結果を表示してくれる。これを利用し、指定したログを正しくパースできるかを確認すると良いだろう。

echo <文字列> | lognormalizer -r <ルールファイル>

続いて、出力に使用するテンプレートを定義する。このテンプレートは、メッセージをJSON形式に変換するものになる。今回は「elasticsearch_template」という名前で、次のように定義した。

template(name="elasticsearch_template"
         type="list"
         option.json="on") {
           constant(value="{")
             constant(value="\"clientip\":\"")      property(name="$!clientip")
             constant(value="\",\"ident\":\"")      property(name="$!ident")
             constant(value="\",\"auth\":\"")      property(name="$!auth")
             constant(value="\",\"timestamp\":\"")      property(name="$!timestamp")
             constant(value="\",\"verb\":\"")      property(name="$!verb")
             constant(value="\",\"request\":\"")      property(name="$!request")
             constant(value="\",\"httpversion\":\"")      property(name="$!httpversion")
             constant(value="\",\"response\":\"")      property(name="$!response")
             constant(value="\",\"bytes\":\"")      property(name="$!bytes")
             constant(value="\",\"referrer\":\"")      property(name="$!referrer")
             constant(value="\",\"agent\":\"")      property(name="$!agent")
             constant(value="\",\"type\":\"apache_access")
             constant(value="\",\"originalmsg\":\"")  property(name="msg")
           constant(value="\"}\n")
         }

やや分かりにくいが、これはmmnormalizeでパースした結果をJSON形式に変換するものだ。

最後に、omelasticsearchモジュールを指定してElasticsearchへの出力を行う。CentOS 7やDebianでは、このモジュールを利用するために「rsyslog-elasticsearch」パッケージのインストールが必要なので、事前にインストールしておこう。

module(load="omelasticsearch")
action(type="omelasticsearch"
       server="<Elasticsearchが稼動しているホスト名/IPアドレス>"
       serverport="<Elasticsearchが稼動しているポート番号>"
       template="elasticsearch_template"
       searchIndex="<格納先インデックス名>"
       bulkmode="on"
)

これら設定をまとめたものは次のようになる。

module(load="imfile")
module(load="mmnormalize")
module(load="omelasticsearch")

input(type="imfile"
      file="/var/log/httpd/access_log"
      tag="httpd:"
      facility="local0"
      severity="notice")

template(name="elasticsearch_template"
         type="list"
         option.json="on") {
           constant(value="{")
             constant(value="\"clientip\":\"")      property(name="$!clientip")
             constant(value="\",\"ident\":\"")      property(name="$!ident")
             constant(value="\",\"auth\":\"")      property(name="$!auth")
             constant(value="\",\"timestamp\":\"")      property(name="$!timestamp")
             constant(value="\",\"verb\":\"")      property(name="$!verb")
             constant(value="\",\"request\":\"")      property(name="$!request")
             constant(value="\",\"httpversion\":\"")      property(name="$!httpversion")
             constant(value="\",\"response\":\"")      property(name="$!response")
             constant(value="\",\"bytes\":\"")      property(name="$!bytes")
             constant(value="\",\"referrer\":\"")      property(name="$!referrer")
             constant(value="\",\"agent\":\"")      property(name="$!agent")
             constant(value="\",\"type\":\"apache_access")
             constant(value="\",\"originalmsg\":\"")  property(name="msg")
           constant(value="\"}\n")
         }

if $syslogtag == "httpd:" then {
    action(type="mmnormalize" ruleBase="/etc/rsyslog/combined_apache.rulebase")
    action(type="omelasticsearch"
           server="172.17.4.199"
           serverport="9200"
           template="elasticsearch_template"
           searchIndex="httpd"
           bulkmode="on"
    )
}

この設定を追加した後、rsyslogを再起動することでhttpdのログが取り込まれてElasticsearchに送信されるようになる。

正しくログが取り込まれているかどうかは次のようにcurlコマンドで確認できる。

$ curl -XGET '<ホスト>:<ポート>/_aliases?pretty'
{
  "httpd" : {    ←ログが取り込まれていれば指定したインデックスが作成されている
    "aliases" : { }
  }
}

$ curl -XGET '<ホスト>:<ポート>/<インデックス名>/_search'
{"took":635,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"httpd","_type":"events","_id":"AVwa02LiDe5URMKYs-ZL","_score":1.0,"_source":{"clientip":"172.17.4.202","ident":"-","auth":"-","timestamp":"18/May/2017:18:11:11 +0900","verb":"GET","request":"/","httpversion":"1.1","response":"304","bytes":"-","referrer":"-","agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36","type":"apache_access","originalmsg":"172.17.4.202 - - [18/May/2017:18:11:11 +0900] \"GET / HTTP/1.1\" 304 - \"-\" \"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36\""}}]}}
↑送信されたログが出力される

rsyslogだけでさまざまな処理が実行できるのがメリット

rsyslogは多くのLinuxディストリビューションで提供されており、特に別途外部リポジトリなどを使わずに利用できるのが大きなメリットだ。やや設定が面倒ではあるが、機能的にも十分なものを備えている。また、利用実績も豊富だ。ログのリモート管理や一元管理などが必要となった場合、まずはrsyslogで実現できないか考えてみると良いだろう。