2016年3月12日土曜日

[CentOS6][fluentd] filter_grep で日本語を使いたい


fluentd の filter_grep を試してみました。
テスト環境は以下のとおり。
[root@node01 ~]# cat /etc/redhat-release
CentOS release 6.7 (Final)
[root@node01 ~]# cat /etc/sysconfig/i18n
LANG="ja_JP.UTF-8"

試した fluentd の設定は以下のとおり。filter_grep に日本語を使用してみました。
"致命的" という文字列を含む行だけアウトプットするようにしています。
## File input
<source>
  type tail
  format none
  path /tmp/dummy.log
  tag local.dummy
</source>

## Filter
<filter local.dummy>
  type grep
  regexp1 message 致命的
</filter>

## File output (/var/log/td-agent/td-agent.log)
<match local.**>
  type stdout
</match>

しかし、期待に反して、grep のキーワードに日本語を使用するとうまくいきません。
/var/log/td-agent/td-agent.log に以下のようなエラーがでます。
2016-03-12 12:43:59 +0900 [warn]: failed to grep events error_class=Encoding::CompatibilityError error="incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string)"

これは、異なる文字コードの文字列で正規表現処理をしたことが原因のようです。
in_tail が使用する文字コードは、"ASCII-8BIT" ですが、grepのキーワードは "UTF-8" です。
in_tail と filter_grep の相性が悪いみたい。

しかし、どうしても、grep のキーワードに 日本語を使用したかったので、 filter_grep を修正してみました。


修正内容

  • オリジナルの filter_grep を別名でコピーして修正し、新しいプラグインを作成する。
  • 新しいプラグイン名は ngrep とする。
  • 正規表現処理時の文字コードをUTF-8にする。


修正手順


オリジナルの filter_grep をコピーします。 コピー先のファイル名は filetr_ngrep.rb とします。
/etc/td-agent/plugin ディレクトリが存在しない場合は、作成しておきます。
[root@node01 ~]# cp /opt/td-agent/embedded/lib/ruby/gems/2.1.0/gems/fluentd-0.12.20/lib/fluent/plugin/filter_grep.rb /etc/td-agent/plugin/filter_ngrep.rb

filter_ngrep.rb を修正してプラグイン名を変更します。
module Fluent
  class NGrepFilter < Filter
    Fluent::Plugin.register_filter('ngrep', self)

filter_ngrep.rb を修正して in_tail で入力したデータを UTF-8 に変換します。
    def filter(tag, time, record)
      result = nil
      begin
        catch(:break_loop) do
          @regexps.each do |key, regexp|
            throw :break_loop unless ::Fluent::StringUtil.match_regexp(regexp, record[key].to_s.force_encoding('UTF-8'))
          end
          @excludes.each do |key, exclude|
            throw :break_loop if ::Fluent::StringUtil.match_regexp(exclude, record[key].to_s.force_encoding('UTF-8'))
          end


filter_ngrep の動作確認


/etc/td-agent/td-agent.conf  の設定は以下のとおり。
type で ngrep を指定します。
他の使い方は、filter_grep と同じです。
<filter local.dummy>
  type ngrep
  regexp1 message 致命的
</filter>

設定変更後、以下のようにして動作を確認しました。
/var/log/td-agent/td-agent.log に "致命的" を含む行だけ出力されたので、うまくいったようです。
[root@node01 ~]# service td-agent restart
Restarting td-agent:                                       [  OK  ]
[root@node01 ~]# echo "xxxxxxx" >> /tmp/dummy.log
[root@node01 ~]# echo "xxxxxxx" >> /tmp/dummy.log
[root@node01 ~]# echo "xxxx致命的xxxx" >> /tmp/dummy.log
[root@node01 ~]# echo "xxxx致命的xxxx" >> /tmp/dummy.log
[root@node01 ~]# echo "xxxxxxx" >> /tmp/dummy.log
[root@node01 ~]# echo "xxxxxxx" >> /tmp/dummy.log
[root@node01 ~]# tail /var/log/td-agent/td-agent.log
    type ngrep
    regexp1 message 致命的
  </filter>
  <match local.**>
    type stdout
  </match>
</ROOT>
2016-03-12 12:54:15 +0900 [info]: following tail of /tmp/dummy.log
2016-03-12 12:54:29 +0900 local.dummy: {"message":"xxxx致命的xxxx"}
2016-03-12 12:54:31 +0900 local.dummy: {"message":"xxxx致命的xxxx"}
[root@node01 plugin]#