ようへいの日々精進XP

よかろうもん

fluentd + elasticsearch + kibana + siege でお手軽に web サイトのレスポンスタイムを可視化する試み

はじめに

  • 前回の続き
  • ログを elasticsearch に投げる部分を fluentd でやってみることにする(厳密には td-agent

参考


準備

fluentd のプラグインインストール

fluent-plugin-elasticsearch

elasticsearch にログを投げる為に...

/usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-elasticsearch --no-ri --no-rdoc -V

fluent-plugin-typecast

elasticsearch に送るデータの型を変換する為に...理由は後述。

/usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-typecast --no-ri --no-rdoc -V

ちなみに一連のセットアップについてはこちらに cookbook 化した(テストはまだ!)。

正規表現を頑張る

siege が出力するログを正規化する為に慣れない正規表現頑張ってみた。尚、siege が出力するログは以下のようなフォーマット。

      Date & Time,  Trans,  Elap Time,  Data Trans,  Resp Time,  Trans Rate,  Throughput,  Concurrent,    OKAY,   Failed
2013-11-16 07:51:06,     25,       0.94,           0,       0.16,       26.60,        0.00,        4.21,      25,       0
2013-11-16 07:58:56,     25,       0.74,           0,       0.14,       33.78,        0.00,        4.74,      25,       0
2013-11-16 07:59:39,     25,       0.75,           0,       0.14,       33.33,        0.00,        4.65,      25,       0
2013-11-16 08:00:16,     25,       0.67,           0,       0.13,       37.31,        0.00,        4.69,      25,       0
2013-11-16 08:00:31,     25,       0.76,           0,       0.14,       32.89,        0.00,        4.67,      25,       0
2013-11-16 08:05:52,     25,       0.86,           0,       0.16,       29.07,        0.00,        4.60,      25,       0

デバッグに際してはこちらこちらを参考にさせて頂いて以下のようなスクリプトでデバッグを行った。

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
 
require 'time'
require 'fluent/log'
require 'fluent/config'
require 'fluent/engine'
require 'fluent/parser'
 
$log ||= Fluent::Log.new
 
# debug
log = '2013-11-17 07:18:02,     25,       0.76,           0,       0.14,       32.89,        0.00,        4.54,      25,       0'
format = /^(?<date>(\d{4})-(\d{2})-(\d{2}) (\d{2}:)(\d{2}):(\d{2})),\s{1,}(?<Trans>\d+(\.\d+)?),\s{1,}(?<Elap_Time>\d+(\.\d+)?),\s{1,}(?<Data_Trans>\d+(\.\d+)?),\s{1,}(?<Resp_Time>\d+(\.\d+)?),\s{1,}(?<Trans_Rate>\d+(\.\d+)?),\s{1,}(?<Throughput>\d+(\.\d+)?),\s{1,}(?<Concurrent>\d+(\.\d+)?),\s{1,}(?<OKAY>\d+),\s{1,}(?<Failed>\d+)$/

time_format = ''
 
parser = Fluent::TextParser::RegexpParser.new(format, 'time_format' => time_format)
puts parser.call(log)

もっと良い方法があれば教えて欲しいよー...

siege を叩くシェルを修正

たったコレだけ!

#!/bin/bash
/usr/bin/siege -b -i -r 3 -c 3 http://hoge.huga.com/ --log=/tmp/test_log

工夫して複数の Web サイトで調査出来るようになるかも。


ハマった

現状

kibana でレスポンスタイムのデータをヒストグラムで見ようとしたら以下のようなエラーとなってしまった。

ClassCastException[org.elasticsearch.index.fielddata.plain.PagedBytesIndexFieldData cannot be cast to org.elasticsearch.index.fielddata.IndexNumericFieldData]

原因

シェルスクリプトから elasticsearch に突っ込んだら type: double なっていたがfluentd(fluent-plugin-elasticsearch) 経由で elasticsearch に突っ込んだら type:string となっていた。

参考にさせて頂いているブログ記事を引用させて頂くと...

  • type apache2parser では size 等には to_i の処理が施されている(ApacheParser が利用されている)
  • format を自作した場合には RegexpParser が利用されて time 以外が文字列として処理される

とのことなので独自に format を書いた場合には全てのフィールドを string 型で処理するらしい。

対応

fluent-plugin-typecast を利用することでフィールドの型を変換してしまう。

<match siege.access>
  type typecast
  item_types Trans:integer,Elap_Time:float,Data_Trans:integer,Resp_Time:float,Trans_Rate:float,Throughput:float,Concurrent:float,OKAY:integer,Failed:integer
  tag filtered.siege.access
</match>

fluent-plugin-typecast で扱えるタイプは以下の通り。

  • integer
  • float
  • string
  • time
  • bool
  • array

fluent-plugin-typecast でパースして elasticsearch に投げると以下のようなデータ型でデータが登録されていた。

f:id:inokara:20131117095704p:plain

elasticsearch 側でデータのタイプを自動判断してくれているようだ。


最終的に...

td-agent.conf

以下のような td-agent.conf となった。

<source>
  type tail
  path /tmp/test_log
  pos_file /tmp/test.pos
  tag siege.access
  format /^(?<date>(\d{4})-(\d{2})-(\d{2}) (\d{2}:)(\d{2}):(\d{2})),\s{1,}(?<Trans>\d+(\.\d+)?),\s{1,}(?<Elap_Time>\d+(\.\d+)?),\s{1,}(?<Data_Trans>\d+(\.\d+)?),\s{1,}(?<Resp_Time>\d+(\.\d+)?),\s{1,}(?<Trans_Rate>\d+(\.\d+)?),\s{1,}(?<Throughput>\d+(\.\d+)?),\s{1,}(?<Concurrent>\d+(\.\d+)?),\s{1,}(?<OKAY>\d+),\s{1,}(?<Failed>\d+)$/
</source>

<match siege.access>
  type typecast
  item_types Trans:integer,Elap_Time:float,Data_Trans:integer,Resp_Time:float,Trans_Rate:float,Throughput:float,Concurrent:float,OKAY:integer,Failed:integer
  tag filtered.siege.access
</match>

<match filtered.siege.access>
  type elasticsearch
  include_tag_key true
  tag_key @log_name
  host 127.0.0.1
  port 9200
  logstash_format true
  flush_interval 10s
</match>

kibana で確認

ログの中から Resp_Time から Elap_Timeヒストグラムで表示させてみた。

f:id:inokara:20131117094735p:plain

もう少しデータ集めたいところ。


最後に

  • 正規表現勉強になった
  • fluentd でオレオレ format を作った時にはデータ型には注意する
  • elasticsearch でデータを突っ込んだ時にデータ型は自動判別してくれる(みたい)
  • elasticsearch-headがあると手軽に elasticsearch のデータが確認出来るのが素晴らしい!