jenkins-bot has submitted this change and it was merged.

Change subject: Implement event logging for Sessions.
......................................................................


Implement event logging for Sessions.

Change-Id: I615811eb08699f6c2435d8eed8288d01661f432e
---
M wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
A wikipedia/src/main/java/org/wikipedia/analytics/SessionFunnel.java
M wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
3 files changed, 204 insertions(+), 0 deletions(-)

Approvals:
  BearND: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java 
b/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
index 40fb4ff..3182e04 100644
--- a/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
+++ b/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
@@ -21,6 +21,7 @@
 import org.acra.annotation.ReportsCrashes;
 import org.mediawiki.api.json.Api;
 import org.wikipedia.analytics.FunnelManager;
+import org.wikipedia.analytics.SessionFunnel;
 import org.wikipedia.bridge.StyleLoader;
 import org.wikipedia.data.ContentPersister;
 import org.wikipedia.data.DBOpenHelper;
@@ -112,6 +113,11 @@
 
     private List<String> languageMruList;
 
+    private SessionFunnel sessionFunnel;
+    public SessionFunnel getSessionFunnel() {
+        return sessionFunnel;
+    }
+
     /**
      * Singleton instance of WikipediaApp
      */
@@ -154,6 +160,8 @@
 
         PrefKeys.initPreferenceKeys(resources);
 
+        sessionFunnel = new SessionFunnel(this);
+
         // Enable debugging on the webview
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
             WebView.setWebContentsDebuggingEnabled(true);
diff --git a/wikipedia/src/main/java/org/wikipedia/analytics/SessionFunnel.java 
b/wikipedia/src/main/java/org/wikipedia/analytics/SessionFunnel.java
new file mode 100644
index 0000000..942363b
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/analytics/SessionFunnel.java
@@ -0,0 +1,190 @@
+package org.wikipedia.analytics;
+
+import org.wikipedia.WikipediaApp;
+import org.wikipedia.history.HistoryEntry;
+import org.json.JSONException;
+import org.json.JSONObject;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.text.format.DateUtils;
+import java.util.Date;
+import java.util.UUID;
+
+public class SessionFunnel extends Funnel {
+    private static final String SCHEMA_NAME = "MobileWikiAppSessions";
+    private static final int REVISION = 9742902;
+    private WikipediaApp app;
+
+    /**
+     * Definition of a "session timeout", as agreed upon by the Apps and 
Analytics teams.
+     * (currently 30 minutes)
+     */
+    private static final int SESSION_TIMEOUT_SECONDS = 30 * 60;
+
+    private static final String APP_ID_PREF_NAME = 
"ANALYTICS_APP_ID_FOR_SESSIONS";
+    private static final String SESSION_TIMESTAMP_PREF_NAME = 
"SESSION_TIMESTAMP_PREF";
+    private static final String SESSION_PAGES_SEARCH_PREF_NAME = 
"SESSION_PAGES_SEARCH_PREF";
+    private static final String SESSION_PAGES_RANDOM_PREF_NAME = 
"SESSION_PAGES_RANDOM_PREF";
+    private static final String SESSION_PAGES_LANGLINK_PREF_NAME = 
"SESSION_PAGES_LANGLINK_PREF";
+    private static final String SESSION_PAGES_INTERNAL_PREF_NAME = 
"SESSION_PAGES_INTERNAL_PREF";
+    private static final String SESSION_PAGES_EXTERNAL_PREF_NAME = 
"SESSION_PAGES_EXTERNAL_PREF";
+    private static final String SESSION_PAGES_HISTORY_PREF_NAME = 
"SESSION_PAGES_HISTORY_PREF";
+    private static final String SESSION_PAGES_SAVED_PREF_NAME = 
"SESSION_PAGES_SAVED_PREF";
+    private static final String SESSION_PAGES_BACK_PREF_NAME = 
"SESSION_PAGES_BACK_PREF";
+
+    private final String appInstallSessionsID;
+    private Date lastEventTime;
+    private int pagesFromSearch;
+    private int pagesFromRandom;
+    private int pagesFromLanglink;
+    private int pagesFromInternal;
+    private int pagesFromExternal;
+    private int pagesFromHistory;
+    private int pagesFromSaved;
+    private int pagesFromBack;
+
+    public SessionFunnel(WikipediaApp app) {
+        super(app, SCHEMA_NAME, REVISION);
+        this.app = app;
+
+        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(app);
+
+        lastEventTime = new Date(prefs.getLong(SESSION_TIMESTAMP_PREF_NAME, 
0));
+        pagesFromSearch = prefs.getInt(SESSION_PAGES_SEARCH_PREF_NAME, 0);
+        pagesFromRandom = prefs.getInt(SESSION_PAGES_RANDOM_PREF_NAME, 0);
+        pagesFromLanglink = prefs.getInt(SESSION_PAGES_LANGLINK_PREF_NAME, 0);
+        pagesFromInternal = prefs.getInt(SESSION_PAGES_INTERNAL_PREF_NAME, 0);
+        pagesFromExternal = prefs.getInt(SESSION_PAGES_EXTERNAL_PREF_NAME, 0);
+        pagesFromHistory = prefs.getInt(SESSION_PAGES_HISTORY_PREF_NAME, 0);
+        pagesFromSaved = prefs.getInt(SESSION_PAGES_SAVED_PREF_NAME, 0);
+        pagesFromBack = prefs.getInt(SESSION_PAGES_BACK_PREF_NAME, 0);
+
+        if (prefs.contains(APP_ID_PREF_NAME)) {
+            appInstallSessionsID = prefs.getString(APP_ID_PREF_NAME, null);
+        } else {
+            appInstallSessionsID = UUID.randomUUID().toString();
+            prefs.edit().putString(APP_ID_PREF_NAME, 
appInstallSessionsID).commit();
+        }
+
+        touchSession();
+    }
+
+    /**
+     * Save the state of the current session. To be called when the main 
Activity is stopped,
+     * so that we don't have to save its state every time a single parameter 
is modified.
+     */
+    public void persistSession() {
+        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(app);
+        prefs.edit().putLong(SESSION_TIMESTAMP_PREF_NAME, 
lastEventTime.getTime())
+             .putInt(SESSION_PAGES_SEARCH_PREF_NAME, pagesFromSearch)
+             .putInt(SESSION_PAGES_RANDOM_PREF_NAME, pagesFromRandom)
+             .putInt(SESSION_PAGES_LANGLINK_PREF_NAME, pagesFromLanglink)
+             .putInt(SESSION_PAGES_INTERNAL_PREF_NAME, pagesFromInternal)
+             .putInt(SESSION_PAGES_EXTERNAL_PREF_NAME, pagesFromExternal)
+             .putInt(SESSION_PAGES_HISTORY_PREF_NAME, pagesFromHistory)
+             .putInt(SESSION_PAGES_SAVED_PREF_NAME, pagesFromSaved)
+             .putInt(SESSION_PAGES_BACK_PREF_NAME, pagesFromBack).commit();
+    }
+
+    protected void log(Object... params) {
+        final int defaultSampleRate = 10;
+
+        //get our sampling rate from remote config
+        int sampleRate = 
app.getRemoteConfig().getConfig().optInt("eventLogSampleRate", 
defaultSampleRate);
+
+        //take the last 4 hex digits of the uuid, modulo the sampling 
coefficient.
+        //if the result is 0, then we're one of the Chosen.
+        final int uuidSubstrLen = 4;
+        final int hexBase = 16;
+        boolean chosen = 
Integer.parseInt(appInstallSessionsID.substring(appInstallSessionsID.length() - 
uuidSubstrLen), hexBase) % sampleRate == 0;
+
+        if (chosen) {
+            log(getApp().getPrimarySite(), params);
+        }
+    }
+
+    @Override
+    protected JSONObject preprocessData(JSONObject eventData) {
+        try {
+            eventData.put("appInstallID", appInstallSessionsID);
+        } catch (JSONException e) {
+            // This isn't happening
+            throw new RuntimeException(e);
+        }
+        return eventData;
+    }
+
+    /**
+     * Update the timestamp for the current session. If the last-updated time 
is older than the defined
+     * timeout period, then consider the current session as over, and send the 
event!
+     */
+    private void touchSession() {
+        Date now = new Date();
+        if (lastEventTime.getTime() == 0) {
+            //the app was just launched, and there's no record of a previous 
session,
+            //so send a session "start" event
+            log(
+                    "action", "start"
+            );
+        } else if (now.getTime() - lastEventTime.getTime() > 
(SESSION_TIMEOUT_SECONDS * DateUtils.SECOND_IN_MILLIS)) {
+
+            // the last session is over!
+            log(
+                    "action", "end",
+                    "pagesViewedFromSearch", pagesFromSearch,
+                    "pagesViewedFromRandom", pagesFromRandom,
+                    "pagesViewedFromLanglink", pagesFromLanglink,
+                    "pagesViewedFromExternal", pagesFromExternal,
+                    "pagesViewedFromHistory", pagesFromHistory,
+                    "pagesViewedFromSaved", pagesFromSaved,
+                    "totalPagesViewed", pagesFromSearch + pagesFromRandom + 
pagesFromLanglink + pagesFromInternal
+                                        + pagesFromExternal + pagesFromHistory 
+ pagesFromSaved,
+                    "backPressed", pagesFromBack
+            );
+
+            // start a new session by clearing everything.
+            // We don't actually need to send another "start" event, since the 
"end" event that we just sent
+            // implies that a new session is starting.
+            pagesFromSearch = 0;
+            pagesFromRandom = 0;
+            pagesFromLanglink = 0;
+            pagesFromInternal = 0;
+            pagesFromExternal = 0;
+            pagesFromHistory = 0;
+            pagesFromSaved = 0;
+            pagesFromBack = 0;
+        }
+        lastEventTime.setTime(now.getTime());
+    }
+
+    public void pageViewed(HistoryEntry entry) {
+        touchSession();
+        switch (entry.getSource()) {
+            case HistoryEntry.SOURCE_SEARCH:
+                pagesFromSearch++;
+                break;
+            case HistoryEntry.SOURCE_RANDOM:
+                pagesFromRandom++;
+                break;
+            case HistoryEntry.SOURCE_LANGUAGE_LINK:
+                pagesFromLanglink++;
+                break;
+            case HistoryEntry.SOURCE_EXTERNAL_LINK:
+                pagesFromExternal++;
+                break;
+            case HistoryEntry.SOURCE_HISTORY:
+                pagesFromHistory++;
+                break;
+            case HistoryEntry.SOURCE_SAVED_PAGE:
+                pagesFromSaved++;
+                break;
+            default:
+                pagesFromInternal++;
+        }
+    }
+
+    public void backPressed() {
+        touchSession();
+        pagesFromBack++;
+    }
+}
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
index f7c6f70..827694d 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
@@ -217,6 +217,8 @@
             return;
         }
 
+        app.getSessionFunnel().pageViewed(entry);
+
         // animate the new fragment into place
         // then hide the previous fragment.
         final PageViewFragment prevFragment = curPageFragment;
@@ -371,6 +373,8 @@
                         fragmentPager.setOnAnimationListener(null);
                     }
                 });
+
+                app.getSessionFunnel().backPressed();
 
                 fragmentPager.setCurrentItem(fragmentPager.getCurrentItem() - 
1);
                 curPageFragment = 
fragmentAdapter.getFragmentAt(fragmentPager.getCurrentItem());
@@ -544,6 +548,8 @@
             themeChooser.dismiss();
         }
 
+        app.getSessionFunnel().persistSession();
+
         super.onStop();
         bus.unregister(this);
         bus = null;

-- 
To view, visit https://gerrit.wikimedia.org/r/158236
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I615811eb08699f6c2435d8eed8288d01661f432e
Gerrit-PatchSet: 6
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <[email protected]>
Gerrit-Reviewer: BearND <[email protected]>
Gerrit-Reviewer: Brion VIBBER <[email protected]>
Gerrit-Reviewer: Yuvipanda <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to