新規アプリサービスのためのログ実装とサービス選定

# イベントログを落とそう
- ユーザーの行動分析
- コンバージョンのトラッキング
- クラッシュ前後の状況判定

などなど、イベントトラッキングツールを入れる用途は様々ある。
少しでも改善しようと思っているサービス運用者は当たり前のように入れるであろうツール群についてまとめます。
（独断と偏見も少し含まれるので、間違いなどあれば編集リクエストにてご指摘いただけるとありがたいです🙇 ）

# 選定 (2017年6月時点)
今話題のもので無料で使えるものを比較してみる。

## [FireBase](https://firebase.google.com/?hl=ja)
![スクリーンショット 2017-06-27 10.04.36.png](https://qiita-image-store.s3.amazonaws.com/0/31237/14f6979d-b447-da8a-f5d5-c5598b7d78ca.png)

言わずと知れたGoogle Analyticsに変わるプラットフォーム。

![スクリーンショット 2017-06-27 10.07.11.png](https://qiita-image-store.s3.amazonaws.com/0/31237/7c9796a2-4e3b-66c6-6bfc-ca3894c9f186.png)

[StreamView](https://support.google.com/firebase/answer/7229836?hl=ja)というすごい機能がある。リアルタイムに誰が何をしているかを一番細かくみることができると思う。**イベントを実施する機会が多く、それをランダムに見たいサービスなどに便利。**

### 導入
アプリケーションごとにplistが必要、Targetを分けている場合などはすこしめんどくさい。

### メリット・いい部分
- 無料で分析以外も様々な機能を利用できる
    - Push通知
    - ABテスト（RemoteConfig: 使い勝手は悪い）
    - ストレージなど
- Stream View という機能でリアルタイムにどんなユーザーが何をしているか見れる
- コホート分析、アトリビューションなど基本的な機能は揃っている
- コンバージョンをGoogle関連の広告と紐づけることができる
- [Crash Reporting](https://firebase.google.com/docs/crash/?hl=ja)がクラッシュ前後のイベントも教えてくれるのは便利

### デメリット・悪い部分
- 課金しないとイベントのプロパティが見れない
- データのCSVダウンロードなどはできない


## [Flurry](https://developer.yahoo.com/analytics/)
![スクリーンショット 2017-06-27 10.14.43.png](https://qiita-image-store.s3.amazonaws.com/0/31237/427e7aaa-04e4-1196-8c10-5cdfa04ab053.png)

Yahoo!incの提供するサービス。**とりあえず多機能**で必要な機能はだいたい揃っている、アプリの管理が会社ごとなので複数のアプリの数値を並行して見れるのが大きい。昔あったバージョンのFlurryからここ1年くらいでリニューアルしてとても見やすくなった。でも前まであったいい機能なども消えた。

### 導入
AppDelegateにconfigureを追加する程度。

### メリット・いい部分
- 無料でイベントのプロパティが見れる（多分制限ないのはFlurryだけ）
- OSやアプリを隔てなく並行してDAUやSessionを見れるので比較しやすい
- イベントログをCSVでエクスポートできる（形式は使いにくいし文字化け多い）
- イベントのプロパティで検索などできる
- イベントにユーザーを紐づけることができる（userIDなど）

### デメリット・悪い部分
- UIが複雑でできること多いのに使いにくい

## [Answers](https://answers.io/)
<img width="1258" alt="スクリーンショット 2017-06-27 10.23.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/31237/81592298-aa51-c034-e133-12b49bc57b0e.png">

Crashlyticsから派生したツール。どちらかというと**ダッシュボードとしての機能がアツい。**というかほぼそれしか用途ない。過去のデータなどはほとんど見れない。だたリアルタイムにクラッシュやDAUが変動していく様子などUI含め使いやすくはある。

<img width="1025" alt="スクリーンショット 2017-06-27 18.14.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/31237/5053de07-98a3-4e50-6ecc-73bd2d6f6ef0.png">
TV Modeというのもあるw

### 導入
iosもAndroidもツール経由で導入できる。これが便利でCrashlyticsの設定やテストアプリの配信など全部設定できる。

### メリット・いい部分
- リアルタイムな分析、クラッシュの検知には向いている
- ダッシュボードが優秀で観やすい
- リテンションでユーザーをHigh/Middle/Lowなど自動で振り分けてくれる
- イベントのパラメータも使える（CSVをDLしたり検索は無理）
- リリースバイナリごとに数値などを見れるのでverごとに伝染率などが観やすい

### デメリット・悪い部分
- 過去のデータが見れない
- データの集計タイミングがデフォルトで朝9時（24時にしてほしい）

## [MixPanel](https://mixpanel.com/)
<img width="1258" src="http://www.cherry-pick.jp/blog/images/Events_Mixpanel.png" />

**イベント数に[無料プラン](https://mixpanel.com/pricing/)だと制限**がある。
20,000件まで。20,000件はとても少ない。例えばDAU100だとしても画面ごとにScreenLogなど落としちゃうと一人5画面見ても500*30 = 15000である。こんなんすぐやん・・・

### 導入
configureするやつ。

### メリット・いい部分
- もともとwebのツールなので導入がシンプル
- リテンション・ファネル分析が使いやすい
- 複数のイベントを条件つけて集計や可視化ができる

### デメリット・悪い部分
- 無料でできることが小さい


# 実装
## iOS
落とすイベントは主に以下。

- 画面表示
- ユーザーアクション
- エラー
- コンバージョン
- その他

まずそれぞれをEnumで定義しました。

```swift

enum ActionType:String{
    case screen
    case click
    case action
    case error
    case conversion
}
```

次にログを落とす実装を共通化。**サービスによってはパラメータが使えないのでイベント名に組み込んじゃう実装**にしました。💰

```swift
// すべてのツールに落とす
class func addEventWithName(_ type:ActionType, name:String, params:[String : NSObject]?){
    Flurry.logEvent(type.rawValue+"_"+name, withParameters: params)
    ....
}
```

画面表示のログに関してはUIViewControllerのsuper classを作るのは**利用漏れ**のリスクと**責務の肥大化**が起こりそうだったので、嫌で[MOAspects](https://github.com/moaible/MOAspects/issues)を使ってメソッドを注入しました。

XXXViewControllerのXXXの部分だけ抜いてログを落とすように実装しました。

```swift
let classes: [AnyClass] = [LoginViewController.self]

for viewControllerClass in classes {
    MOAspects.hookInstanceMethod(for: viewControllerClass.self, selector:#selector(UIViewController.viewWillAppear(_:)), position:.before, range:MOAspectsHookRangeSingle){
        let classPrefixName = String(describing: viewControllerClass.self).replacingOccurrences(of: "ViewController", with: "")
        FireBaseManager.addEventWithName(.Show, name:classPrefixName)
        DDLogInfo("Show \(String(describing: viewControllerClass.self))")
    }
}

```

## Android
そもそも画面管理を

- 再利用性の高いもの: Fragment
- 他画面の依存しないもの: Activity

で実装していて、画面の表示をどう落とすか悩んだんですが、結局親クラスを作る形になりました・・・いいやり方を知りたかった。

その他の実装はiOSとほぼ同じですね。

# 運用サイクル
いまはそもそも自分一人だけのアプリチームです。指標にしているものも正確な値はサーバ側で計測しています。基本的にKPIツリーを作って、その数値を拾うために計測ツールを使っています。
前のその辺の話をしたこちらの資料をごらんください。
[一人ですすめるモバイル開発](https://www.slideshare.net/kenjhaneda/ss-66621373)

**日々の数値の監視にはAnswers,Firebase、過去のデータの集計とファネル分析にはFlurryを使っています。**

この辺はチームであれば**数値をSlackに通知する**とか**定期的にメールで飛ばす**とか必要だと思うんですが、初期のアプリサービスであれば主要KPIだけ追えばいいので、わざわざ面倒なことしないほうがいいと思います。

# まとめ
DAUやSessionはサービスによって微妙に誤差があります。集計のタイミングやSDKの実装によるので。なのでもしDAUなどをKPIにするのであればちゃんと**どのサービスの数値を指標にするのか**を考えなければいけません。

お金をかけられるのであればサーバ側で計測する指標（売り上げなど）と連携するためにfirebaseを使うことをお勧めします。BigQueryはとても便利です・・・扱いは難しいですが

施策ごとに数値があると思うので、売り上げから遠いユーザーに関するログを落としたい時、絶対パラメータが必要になると思うので、**迷ったらFlurryとAnswers**入れておけばいいんじゃないでしょうか。