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

Lostman

迷いがちな日々のこととかを

Hekaで始めるログ収集

ログ収集ツールといえば fluentd が有名ですが、最近 mozilla が作っている Heka はご存知でしょうか? この Heak プロジェクト、将来 fluentd の対抗馬になる予感を感じるのですが、現在ベータ版なこともあって、ドキュメントと実態が乖離しているためちょっと手が出しづらいです。 そこで、軽く使い方を紹介しようと思います。

※以下は Heka 0.3.0 について書いています。

Heka って?

Go で書かれた hekad によって構成されるログ収集・解析システムです。面白いのは statsd にインスパイアされた統計・解析用のプラグインがデフォルトで入っていることで、例えば直近1分のログのうち、エラーがある一定値を超えたら何かをする、というリアルタイム解析が簡単に出来るようになっています。

hekad のプラグインは以下の4つのタイプに分かれており、これらを組み合わせることでログ収集を行います(このあたりは fluentd とほぼ同じですね)。

  • Input: 様々なプロトコルでログを突っ込んだり、ローカルファイルの更新を検知してログを収集します
  • Decoder: input されたログを扱いやすいように構造化し、メタデータを付加します
  • Filter: ログデータを処理し、単位時間あたりのログ数などにして出力します
  • Output: ログをローカルファイルに書き出したり、別の hekad に転送したりします

ユーザーがメインで作成するのは Filter になるでしょう。そのため LUA でコンパイルし直さずにプラグインを追加できるようになっています。

上記の Input -> Decoder -> Filter -> Outpu の流れは一台で完結させることもできますが、複数の hekad の Output, Input をつなげることでを使うことで、下図のような大規模なログ収集システムを構築できます。

Architecture of Heka

from Heka Documentation

参考

インストールと起動

Ubuntu ならここから最新版のアーカイブをダウンロードしてきて、dpkg 一発です。

$ dpkg -i hekad_*.deb

起動時は -config オプションで設定ファイルを指定します。 ※man を読むとデフォルトは /etc/hekad.toml と書いてありますが、該当のファイルを置いても config の指定を求められます。

$ hekad -config config.toml

はまりどころと対策

まず公式ドキュメントが master の最新版を反映しているようで、存在しないプラグインが書いてあったり、デフォルト値が違っていたりします。

$ man hekad.plugin

でインストールされたバージョンのマニュアルを確認するのが一番確実です。

さらに、上記のマニュアルでも若干間違いがあります。ここで結構はまるので、以下の設定を参考にしてみて下さい。

また、matcher を書く際にログの type をよく使うのですが、どのプラグインがどの type になるのか書いてありません。最終的にはソースを読むのが確実です。

基本編(syslog を収集)

ローカルの syslog を読み、ログを stderr に出力するための設定です。

[debug]
type = "LogOutput"
message_matcher = "Type == 'logfile'"  # "Type =~ /.*/" でもOK
 
[syslog]
type = "LogfileInput"
logfile = "/var/log/syslog"

LogileInput の seek journal (どこまでファイルを読んだかを記録しておいて、再起動時に続きから読むための設定) を ON にしている場合、seek journal 用のファイルを作成するディレクトリの作成、及び権限設定が必要です。seek journal の詳細は LogfileInput を参照して下さい。

応用編(Apache のアクセスログ解析)

ロードバランシングされた複数台の Apache のログを収集し、それらをまとめて解析するための設定です。 Apache 側は access log を LogfileInput で収集、解析し、 TcpOutput で後段の hekad に流します。 後段では複数の Apache から送られてきたログの解析を行い、各 Virtual Host 毎のエラー率や、平均応答時間をリアルタイムで Graphite に流して描画します。

※Graphite のインストールはこちらを参考に

Apache

[access_log]
type = "LogfileInput"
logfile = "/PATH/TO/LOGFILE"
logger = "access_log"
decoders = ["access_log_decoder"]
 
[aaccess_log_decoder]
type = "LoglineDecoder"
match_regex = '^(?P<Target>\S+) (?P<PTime>\d+) (?P<RemoteIP>\S+) \S+ \S+ \[(?P<Timestamp>[^\]]+)\] "(?P<Method>[A-Z]+) (?P<Url>[^\s]+)[^"]*" (?P<StatusCode>\d+) (?P<RequestSize>\d+) "(?P<Referer>[^"]*)" "(?P<Browser>[^"]*)"'
timestamp_layout = "02/Jan/2006:15:04:05 -0700"
 
[aaccess_log_decoder.message_fields]
Type = "ApacheLogfile"
Logger = "apache"
Target = "%Target%"
Url|uri = "%Url%"
Method = "%Method%"
Status = "%StatusCode%"
RequestSize|B = "%RequestSize%"
Referer = "%Referer%"
PTime|us = "%PTime%"
Browser = "%Browser%"
 
[upstream]
type = "TcpOutput"
address = "x.x.x.x:8081"
message_matcher = "Type == 'ApacheLogfile'"

注意点

  • log のローテーションに rotatelogs を使っている場合は適切にログを収集できません。。
  • ドキュメントに載っている match_regx の 最初と最後のスラッシュ(/)は不要です。ハマります。

解析用

[TcpInput]
address = ":8081"
 
[StatAccumInput]

[access_log_filter]
type = "StatFilter"
message_matcher = 'Type == "ApacheLogfile"'
 
[access_log_filter.Metric.error]
type = "Counter"
name = "stats.apache.%Target%.%Status%"
value = "1"

[CarbonOutput]
message_matcher = "Type == 'heka.statmetric'"
address = "localhost:2003"

注意点

  • StatFilter の man には stat_accum_name というオプションがあるが、指定すると Unknown config setting: ... といって怒られます。