読者です 読者をやめる 読者になる 読者になる

tweeeetyのぶろぐ的めも

アウトプットが少なかったダメな自分をアウトプット<br>\(^o^)/

td-agent(fluentd)でtagを色々してみたメモ①-タグにhotname追加、タグを書き換え、タグを入れ替えとかとか

はじめに

td-agent使って最初はすこし四苦八苦しましたが、
だいぶ期間も経ってしまって忘れそうなのでタグの扱いについて自分なりにメモっておこーっていう記事です
 
また、各プラグインの詳細は開発者の方のサイトや参考になるサイトも多数あるので
ピンポイントで使った感じだけをそのままメモ

補足

そんなにテクニカルでも有用でもないカモですがこちらにメモまとめをメモっておきました →td-agent(fluentd)を本番サ―ビスで小さく使ってみたメモ-まとめ

ながれ

こんな感じで書いてみました

  1. 前提とか(fluent-plugin-parser)
    • 前提
    • 関連ディレクトリ構成
    • イメージ
  2. タグにhostname追加したい(fluent-plugin-config-expander)
  3. タグをjsonの中身でパターンマッチングして書き換えたい(fluent-plugin-rewrite)
  4. タグを入れ替えたりjsonの中身を追加・削除したい(fluent-plugin-record-reformer)

前提とか

前提
  • td-agentインストール済み
  • apacheaccessログをtailする(フォーマットデフォルトではない)
  • 送信側は受信側にそのまんま送る(後述のイメージ参照)
  • 受信側ではまず最初にfluent-plugin-parserでパース処理する
関連ディレクトリ構成

outファイルで出力するログやpos、シンボリックリンクを格納するフォルダの構成はこんな感じにしてます

  • 送信・受信側共通
# tree /var/log/td-agent
/var/log/td-agent
|-- project
|   |-- aclog
|   |-- buffer
|   |-- out
|   |-- pos
|   `-- slink
`-- unmatched
イメージ

いくつかプラグインを使いますが基本的な流れはこれで行います。
理由はサービスに導入した際に、webサーバに負荷をかけたくなかったのでパース処理も受信側で行いたかったというのが大きな理由です!

送信側はaccessログをそのまんまの形で送信

受信側は来たログをparserでパースしてemit~からのいろいろやる

  • 図だとこんな感じ

f:id:tweeeety:20140521222128p:plain

準備

fluent-plugin-parserだけは最初にインストールしておきます

/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-parser

ってことで早速

2. タグにhostname追加(fluent-plugin-config-expander)

タグにhostnameを追加します

インストール
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-config-expander
config例
  • 送信側
<source>
  type config_expander
  <config>
    type tail
    format none
    time_format %d/%b/%Y:%T %z
    path /var/log/td-agent/project/slink/access.log
    pos_file /var/log/td-agent/project/pos/access.pos
    #rotate_wait 30
    tag raw.project.apache.access.__HOSTNAME__
  </config>
</source>
  • 受信側
<match raw.project.apache.**>
  type parser
  remove_prefix raw
  add_prefix parsed
  format /^(?<host>[^ ]+) [^ ]+ [^ ]+ \[(?<time>[^\]]+)\] "(?<method>[^ ]+) (?<path>[^ ]+) [^ ]+" (?<code>[^ ]+) .+ ".+" "(?<ua>.+)" (?<response_time>[^ ]+)$/
  time_format %d/%b/%Y:%T %z
  key_name message
</match>

<match parsed.**>
  type file
  path /var/log/td-agent/project/out/config_expander
</match>
結果
# pwd
/var/log/td-agent/project/out

# ls
config_expander.20140521.b4f9e8fdb97104ed8

# cat config_expander.20140521.b4f9e8fdb97104ed8
2014-05-21T22:32:46+09:00       parsed.project.apache.access.hoge.co.jp {"host":"172.21.44.55","method":"GET","path":"/mypage","code":"200","ua":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.33 Safari/535.11","response_time":"187047"}
参考

Fluentd界で知らない人がいないtagomoris先生のブログとgithub
http://d.hatena.ne.jp/tagomoris/20120802/1343891922
https://github.com/tagomoris/fluent-plugin-config-expander/blob/master/README.md

3. タグをjsonの中身でパターンマッチングして書き換えたい(fluent-plugin-rewrite)

タイトルのとおりですが、jsonの中身のkey:valueでパターンマッチングしてtagを書き換えます

インストール
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-rewrite
config例
  • 送信側
<source>
  type config_expander
  <config>
    type tail
    format none
    time_format %d/%b/%Y:%T %z
    path /var/log/td-agent/project/slink/access.log
    pos_file /var/log/td-agent/project/pos/access.pos
    #rotate_wait 30
    tag raw.project.apache.access.__HOSTNAME__
  </config>
</source>
  • 受信側
<match raw.project.apache.**>
  type parser
  remove_prefix raw
  add_prefix parsed
  format /^(?<host>[^ ]+) [^ ]+ [^ ]+ \[(?<time>[^\]]+)\] "(?<method>[^ ]+) (?<path>[^ ]+) [^ ]+" (?<code>[^ ]+) .+ ".+" "(?<ua>.+)" (?<response_time>[^ ]+)$/
  time_format %d/%b/%Y:%T %z
  key_name message
</match>

<match parsed.**>
  type rewrite

  remove_prefix parsed.project.apache.access
  add_prefix filtered

  <rule>
    key     path
    pattern ^\/(?:img|js|css|static)
    ignore  true
  </rule>
  <rule>
    key     path
    pattern ^\/$
    replace /top
  </rule>
  <rule>
    key     path
    pattern ^\/\?.+$
    replace /top
  </rule>
  <rule>
    key     response_time
    pattern ^$
    ignore  true
  </rule>
  #<rule>
  #  key     code
  #  pattern ^(?!200)\d+$
  #  ignore  true
  #</rule>
  <rule>
    key     method
    pattern ^(?!GET).+$
    ignore  true
  </rule>
  <rule>
    key     path
    pattern ^/([^\/]+).*$
    append_to_tag true
    fallback other
  </rule>
</match>

<match  filtered.**>
  type file
  path /var/log/td-agent/project/out/rewrite
</match>
  • ruleについてちょっと説明
    emitされたタグがruleにもとづいてパースされます。今回のルールはこんな感じ
  • pathがimg|js|css|staticから始まったら破棄
  • pathが/のみのものは/topに書き換え
  • pathが/?のものは/topに書き換え(/?id=1とか)
  • response_timeがカラのものは破棄(なんで入れたか忘れました)
  • methodがGETじゃなかったら破棄
  • それ以外のパスはmatchした部分を追加して再emit

ruby正規表現についてはこちらが参考になります
http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fregexp.html
http://www.rubylife.jp/regexp/lookahead/index2.html

結果
# pwd
/var/log/td-agent/project/out

# ls
rewrite.20140521.b4f9e994237d856d4

# cat rewrite.20140521.b4f9e994237d856d4
2014-05-21T23:18:37+09:00       filtered.hoge.co.jp.mypage      {"host":"172.21.44.55","method":"GET","path":"/mypage","code":"200","ua":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.33 Safari/535.11","response_time":"203840"}
2014-05-21T23:18:40+09:00       filtered.hoge.co.jp.campaign    {"host":"172.21.44.55","method":"GET","path":"/campaign/index/loginbonus_5","code":"200","ua":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.33 Safari/535.11","response_time":"41679"}

matchしたpath(mypateとかcampaign)とかが追加されました

参考

作者さんのgithubが一番説明わかりやすいと思います https://github.com/kentaro/fluent-plugin-rewrite

4. タグを入れ替えたりjsonの中身を追加・削除したい

add_prefix、remove_prefixだけではやれることが限られているので、いっそのことタグをもっと自由にガチャガチャやりたい!!
そんな場合に使います。
また、jsonの中身をシェイプアップして送ったりもできます。

インストール
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-record-reformer
config例
  • 送信側
<source>
  type config_expander
  <config>
    type tail
    format none
    time_format %d/%b/%Y:%T %z
    path /var/log/td-agent/project/slink/access.log
    pos_file /var/log/td-agent/project/pos/access.pos
    #rotate_wait 30
    tag raw.project.apache.access.__HOSTNAME__
  </config>
</source>
  • 受信側
<match raw.project.apache.**>
  type parser
  remove_prefix raw
  add_prefix parsed
  format /^(?<host>[^ ]+) [^ ]+ [^ ]+ \[(?<time>[^\]]+)\] "(?<method>[^ ]+) (?<path>[^ ]+) [^ ]+" (?<code>[^ ]+) .+ ".+" "(?<ua>.+)" (?<response_time>[^ ]+)$/
  time_format %d/%b/%Y:%T %z
  key_name message
</match>

<match parsed.**>
  type record_reformer
  remove_keys ua,response_time
  tag reformed.${tag_parts[4]}.${tag_parts[1]}
  
  hostname ${hostname}
  from ${tag_parts[4]}
</match>

<match  filtered.**>
  type file
  path /var/log/td-agent/project/out/rewrite
</match>
  • 今回の例をちょっと説明
    perserによってemitされたタグがこんな感じだとします
[tag ]parsed.project.apache.access.hoge.co.jp
[json]{"host":"172.21.44.55","method":"GET","path":"/mypage","code":"200","ua":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.33 Safari/535.11","response_time":"267804"}

これに対してrecord_reformerでこんなことをしてます

  • remove_keys…jsonからremove_keys(ua、response_time)を除外
  • tag…emitするタグをreformed.projectにする
  • hostname…jsonにhostnameという項目を追加
  • from…jsonにfromという項目を追加
結果
# pwd
/var/log/td-agent/project/out

# ls
reformed.20140522.b4f9f37ed8ae1fb4b

# cat reformed.20140522.b4f9f37ed8ae1fb4b
2014-05-22T11:20:19+09:00  reformed.hoge.project  {"host":"172.21.44.55","method":"GET","path":"/mypage","code":"200","hostname":"logsv.co.jp","from":"hoge"}
2014-05-22T11:20:20+09:00  reformed.hoge.project  {"host":"172.21.44.55","method":"GET","path":"/js/mypage/main.js","code":"200","hostname":"logsv.co.jp","from":"hoge"}

こんな感じでタグもjsonの中身も自由に追加・削除できました

補足

以前と少し仕様が変わったようでoutput_tagを使用すると起動時にこんなエラーがでます あたらしくtagというOption Parametersが追加されるのでそちらを使いましょう

2014-05-22 10:54:29 +0900 [warn]: out_record_reformer: `output_tag` is deprecated. Use `tag` option instead.

まとめ

ってことで、下記を使うことでかなり自由にできます!

  • fluent-plugin-parser
  • fluent-plugin-config-expander
  • fluent-plugin-rewrite
  • fluent-plugin-record-reformer

authorのかたがたに感謝します!