fluentdでログの取捨選択/加工をする

#前回の記事
https://qiita.com/ys_nishida/items/8b5274d8f3ec740ffa16
前回で、fluentd → Stackdriver にログを送ることが出来ました。
今回はようやく本題！fluentdのすごいところを少しだけ紹介していきます。

#fluentdでログを分解する
まずは基本中の基本。json形式にログを分解していきましょう。
###おさらい
まずはおさらい。ログはこんな形状でしたね。

```bash:/var/log/my_custom_app.log
2020-03-08 23:05:52.153 dev-machine-cent my_custome_app [info] : The transaction completed successfully.
2020-03-08 23:05:52.157 dev-machine-cent my_custome_app [warn] : The transaction completed, but some columns were invalid.
2020-03-08 23:05:52.161 dev-machine-cent my_custome_app [error] : The transaction stopped because of error.
```

###Parser Pluginを使う
まずは、ログが出てきた日付、時刻、hostnameなど、key-value形式に分解しましょう。

```bash:/etc/google-fluentd/config.d/my_custom_app.conf
<source>
  @type tail
#  format none # ← コメントアウト。実はこれは、log 1行全てをmessageというkeyに入れる、という意味。
  <parse>
    @type regexp
    expression /^(?<date>.+?)\s(?<log_time>.+?)\s(?<hostname>.+?)\s(?<appname>\w+)\s\[(?<level>\w+).*\s:\s(?<message>.*)$/
  </parse>
  path /var/log/my_custom_app.log
  pos_file /var/lib/google-fluentd/pos/my_custom_app.pos
  read_from_head true
  tag my_custom_app_log
</source>
```
```bash
sudo systemctl restart google-fluentd
sudo systemctl status google-fluentd
sudo sh ./my_logger.sh info "The transaction completed successfully."
sudo sh ./my_logger.sh warn "The transaction completed, but some columns were invalid."
sudo sh ./my_logger.sh error "The transaction stopped because of error."
```
![fBzy31Harz3MoeL1584196963_1584196991.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598801/fbd97f13-6fde-a9b9-cff1-0880573f1525.png)

json形式に分解できましたね。これがfluentdの実力を出すまず最初の一歩です。

#送るログと送らないログを選択する
たいていの製品だと、『送りたいログ』 or 『送りたくないログ』のどちらかで定義することが多いですよね。
fluentdはどちらも出来ますし、組み合わせる事だって出来ます。

##Filter Pluginを使う
『"error", "warn" は必要だが "info" は不要』という制御をかけてみましょう。

###送信するものを定義する方法
```bash:/etc/google-fluentd/config.d/my_custom_app.conf
<source>
  @type tail
  <parse>
    @type regexp
    expression /^(?<date>.+?)\s(?<log_time>.+?)\s(?<hostname>.+?)\s(?<appname>\w+)\s\[(?<level>\w+).*\s:\s(?<message>.*)$/
  </parse>
  path /var/log/my_custom_app.log
  pos_file /var/lib/google-fluentd/pos/my_custom_app.pos
  read_from_head true
  tag my_custom_app_log
</source>

<filter my_custom_app_log> # ← tagの名前で対象を選べる。wild cardも指定可能
 @type grep
  <regexp>
    key level
    pattern /^(?:warn|error)$/
  </regexp>
</filter>
```
```bash
sudo systemctl restart google-fluentd
sudo systemctl status google-fluentd
sudo sh ./my_logger.sh info "The transaction completed successfully."
sudo sh ./my_logger.sh warn "The transaction completed, but some columns were invalid."
sudo sh ./my_logger.sh error "The transaction stopped because of error."
```
![oEUOunwySndQoz21584199597_1584199643.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598801/207f4c5b-3e16-363f-3a8a-d90a0190001f.png)

画像からではわからないですが、infoのログは来ていません。

###送信しないものを定義する方法
例えば、『"warn"は基本は送るがこのメッセージは不要』みたいなケースもありますよね。
その様なケースは、組み合わせでも書けます。

```bash:/etc/google-fluentd/config.d/my_custom_app.conf
<source>
  @type tail
  <parse>
    @type regexp
    expression /^(?<date>.+?)\s(?<log_time>.+?)\s(?<hostname>.+?)\s(?<appname>\w+)\s\[(?<level>\w+).*\s:\s(?<message>.*)$/
  </parse>
  path /var/log/my_custom_app.log
  pos_file /var/lib/google-fluentd/pos/my_custom_app.pos
  read_from_head true
  tag my_custom_app_log
</source>

<filter my_custom_app_log>
 @type grep
  <regexp>
    key level
    pattern /^(?:warn|error)$/
  </regexp>
  <exclude>
    key message
    pattern /The transaction completed/
  </exclude>
</filter>
```
```bash
sudo systemctl restart google-fluentd
sudo systemctl status google-fluentd
sudo sh ./my_logger.sh info "The transaction completed successfully."
sudo sh ./my_logger.sh warn "The transaction completed, but some columns were invalid."
sudo sh ./my_logger.sh error "The transaction stopped because of error."
```

画像は張りませんが、これで
- level が "warn" or "error" のログだけが抽出されて 
- message に "The transaction completed" が含まれるログは除外される
という事が実現出来ています。
この時点で割と複雑なので、大規模なシステムや担当者がよく変わるようなシステムで運用をする時は注意が必要です。

#ログを加工する
さて、次はログを加工してみようと思います。あまりきちんとしたユースケースが思いつかないのですが、production/stagingなどの環境を入れる事にしましょう。

```bash:/etc/google-fluentd/config.d/my_custom_app.conf
<source>
  @type tail
  <parse>
    @type regexp
    expression /^(?<date>.+?)\s(?<log_time>.+?)\s(?<hostname>.+?)\s(?<appname>\w+)\s\[(?<level>\w+).*\s:\s(?<message>.*)$/
  </parse>
  path /var/log/my_custom_app.log
  pos_file /var/lib/google-fluentd/pos/my_custom_app.pos
  read_from_head true
  tag my_custom_app_log
</source>

<filter my_custom_app_log>
 @type grep
  <regexp>
    key level
    pattern /^(?:warn|error)$/
  </regexp>
  <exclude>
    key message
    pattern /The transaction completed/
  </exclude>
</filter>

<filter my_custom_app_log>
  @type record_transformer
  <record>
    env "production"
  </record>
</filter>
```

```bash
sudo systemctl restart google-fluentd
sudo systemctl status google-fluentd
sudo sh ./my_logger.sh error "The transaction stopped because of error."
```
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598801/4edc400c-2e53-9ac2-637c-35310ee0f833.png)
この通り、別の値を追加する事が出来ました。

###tagを編集する
例えば、Stackdriverに送った後、GCSに保管しておく様なログだった場合、ログのレベルに応じて保管期間などを変えたい、というケースもありますよね。そういう際は、tagの設定が非常に重要になってきます。同じbucketに送信する場合でもtag別にfolderを自動で切ってくれます。

```bash:/etc/google-fluentd/config.d/my_custom_app.conf
<source>
  @type tail
  <parse>
    @type regexp
    expression /^(?<date>.+?)\s(?<log_time>.+?)\s(?<hostname>.+?)\s(?<appname>\w+)\s\[(?<level>\w+).*\s:\s(?<message>.*)$/
  </parse>
  path /var/log/my_custom_app.log
  pos_file /var/lib/google-fluentd/pos/my_custom_app.pos
  read_from_head true
  tag my_custom_app_log
</source>

<filter my_custom_app_log>
 @type grep
  <regexp>
    key level
    pattern /^(?:warn|error)$/
  </regexp>
  <exclude>
    key message
    pattern /The transaction completed/
  </exclude>
</filter>

<match my_custom_app_log>
  @type rewrite_tag_filter
  <rule>
    key level
    pattern /warn/
    tag warn.${tag}
  </rule>
  <rule>
    key level
    pattern /error/
    tag error.${tag}
  </rule>
</match>
```
```bash
sudo systemctl restart google-fluentd
sudo systemctl status google-fluentd
sudo sh ./my_logger.sh warn "The transaction has not completed, some columns were invalid."
sudo sh ./my_logger.sh error "The transaction stopped because of error."
```
![Ql7RgauK5tMtsvu1584283503_1584283562.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598801/67493344-6579-1660-2b5e-3f526d7da64b.png)

#次回
次は複数行のログを扱います。
https://qiita.com/ys_nishida/items/f33b7dad5f49650037cc