IISログをnxlog+fluentd経由で処理してElasticsearchやBigQueryに持っていった話

この記事は、[Fluentd Advent Calendar 2015 - Qiita](http://qiita.com/advent-calendar/2015/fluentd) の16日目の記事です。

IISでwebサービスを運営している環境で、nxlog+fluentdを使ってログ収集の環境を構築して半年程運用したので、その話を書こうと思います。
Windows系の記事はあまり響く方がいないのであれですが誰かの参考になれば。
※この記事を書いている最中にfluentdがwindowsに正式対応した事を知ったので、あんまり今後は需要がないかもしれません。。

##全体の構成

![BigQueryへのデータ保管.jpg](https://qiita-image-store.s3.amazonaws.com/0/40850/887a6b82-9a51-a998-4cef-4e45489c934f.jpeg "BigQueryへのデータ保管.jpg")


##なぜnxlog??

- 検証・導入の時点でwindows版fluentdが開発版で導入事例もなかった。。
- Webアプリケーションサーバに負荷をかけないツールを使う必要があった
- Cで書かれた軽量ツールで、負荷試験したところCPU使用率1%以内,Memも負荷をかけても2,30MBしか使用しなかった
- Input,Processor,Outputという3段階構成で各処理コンフィグに書くので、コンフィグも見やすい 
- buffering機構,cache機構(positionファイル)があるので、取りこぼしや重複が発生しないアーキテクチャ

fluentdで担保されている部分をWindowsで出来るツールはないかと探した結果がnxlogでした。

##fluentdの設定


###[工夫してる点]

- [multi_process_plugin](http://docs.fluentd.org/articles/in_multiprocess)を使いサービス種別毎にListenポートを分ける事でfluentdのタグを区別
※送信(nxlog)側で、タグをつけれない為
- 同一プロセスの中で、ログ種類を区別する時の為に、parser時にtagsというキーを追加
- プロセスのエラーは、td-agent.logには出ないので、プロセス毎にロギングを指定してwarn以上のログはslackに通知

###td-agent.confサンプル
```
## match tag=debug.** and dump to console
<match debug.**>
  type stdout
</match>

## live debugging agent
<source>
  type debug_agent
  bind 127.0.0.1
  port 24230
</source>

##マルチプロセス化
<source>
  type multiprocess
  
  <process>
    cmdline -c /etc/td-agent/td-agent_child1.conf --log /var/log/td-agent/td-agent1_st.log
    sleep_before_start 1s
    sleep_before_shutdown 5s
  </process>
</source>
```

###td-agent_child1.confサンプル
※エラー検知の為に、warn以上のログをプロセス毎のタグをつけてslackに通知

```
####
## タグ:
## 機能:

<source>
  type syslog
  protocol_type tcp
  port 5100
  tag xx.iislog
</source>

@include conf.d/iislog.conf

<match fluent.**>
  type record_modifier
  tag internal.message
  include_tag_key
  tag_key original_tag
</match>

<filter internal.message>
  type grep
  exclude1 message .+(Version: |Date: |Fields: |Software: ).+
</filter>

<filter internal.message>
  type grep
  regexp1 original_tag fluent.(warn|error|fatal)
</filter>

<match internal.message>
  type buffered_slack
  webhook_url [URL]
  channel [channel名]
  username fluentd
  color danger
  icon_emoji :rotating_light:
  message "Level:%s [タグ名]  Time:%s\r\nMessage:%s"
  message_keys original_tag,time,message
  flush_interval 5s
  log_level warn
</match>
```

###iislog.confサンプル

#####【アウトプット】
- BigQueryにバッチインサート用の一時ファイル(1時間単位)
※BigQueryの場合は、-はフィールド名に使えないので注意
- Elasticsearchにデイリーインデックスでエクスポート



#####【IISログならでは】
- parserで、nxlogから送ったmessage部分を各キーにparseする
- record_reformerでJST時間に変換(ElasticsearchにJSTで入れたい為)

```
<match xx.iislog.*.*>
    type parser
    add_prefix parse
    format /^(?<tags>.+)\s(?<time>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s(?<s_sitename>[^ ]*)\s(?<s_ip>[^ ]*)\s(?<cs_method>[^ ]*)\s(?<cs_uri_stem>[^ ]*)\s(?<cs_uri_query>[^ ]*)\s(?<s_port>[^ ]*)\s(?<cs_username>[^ ]*)\s(?<c_ip>[^ ]*)\s(?<User_Agent>[^ ]*)\s(?<Referer>[^ ]*)\s(?<sc_status>[^ ]*)\s(?<sc_substatus>[^ ]*)\s(?<sc_win32_status>[^ ]*)\s(?<sc_bytes>[^ ]*)\s(?<cs_bytes>[^ ]*)\s(?<time_taken>[^ ]*)\r/
    key_name message
    types sc_status:integer,time_taken:integer,sc_bytes:integer,cs_bytes:integer
</match>

<match parse.xx.iislog.*.*>
  type copy

  <store>
    type file
    path /var/log/td-agent/bq/bqfile_iis
    time_slice_format %Y%m%d
    include_time_key true
    time_format %Y-%m-%d %H:%M:%S
    format json
    buffer_type file
    buffer_path /var/log/td-agent/bq/buffer/bq_iis
    buffer_chunk_limit 2g
    buffer_queue_limit 10
    flush_interval 1h
    #flush_at_shutdown true
    compress gzip
  </store>

  <store>
    type record_reformer
    tag ${tag_prefix[1]}.elastic
    jst_time ${(time + (9 * 60 * 60)).strftime('%Y-%m-%dT%H:%M:%S%z')}
  </store>
</match>

<match parse.xx.elastic>
    type elasticsearch
    host localhost
    port 9200
    logstash_format true
    time_key jst_time
    logstash_prefix iis_log
    logstash_dateformat %Y.%m.%d
    type_name iis_log
    buffer_type file
    buffer_path /var/log/td-agent/buffer/iis_es
    buffer_chunk_limit 3m
    buffer_queue_limit 1000
    flush_interval 3s
    flush_at_shutdown true
    retry_wait 1s
    retry_limit 17
</match>
```

##nxlogの設定

収集対象の、WindowsServerでの設定
インストールは、[こちら](http://nxlog.org/products/nxlog-community-edition/download) からmsiパッケージをダウンロードしてインストールするだけ！

```configのディレクトリ構成
C:/Program Files (x86)/nxlog/nxlog.conf #conf.d配下をinclude
                            /con.d/xxx.conf
                                  /xxx2.conf
```

###nxlog.confサンプル
うちだと、ログやバッファはD:¥nxlogに作成するので、その場合は、最初にディレクトリを作成しておく必要がある。

```
#define ROOT C:\Program Files\nxlog
define ROOT C:/Program Files (x86)/nxlog
define DATA_DIR D:/nxlog
define DST_SRV [fluentdが稼働しているサーバのIP]

#Global Directive

#バイナリ置き場
Moduledir %ROOT%/modules

#最終読込位置記憶の為のconfigcache.datの保存場所
CacheDir %DATA_DIR%/data

#ログ出力先
LogFile %DATA_DIR%/data/logs/nxlog.log

#ログレベル: CRITICAL, ERROR, WARNING, INFO, DEBUG 
LogLevel ERROR

#何に使っているかは不明
SpoolDir %DATA_DIR%/data

#<Extension _syslog>
<Extension syslog>
    Module      xm_syslog
</Extension>

<Extension charconv>
    Module      xm_charconv
    AutodetectCharsets utf-8, euc-jp, utf-16, utf-32, iso8859-2
</Extension>

# エスケープ注意
include %ROOT%\conf\conf.d\\*.conf
```

#####xxx.confサンプル(includeされるファイル)

#####サンプル内にコメントでIIS用のTIPSを。

```
<Input in_fgac>
    Module im_file
    File "D:\[IISログディレクトリ]\ex*.log"
    SavePos TRUE
    ReadFromLast TRUE
    InputType LineBased
    # shift_jisに設定しないとIISログの日本語が文字化けするので注意
    Exec convert_fields("shift_jis", "utf-8");
</Input>

<Processor fg_t>
    Module pm_transformer
    OutputFormat syslog_bsd
    # IISログの中身を全て$Message(syslogのmessageキーに詰め込む)
      Exec $Message=(": "+$raw_event);
      # fluentd側ではsyslogで受信するので、タグが統一されるため、予めタグをnxlogで仕込んでおく場合は下記
      # Exec $Message=(": [タグ名] "+$raw_event);
</Processor>

<Processor fg_b>
    Module pm_buffer
    # 500MB
    MaxSize 512000
    Type disk
    Directory %DATA_DIR%\data\buffer
    WarnLimit 1024
</Processor>

<Output out_fgac>
    Module      om_tcp
    Host        %DST_SRV%
    # fluentdでListenしているポート
    Port        5100
</Output>

<Route fgac_r>
    Path        in_fgac => fg_t => fg_b => out_fgac
</Route>
```

この構成で、nxlog,fluentdにはこれまで障害が出たことはなく、4000万/dayくらいのログを捌いているのでIISログを扱うには中々いい組み合わせかなと。
もう少しユースケースが出てきたら、Windows版fluentdも試してみたいとは思っています！タグを収集側でつけれると格段に楽になるので！