Grafana/InfluxDB/Fluentdでログを可視化する

(2016-08-31)

コードはここ

InfluxDB

Golangで書かれた時系列データベース。今回使うのはv0.13。前のバージョンと結構違うので注意。

デフォルトでは無効になっている認証を有効にするために設定ファイルを編集して設置する。

$ brew install influxdb # OSX
$ influxd config > influxdb.conf
[http]
  ...
  auth-enabled = true
  ...
FROM influxdb:0.13

VOLUME /var/lib/influxdb
ADD influxdb.conf /
ENV INFLUXDB_CONFIG_PATH /influxdb.conf
$ docker run -p 8083:8083 -p 8086:8086 myinfluxdb

influxdコマンドや :8083のWebインタフェースの他に :8086HTTP APIが用意されている。

$ curl -i -XPOST http://localhost:8086/query --data-urlencode "q=CREATE USER root WITH PASSWORD 'root' WITH ALL PRIVILEGES"

$ curl -i -XPOST http://localhost:8086/query -u root:root --data-urlencode "q=CREATE DATABASE mydb"
{"results":[{}]}

# Line Protocol(https://docs.influxdata.com/influxdb/v0.13/write_protocols/line/)
$ curl -i -XPOST 'http://localhost:8086/write?db=mydb' -u root:root --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
(204 No Content)

$ curl -GET 'http://localhost:8086/query?db=mydb' -u root:root --data-urlencode 'q=SELECT * FROM "cpu_load_short"' | jq
{
  "results": [
    {
      "series": [
        {
          "name": "cpu_load_short",
          "columns": [
            "time",
            "host",
            "region",
            "value"
          ],
          "values": [
            [
              "2015-06-11T20:46:02Z",
              "server01",
              "us-west",
              0.64
            ]
          ]
        }
      ]
    }
  ]
}

fluent-plugin-influxdb

設定はこんな感じ。

<source>
  type tail
  path      /usr/src/app/test.log
  pos_file  /etc/td-agent/test.log.pos
  tag       something.log
  format    json
</source>

<match *.log>
  @type     influxdb
  host      influxdb
  port      8086
  dbname    mydb
  user      root
  password  root
</match>

5秒ごとにランダムな値valueのログを出力し続ける。

from twisted.internet import task, reactor
import logging
import json
import random

INTERVAL = 5 # sec
logging.basicConfig(filename='test.log', format='%(message)s', level=logging.INFO)

def somethingHappend():
  data = {
    "value": random.randint(0, 100),
    "event": "something"
  }
  logging.info(json.dumps(data))  

if __name__ == '__main__':
    instance = task.LoopingCall(somethingHappend)
    instance.start(INTERVAL)
    reactor.run()

Grafana

可視化ツール。データソースとしてInfluxDB、Garaphite、Elasticsearchなどが使える。

Demo

Kibana(+Elasticsearch)だと 認証するのに有償のShieldプラグインが必要だが、 こちらは最初からできて手軽。


これらのDockerイメージを作って、minikubeで立ち上げてみた。

$ kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
grafana-1386260931-lq8wh    1/1       Running   0          2m
influxdb-2543054961-yj1bd   1/1       Running   0          2m
testapp-532457622-269qo     1/1       Running   0          2m

$ curl -i -XPOST http://192.168.99.100:30005/query?db=mydb -u root:root --data-urlencode 'q=SELECT * FROM "something.log" LIMIT 1'
{"results":[{"series":[{"name":"something.log","columns":["time","event","value"],"values":[["2016-08-31T08:38:37Z","something",23]]}]}]}

http://192.168.99.100:30003

admin/adminでログインしてDataSourceにhttp://192.168.99.100:30005のInfluxDBを設定すると、 Dashboardにグラフやテーブルなどを置いて表示させることができるようになる。

grafanaのDashboard

1秒以内に複数のログが発生する場合 (2016-11-07)

時系列DBであるinfluxdbは同じタイムスタンプで複数のデータを持つことができない。 fluentdはv0.14からナノ秒でタイムスタンプを持つようになったので、これを利用することで1秒以内に発生するログも 正常に処理できるようになる。

td-agentをビルドしてfluentdのバージョンを上げる

fluent-plugin-influxdbのtime_precisionはデフォルトでs(秒)になっているが、 これをns(ナノ秒)にしただけでは、(現時点では)秒のままのタイムスタンプが送られるのでうまくいかない。 そのため、以下のようにナノ秒を取れる場合はそれを使い、そうでない場合は無視するように修正した。

nstime = time * (10 ** 9) + (defined?(Fluent::EventTime) ? time.nsec : 0)

プルリクは出した。 自分のプラグインはこんな感じで使うことができる。

td-agent-gem install specific_install && \
td-agent-gem specific_install https://github.com/sambaiz/fluent-plugin-influxdb.git