Athenaを使ってS3のログを検索できるようにし運用コストを改善する

# Intro
こんにちは。
サービスを運営していく中でサービス障害時，ユーザーの行動分析をしたい時などにログはとても効果を発揮します。一方で構造化されていないログや,気軽に確認出来る環境がない場合,苦行が始まります。

担当したプロジェクトで,S3に溜め込んだアクセスログやアプリログを気軽に確認できるようにAthenaを利用する機会があったため, その時の知見をまとめておきます。参考になるかは分からないけど。

今回は, nginxのアクセスログを題材に紹介しています。

# Athenaとは
[Athena](https://aws.amazon.com/jp/blogs/news/amazon-athena-interactive-sql-queries-for-data-in-amazon-s3/
) は, AWSのサービスの一つで, S3のデータをクエリを用いて検索をすることができます。
サーバーレスなため, インフラストラクチャーの構築など不要なので簡単に始められます。

BIGQueryと同じで, 固定費ではなくスキャンしたデータ量によって従量課金されます。

# Athenaを使えば人類はどう幸せになれるのか。

通常, アクセスログやアプリケーションログを見る時は, サーバーにログインして, コマンドで抽出して, 加工して...と地味に労力が必要でした。

簡単な抽出ならまだしも, 複数の条件, 複雑な条件でデータを抽出したいといったときに, 一気に難易度が高くなりますよね.

また, 企画者などがログを分析したい時も,エンジニアを通さないと現状ではログを見ることが難しそうです。

それを,GUI上などでクエリを書いて簡単に欲しいログデータを検索出来るソリューションです。

企画者は企画や分析に集中でき, エンジニアは開発に集中出来るとハッピーです。

# ログ収集の構成
アクセスログの収集の構成はざっくりこんな感じでやってました。
各アプリケーションサーバーから集約サーバーへ集約し, Athenaが扱えるようにS3にJSON形式で保存してます。

![Athena (1).png](https://qiita-image-store.s3.amazonaws.com/0/38342/e1b7872e-efaf-efaf-ec90-d13cf8123408.png)

# 導入のためにやった工夫

* アクセスログのフォーマットの変更
* S3バケットのディレクトリ設計
* Athenaを利用する

## アクセスログをLTSV形式にする
標準のログフォーマットでもパース処理をかけば問題ありませんが, アクセスログを解析しやすく, 項目追加など変化に強い形になるため, 将来的なこと考え LTSV形式に変えました。

ラベリングは ltsv.org が推奨しているラベル名あるようです.

- [LTSV FAQ - LTSV って何? どういうところが良いの?](http://d.hatena.ne.jp/naoya/20130209/1360381374)
- [ltsv.org](http://ltsv.org/)


```ltsv
time:2017-12-27T18:29:59+09:00<TAB>host:127.0.0.1<TAB>referer:http://www.example.com/<TAB>... 
```

## S3へ保存するログファイルをJSONにする
Amazon Athena では, CSV, TSV, JSON などの幅広いデータ形式がサポートされます。

nginxのログフォーマットをLTSVにしていると, fluentd などで簡単にJSONへ変換できます。


```json
{"time":"2018-01-11T14:26:01+09:00","host":"127.0.0.1","method":"GET","reqsize":"3434","uri":"/","query":"-","status":"200","size":"19658"}
```

- [Amazon Athena ではどのデータ形式がサポートされていますか?](https://aws.amazon.com/jp/athena/faqs/)


## S3バケットのディレクトリ設計。HIVE形式にする
Athenaはスキャンした容量により, 従量課金される課金方式を取っています。

特定のログを検索する際に全ファイルを探索してしまうと, その分課金されてしまうので, パーティションで区切って, 必要なデータしかスキャンしないようにします。

HIVEフォーマットで格納することにより, Athenaが自動的にパーティションとして認識してくれるため, この形式を採用しました。

- [Amazon Athenaのパーティションを理解する #reinvent](https://dev.classmethod.jp/cloud/aws/athena-partition-reinvent/)

```s3の保存先
# dt=yyyy-MM-ddがミソ
aws s3 ls s3://elasticmapreduce/samples/hive-ads/tables/impressions/

    PRE dt=2009-04-12-13-00/
    PRE dt=2009-04-12-13-05/
    PRE dt=2009-04-12-13-10/
    PRE dt=2009-04-12-13-15/
```

## パーティションを認識させる

上述したディレクトリでログを保存していれば, **MSCK REPAIR TABLE** コマンドを叩くことによってパーティションを認識することができます。

新たなディレクトリが追加されても自動でパーティションを認識をしないようなので, 何らかの手段でコマンドを叩く必要があります（cronやS3イベントとかが思い浮かびます)

```
# パーティションを認識させる
MSCK REPAIR TABLE nginx_access

---
Partitions not in metastore:	nginx_access:dt=2018-01-12	nginx_access:dt=2018-01-13	nginx_access:dt=2018-01-14
Repair: Added partition to metastore nginx_access:dt=2018-01-12
Repair: Added partition to metastore nginx_access:dt=2018-01-13
Repair: Added partition to metastore nginx_access:dt=2018-01-14
```

# Athenaを利用してみる
## CASE1：googlebotを調べたいのでログを調べてほしい！
どこかのマーケターが言いそうですね。

```
SELECT count(ua) as ua_count FROM nginx_access WHERE dt > '2018-01-10' and dt <= '2018-01-11'  and ua = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0' group by ua
```
<img width="1025" alt="スクリーンショット 2018-01-12 15.07.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/38342/7aa4ccb6-ba39-297e-8792-566daaa32adf.png">

## CASE2：とあるユーザーの行動を調べてほしい！
どこかの企画者が言いそうですね。

```
SELECT time, uri, referer, user_id FROM nginx_access WHERE dt > '2018-01-10' and dt <= '2018-01-11' and user_id = '1' LIMIT 10
```
<img width="1024" alt="スクリーンショット 2018-01-12 14.41.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/38342/ef073d12-a261-a2a0-8bc9-900f2bcf325d.png">
 
# 最後に。
これに限らず, アプリケーションが活用しやすい形でログを活用することで, 楽しいログライフが待っているかもしれません. 運用コストはだいぶ減るはずです.

また, RedashをはじめとしたBIツールと連携しログを可視化することでデータへの意識が醸成されることを期待。

あでゅ