Konboi Note

goでfluentdを使ってlogを吐いてみる

macにfluentdをインストールする

まずは手元の環境にfluentdをインストールする (そこから?!)

公式サイトからインストールする 今回は手元のmacのversionがv10.10なのでtd-agent-v2.1.4-0.dmg をインストールした

$ which td-agent
/usr/sbin/td-agent
$ td-agent --version
td-agent 0.10.60

インストールした .dmgのバージョンと td-agent —versionの値が違うのであれ?と思ったけどChangelogを見ると正しいみたい

td-agentを起動してみる

$ td-agent
2016-10-17 12:36:35 +0900 [info]: reading config file path="/etc/td-agent/td-agent.conf"
2016-10-17 12:36:35 +0900 [info]: starting fluentd-0.10.60
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-mixin-config-placeholders' version '0.3.0'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-mixin-plaintextformatter' version '0.2.6'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-mongo' version '0.7.5'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-rewrite-tags-filter' version '1.4.1'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-s3' version '0.5.3'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-scribe' version '0.10.14'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-td' version '0.10.25'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-td-monitoring' version '0.2.0'
2016-10-17 12:36:36 +0900 [info]: gem 'fluent-plugin-webhdfs' version '0.4.1'
2016-10-17 12:36:36 +0900 [info]: gem 'fluentd' version '0.10.60'
2016-10-17 12:36:36 +0900 [info]: using configuration file: <ROOT>
  <match td.*.*>
    type tdlog
    apikey YOUR_API_KEY
    auto_create_table
    buffer_type file
    buffer_path /var/log/td-agent/buffer/td
    <secondary>
      type file
      path /var/log/td-agent/failed_records
    </secondary>
  </match>
  <match debug.**>
    type stdout
  </match>
  <source>
    type forward
  </source>
  <source>
    type http
    port 8888
  </source>
  <source>
    type debug_agent
    bind 127.0.0.1
    port 24230
  </source>
</ROOT>
2016-10-17 12:36:36 +0900 [info]: adding source type="forward"
2016-10-17 12:36:36 +0900 [info]: adding source type="http"
2016-10-17 12:36:36 +0900 [info]: adding source type="debug_agent"
2016-10-17 12:36:36 +0900 [info]: adding match pattern="td.*.*" type="tdlog"
2016-10-17 12:36:36 +0900 [info]: adding match pattern="debug.**" type="stdout"
2016-10-17 12:36:36 +0900 [info]: listening fluent socket on 0.0.0.0:24224
2016-10-17 12:36:36 +0900 [info]: listening dRuby uri="druby://127.0.0.1:24230" object="Engine"
​```
$ curl -X POST -d 'json={"json":"message"}' http://localhost:8888/debug.test

でhttp経由でlogをポストすると起動したtd-agentの標準出力に

2016-10-17 12:39:32 +0900 debug.test: {"json":"message"}

と出力される

設定ファイルは /etc/td-agent/td-agent.conf を参照しているので修正したければそのファイルを修正するか起動時にtd-agent -c <config file>で指定すればよさそう

go-fluentd-loggerを使ってみる

td-agentの準備はできたのでgoから触ってみる サンプルコードもあるのでこれを少し修正してみる

package main

import (
        "log"

        "github.com/fluent/fluent-logger-golang/fluent"
        "github.com/mattn/go-gimei"
)

type Player struct {
        ID   int
        Name string
}

func main() {
        logger, err := fluent.New(fluent.Config{FluentPort: 24224, FluentHost: "127.0.0.1"})
        if err != nil {
                log.Fatalln(err.Error())
        }
        defer logger.Close()

        tags := "debug.player"

        for i := 1; i < 100; i++ {
                p := Player{
                        ID:   i,
                        Name: gimei.NewName().Kanji(),
                }

                err := logger.Post(tags, p)
                if err != nil {
                        log.Println(err.Error())
                }
        }

        log.Println("done")
}

こんなファイルで実行すると

2016-10-17 14:53:52 +0900 debug.player: {"ID":89,"Name":"岡本 紫薫"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":90,"Name":"池上 暖芽"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":91,"Name":"三木 嘉耶"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":92,"Name":"津田 麻月"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":93,"Name":"熊谷 柚和"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":94,"Name":"角田 留治"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":95,"Name":"森川 敬輔"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":96,"Name":"中野 浩紀"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":97,"Name":"小田 征男"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":98,"Name":"岸 暖"}
2016-10-17 14:53:52 +0900 debug.player: {"ID":99,"Name":"菊池 岳人"}

こんな感じのlogを出してくれる

type Player struct {
        ID   int    `msg:"id"`
        Name string `msg:"name"`
}

msgでtagsを指定すると指定したtagsで出力してくれる

2016-10-17 15:04:38 +0900 debug.player: {"id":97,"name":"岡野 浩志"}
2016-10-17 15:04:38 +0900 debug.player: {"id":98,"name":"足立 岳治"}
2016-10-17 15:04:38 +0900 debug.player: {"id":99,"name":"小柳 遼太"}

他にも map[string]interface 形式も対応しているので

logObj := make(map[string]interface{})
logObj["player.name"] = p.Name
logObj["player.id"] = p.ID

err := logger.Post(tags, logObj)
if err != nil {
    log.Println(err.Error())
}
2016-10-17 15:26:47 +0900 debug.player: {"player.name":"新田 実喜","player.id":93}
2016-10-17 15:26:47 +0900 debug.player: {"player.name":"前田 俊之","player.id":94}
2016-10-17 15:26:47 +0900 debug.player: {"player.name":"庄司 一樹","player.id":95}
2016-10-17 15:26:47 +0900 debug.player: {"player.name":"中山 敏之","player.id":96}
2016-10-17 15:26:47 +0900 debug.player: {"player.id":97,"player.name":"緒方 靖憲"}
2016-10-17 15:26:47 +0900 debug.player: {"player.name":"島田 智啓","player.id":98}
2016-10-17 15:26:47 +0900 debug.player: {"player.name":"溝口 守理","player.id":99}

こんな感じで出力できる

まとめ

Goでも比較的簡単にfluentdでlogを出力することができる

実際に自分のプロジェクトで使うなら

fluentPrint(logTag string, v...interface{})

みたいに複数structを受け付けられるようにしてfluentPrintのなかでstructを分解し利用するようにすればいいのかなと思います。