More Related Content Similar to アプリを成長させるためのログ取りとログ解析に必要なこと (20) More from Takao Sumitomo (20) アプリを成長させるためのログ取りとログ解析に必要なこと5. DroidKaigi 2018 @cattaka_net5
触ったことあるもの
プログラム
Java, C++, Ruby,
PHP, Python
データベース
Oracle, Sqlite3,
PostgreSQL,
MySQL, Realm
プラットフォーム等
Android,
Linux(Debian),
MFC, Struts
設計
UML, Excel方眼紙
16. DroidKaigi 2018 @cattaka_net16
1 2 3 4 5
0.00%
10.00%
20.00%
30.00%
40.00%
50.00%
60.00%
70.00%
80.00%
90.00%
100.00%
応募にたどり着くまでのファネル
それまでの過程は?
●
1: インストール
●
2: ユーザー登録
●
3: 探す操作をする
●
4: 詳細画面を開く
●
5: 応募を押す
こんな感じ??
42. DroidKaigi 2018 @cattaka_net42
イベントログの例
ユーザー
識別子
画面名
イベント名
イベントの
追加属性画面の
追加属性
time user_id screen screen_params event event_params
1234 ListActivity click {"view_id": "title", "item_id": 432}
1234 DetailActivity {"item_id": 432} press_back
1234 ListActivity click {"view_id": "title", "item_id": 234}
1234 DetailActivity {"item_id": 234} click {"view_id": "apply"}
1234 DetailActivity {"item_id": 234} cvt_apply {"item_id": 234}
2018/02/09
12:30
2018/02/09
12:31
2018/02/09
12:32
2018/02/09
12:33
2018/02/09
12:33
44. DroidKaigi 2018 @cattaka_net44
Viewの操作 vs コンバージョン
●
どっちが解析しやすいか?
– Viewの操作として記録
– コンバージョンとして記録
●
ツールに寄る
– FAはコンバージョンが扱いやすい
time user_id screen screen_params event event_params
1234 DetailActivity {"item_id": 234} click {"view_id": "apply"}
1234 DetailActivity {"item_id": 234} cvt_apply {"item_id": 234}
2018/02/09
12:33
2018/02/09
12:33
※:2つはユーザーの操作としては同じ
重要な指標だから両方取る
46. DroidKaigi 2018 @cattaka_net46
イベントログの実装:Treasure Data
Map<String, Object> event = new HashMap<>();
event.put("user_id", userId);
event.put("activity", activityName);
event.put("fragment", fragmentName);
event.put("event", "select_cotent");
event.put("item_id", itemId);
event.put("name", name);
TreasureData.sharedInstance()
.addEvent("event_log", event);
ユーザー識別子
画面
イベント名
追加属性
全部自分でやる!
47. DroidKaigi 2018 @cattaka_net47
イベントログの実装:Firebase Analytics
Bundle bundle = new Bundle();
bundle.putLong
(FirebaseAnalytics.Param.ITEM_ID, itemId);
bundle.putString
(FirebaseAnalytics.Param.ITEM_NAME, name);
bundle.putString
(FirebaseAnalytics.Param.CONTENT_TYPE, "image");
mFirebaseAnalytics.logEvent(
FirebaseAnalytics.Event.SELECT_CONTENT, bundle);
↓追加属性
↑イベント名
画面やユーザー識別子はやってくれる
53. DroidKaigi 2018 @cattaka_net53
スクリーンログの例
画面名
画面の
追加属性
次の画面の
追加属性
次の画面名 滞在時間
time user_id screen screen_params next_screen next_params duration
1234 ListActivity DetailActivity {"item_id": 432} 46231
1234 DetailActivity {"item_id": 432} ListActivity 82323
1234 ListActivity DetailActivity {"item_id": 234} 53341
1234 DetailActivity {"item_id": 234} 72652
2018/02/09
12:30
2018/02/09
12:31
2018/02/09
12:32
2018/02/09
12:33
56. DroidKaigi 2018 @cattaka_net56
スクリーンログの実装:Treasure Data
Map<String, Object> event = new HashMap<>();
event.put("user_id", userId);
event.put("activity", activity);
event.put("fragment", fragment);
event.put("params", params);
event.put("next_activity", nextActivityName);
event.put("next_fragment", nextFragmentName);
event.put("next_params", nextParams);
event.put("duration", duration);
TreasureData.sharedInstance()
.addEvent("screen_log", event);
全部自分でやる!
ユーザー識別子
画面
次の画面
滞在時間
※:onStopなどに書く
62. DroidKaigi 2018 @cattaka_net62
FAでベタで書いたときの問題
Bundle bundle = new Bundle();
bundle.putLong ( "item_id", id );
bundle.putString( "item_name", name );
mFirebaseAnalytics.logEvent("select_content", bundle);
イベント名を定数にしたい
属性名を定数にしたい
値を型安全にしたい
これらは一度コードに散らばると回収不可能になる
65. DroidKaigi 2018 @cattaka_net65
属性をGenericsで型のある定数にする
public class Param<T> {
public static final Param<Long> ITEM_ID =
new Param<>("item_id", BaseBundle::putLong);
public static final Param<String> ITEM_NAME =
new Param<>("item_name", BaseBundle::putString);
String key;
IFunc<T> putFunc;
private Param(String key, IFunc<T> putFunc) {
this.key = key;
this.putFunc = putFunc;
}
public interface IFunc<V> {
void put(Bundle dest, String key, V value);
}
}
66. DroidKaigi 2018 @cattaka_net66
Generics芸を使った便利メソッドを作る
public <V1, V2> void logEvent(
Event event,
Param<V1> k1,
V1 v1,
Param<V2> k2,
V2 v2
) {
Bundle bundle = new Bundle();
k1.putFunc.put(bundle, k1.key, v1);
k2.putFunc.put(bundle, k2.key, v2);
mFirebaseAnalytics.logEvent(event.key, bundle);
}
// イベント名
// 属性1
// 値1
// 属性2
// 値2
型安全が守られる
型安全が守られる
70. DroidKaigi 2018 @cattaka_net70
属性の個数は可変だよね?
●
諦めて属性の
数ごとに作る
●
RxJavaも
似たことをしてる
●
0〜7個あれば
実用十分
public <V1, V2, V3, V4, V5, V6>
void logEvent(
Event event,
Param<V1> k1, V1 v1,
Param<V2> k2, V2 v2,
Param<V3> k3, V3 v3,
Param<V4> k4, V4 v4,
Param<V5> k5, V5 v5,
Param<V6> k6, V6 v6
) {
Bundle bundle = new Bundle();
k1.putFunc.put(bundle, k1.key, v1);
k2.putFunc.put(bundle, k2.key, v2);
k3.putFunc.put(bundle, k3.key, v3);
k4.putFunc.put(bundle, k4.key, v4);
k5.putFunc.put(bundle, k5.key, v5);
k6.putFunc.put(bundle, k6.key, v6);
mFirebaseAnalytics.logEvent(event.key,
bundle);
}
例:属性が6つの場合
76. DroidKaigi 2018 @cattaka_net76
個別にコードを入れるのは大変
●
対策1
– BaseActivity や BaseFragment を作る
●
onStart や onStop などに仕込む
public class BaseFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
MyTracker.getInstance().logScreen(this);
}
}
↑画面用のメソッド
88. DroidKaigi 2018 @cattaka_net88
Firebase Analyticsへの気遣い
●
Firebase Analyticsには地味に制約が多い
– 制約を守らないとエラーになってログが送れない
●
主な制約
– イベント名の種類は500個まで
– イベント名と属性名
●
英数とアンダースコアで40文字まで
– 属性の値は100文字まで
– 同一属性名の型は揃えること