Bug 1174937 - Beta 43 experiment, share of searches recorded in Places that resolve to major web SRPs. r=mak,felipe
authorJared Hirsch <6a68@mozilla.com>
Mon, 16 Nov 2015 13:20:32 -0200
changeset 59 ce604a104dc263b7aac7a044b42d9fe6ede879ab
parent 58 5ab27d87508be702d4653449a04b1bcce9fe60d8
child 60 f8c39c544bf3ae3f5ea0d99c09d0ea80c1e159df
push id45
push userfelipc@gmail.com
push dateMon, 16 Nov 2015 15:21:18 +0000
reviewersmak, felipe
bugs1174937
Bug 1174937 - Beta 43 experiment, share of searches recorded in Places that resolve to major web SRPs. r=mak,felipe
experiments/serp-fraction-counts/DOCUMENTATION
experiments/serp-fraction-counts/code/bootstrap.js
experiments/serp-fraction-counts/code/install.rdf
experiments/serp-fraction-counts/experiment.xpi
experiments/serp-fraction-counts/filter.js
experiments/serp-fraction-counts/manifest.json
new file mode 100644
--- /dev/null
+++ b/experiments/serp-fraction-counts/DOCUMENTATION
@@ -0,0 +1,105 @@
+# DOCUMENTATION
+
+This file documents the data collected, basic facts about the server and
+client, including a complete list of endpoints, and their meaning.
+
+
+## Client data sending overview
+
+`navigator.sendBeacon` is used to send data without competing with the user's
+web browsing.
+
+Individual data points are POSTed to the endpoints specified below. The packet
+contains just a single number in the request body, as usual with statsd data.
+Each endpoint fully specifies the 'key' to which the request body corresponds
+as a numeric 'value'.
+
+
+## Server overview
+
+Our statsd-over-http server is located at:
+  https://statsd-bridge.services.mozilla.com
+
+The server source code is located at:
+  https://github.com/mozilla-services/datadog-bridge
+
+The server's SSL cert is pinned in Firefox, along with all other
+services.mozilla.com subdomains. See the 'services.mozilla.com' entry in the
+'entries' object in this file:
+  https://mxr.mozilla.org/mozilla-central/source/security/manager/tools/PreloadedHPKPins.json
+
+Our server forwards the data points to datadog, a dashboarding service that
+has been legally approved for non-personally identifiable data visualization.
+It's used already by other services / cloud ops projects.
+
+We use two statsd data types in our reporting: gauges and counters. The data
+type is specified as part of the URL, by putting either /gauge/ or /count/ in
+the URL itself (see below for examples).
+
+* Gauges are decimal numbers representing arbitrary data values.
+* Counters are whole number counts of events. We use them mostly for
+  incrementing error event counters when something fails.
+
+Learn more: http://docs.datadoghq.com/guides/dogstatsd/#metrics
+
+
+## The complete set of endpoints
+
+Every count has the number '1' as its request body, because the counts are
+experiment-global counters of events, like errors.
+
+### Search Provider Visit Percentage
+
+The percentage of visits corresponding to a given search provider is sent to
+one of these endpoints:
+
+  https://statsd-bridge.services.mozilla.com/gauge/beta42.1174937.serpfraction.google
+  https://statsd-bridge.services.mozilla.com/gauge/beta42.1174937.serpfraction.yahoo
+  https://statsd-bridge.services.mozilla.com/gauge/beta42.1174937.serpfraction.bing
+
+The request body is the percentage given as an integer.
+
+
+### Search Provider Visit Percentage Errors
+
+If we encounter errors in calculating a given provider's percentage of visits,
+then we increment error counters corresponding to the failed provider:
+
+  https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.google.error
+  https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.yahoo.error
+  https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.bing.error
+
+
+### Total Number of Visits in History
+
+The total number of visits is sent to this endpoint:
+
+  https://statsd-bridge.services.mozilla.com/gauge/beta42.1174937.serpfraction.total
+
+The request body contains the integer total number of visits.
+
+
+### Participating Firefox Instance Counter
+
+Each FF instance, when it sends data, also increments a count of the total number
+of FF clients that have contributed data to the experiment, by pinging this endpoint:
+
+  https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.clients
+
+
+### Startup Error Counter
+
+If an error occurs during startup, the error message is discarded, as it might
+well contain information that could identify the user, and this error counter is incremented:
+
+  https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.error.startup
+
+
+### Experiment Error Counter
+
+If an error occurs while the experiment is running, again, the error message is
+discarded, and this error counter is incremented:
+
+  https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.error.experiment
+
+
new file mode 100644
--- /dev/null
+++ b/experiments/serp-fraction-counts/code/bootstrap.js
@@ -0,0 +1,259 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
+                                  "resource:///modules/experiments/Experiments.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+                                  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
+                                  "resource:///modules/RecentWindow.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+                                  "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+                                  "resource://gre/modules/Task.jsm");
+/*
+ * experiment code
+ */
+
+// if true, abort any remaining DB requests or beacons
+let isExiting = false;
+
+// see https://bugzil.la/1174937#c16 for explanation of query optimizations
+const query = `SELECT SUM(visit_count) AS count, url FROM moz_places
+               WHERE rev_host BETWEEN :reversed AND :reversed || X'FFFF'
+               AND url LIKE :fuzzy`;
+
+// we need a window pointer to get access to navigator.sendBeacon, but we have
+// to wait until a DOMWindow is ready (see runExperiment below)
+let window;
+
+const countUrl = "https://statsd-bridge.services.mozilla.com/count/beta42.1174937.serpfraction.";
+const gaugeUrl = "https://statsd-bridge.services.mozilla.com/gauge/beta42.1174937.serpfraction.";
+
+const searchProviders = {
+  google: {
+    reversed: "moc.elgoog.",
+    fuzzy: "%google.com/search?q%"
+  },
+  yahoo: {
+    reversed: "moc.oohay.",
+    fuzzy: "%search.yahoo.com/yhs/search?p%"
+  },
+  bing: {
+    reversed: "moc.gnib.",
+    fuzzy: "%bing.com/search?q%"
+  }
+};
+
+const counts = {
+  google: null,
+  yahoo: null,
+  bing: null,
+  total: null
+};
+
+function saveCount(providerName, results) {
+  // query returns undefined if there are no visits to the specified page; replace with 0
+  let count = results && results[0] && results[0].getResultByName("count") || 0;
+  counts[providerName] = count;
+}
+
+// returns an integer percentage or null if either operand was invalid.
+// division operator handles type coercion for us
+function percentage(a, b) {
+  const result = a / b;
+  const p = isFinite(result) ? Math.round(result * 100) : null;
+  return p;
+}
+
+function sendBeacon(url, data) {
+  if (isExiting) {
+    return;
+  }
+  try {
+    window.navigator.sendBeacon(url, data);
+  } catch (ex) {
+    // something's wrong, give up
+    uninstallExperiment();
+  }
+}
+
+// For each search provider, either send the result percentage for that
+// provider, or increment an error counter. Also send down the total history
+// size for that user, and increment the total count of responding clients.
+function send(data) {
+  ["google", "yahoo", "bing"].forEach(function(provider) {
+    let pct = percentage(counts[provider], counts.total);
+    if (pct !== null) {
+      sendBeacon(gaugeUrl + provider, pct);
+    } else {
+      sendBeacon(countUrl + provider + ".error", 1);
+    }
+  });
+  sendBeacon(gaugeUrl + "total", counts.total);
+  sendBeacon(countUrl + "clients", 1);
+}
+
+// If an error occurs when querying or connecting to the DB, just give up:
+// fire a beacon with the name of the failed step (in dot-delimited statsd
+// format) and uninstallExperiment the experiment.
+function onError(step) {
+  sendBeacon(countUrl + "error." + step, 1)
+  uninstallExperiment();
+}
+
+function onDomWindowReady(domWindow) {
+  try {
+    if (domWindow && domWindow.removeEventListener) {
+      domWindow.removeEventListener("load", onDomWindowReady);
+    }
+    // if this is not a browser window, bail
+    let windowType = domWindow && domWindow.document &&
+                     domWindow.document.documentElement.getAttribute("windowtype");
+    if (windowType !== "navigator:browser") {
+      return;
+    }
+    // assign the addon-global window variable, so that
+    // "window.navigator.sendBeacon" will be defined
+    window = domWindow;
+    _runExperiment()
+      .catch(() => {
+      onError("experiment");
+    })
+      .then(() => {
+      uninstallExperiment();
+    });
+  } catch(ex) {}
+}
+
+
+
+// annoying, but unavoidable, window management code
+// implements nsIWindowMediatorListener
+// pulled from MDN: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIWindowMediator#addListener()
+let windowListener = {
+  onOpenWindow: function(aWindow) {
+    try {
+     Services.wm.removeListener(windowListener);
+     let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+                             getInterface(Ci.nsIDOMWindow);
+      if (domWindow && domWindow.document && domWindow.document.readyState === "complete") {
+        onDomWindowReady(domWindow);
+      } else {
+        domWindow.addEventListener("load", onDomWindowReady);
+      }
+    } catch (ex) {
+    }
+  },
+  onCloseWindow: function(aWindow) {},
+  onWindowTitleChange: function(aWindow, aTitle) {}
+};
+
+function runExperiment() {
+  try {
+    if (isExiting) {
+      return;
+    }
+    // get a window, or wait till a window is opened, then continue.
+    let win = RecentWindow.getMostRecentBrowserWindow();
+    if (win) {
+      windowListener.onOpenWindow(win);
+    } else {
+      Services.wm.addListener(windowListener);
+    }
+  } catch(ex) {}
+}
+
+let getTotalCount = Task.async(function* (db) {
+  if (isExiting) {
+    return;
+  }
+  return yield db.execute(`
+    SELECT COUNT(*) AS count FROM moz_historyvisits;
+  `);
+});
+
+let _runExperiment = Task.async(function* () {
+  let db = yield PlacesUtils.promiseDBConnection();
+  for (let providerName in searchProviders) {
+    if (isExiting) {
+      break;
+    }
+    try {
+      let result = yield db.execute(query, searchProviders[providerName]);
+      saveCount(providerName, result);
+    } catch (ex) {
+    }
+  }
+  let totalResult = yield getTotalCount(db);
+  saveCount("total", totalResult);
+  send(counts);
+  uninstallExperiment();
+});
+
+function exit() {
+  // abort any future Places queries or beacons
+  isExiting = true;
+}
+
+/*
+ *  bootstrapped addon code
+ */
+
+// the startup method is apparently called twice, so you have to guard against
+// that manually via gStarted. See
+//   https://bugzilla.mozilla.org/show_bug.cgi?id=1174937#c44
+// and see also, for example,
+//   http://hg.mozilla.org/webtools/telemetry-experiment-server/file/ (cont'd)
+//   59365ce5cabe/experiments/flash-protectedmode-beta/code/bootstrap.js#l12
+var gStarted = false;
+
+function startup() {
+  if (gStarted) {
+    return;
+  }
+  gStarted = true;
+
+  // Make sure the user has telemetry and Firefox Health Report enabled.
+  // If not, immediately uninstall the experiment.
+  const prefBranch = Cc["@mozilla.org/preferences-service;1"]
+                   .getService(Ci.nsIPrefService)
+                   .getBranch("");
+  const isTelexEnabled = prefBranch.getPrefType("toolkit.telemetry.enabled") ?
+                    prefBranch.getBoolPref("toolkit.telemetry.enabled") : false;
+  const isFHREnabled = prefBranch.getPrefType("datareporting.healthreport.service.enabled") ?
+                    prefBranch.getBoolPref("datareporting.healthreport.service.enabled") : false;
+  const isFHRUploadEnabled = prefBranch.getPrefType("datareporting.healthreport.uploadEnabled") ?
+                    prefBranch.getBoolPref("datareporting.healthreport.uploadEnabled") : false;
+
+  if (!isTelexEnabled || !isFHREnabled || !isFHRUploadEnabled) {
+    uninstallExperiment();
+    return;
+  }
+
+  try {
+    runExperiment();
+  } catch(ex) {
+    onError("startup");
+  }
+}
+
+function shutdown() {
+  exit();
+}
+
+function uninstallExperiment() {
+  exit();
+  Experiments.instance().disableExperiment("FROM_API");
+}
+
+function install() {
+}
+
+function uninstall() {
+}
new file mode 100644
--- /dev/null
+++ b/experiments/serp-fraction-counts/code/install.rdf
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>serp-fraction-counts-beta42@experiments.mozilla.org</em:id>
+    <em:version>1.0.0</em:version>
+    <em:type>128</em:type>
+    <em:bootstrap>true</em:bootstrap>
+    <em:unpack>false</em:unpack>
+
+    <!-- Firefox -->
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>42.0</em:minVersion>
+        <em:maxVersion>45.*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <!-- Front End MetaData -->
+    <em:name>Search result pages in history</em:name>
+    <em:description>An experiment that measures what percentage of history visits are search result pages. The search percentage data is anonymous.</em:description>
+    <em:aboutURL>https://bugzilla.mozilla.org/show_bug.cgi?id=1174937</em:aboutURL>
+  </Description>
+</RDF>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0c5d9ed666e80ac49e1cb34fc0d29bc9ed44cd3e
GIT binary patch
literal 7667
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
new file mode 100644
--- /dev/null
+++ b/experiments/serp-fraction-counts/filter.js
@@ -0,0 +1,3 @@
+function filter(c) {
+  return c.telemetryEnvironment.settings.telemetryEnabled;
+}
new file mode 100644
--- /dev/null
+++ b/experiments/serp-fraction-counts/manifest.json
@@ -0,0 +1,18 @@
+{
+  "publish": true,
+  "priority": 5,
+  "name": "Search result pages in history",
+  "description": "An experiment that measures what percentage of history visits are search result pages. The search percentage data is anonymous.",
+  "info": "https://bugzilla.mozilla.org/show_bug.cgi?id=1174937",
+  "manifest": {
+    "id": "serp-fraction-counts-beta42@experiments.mozilla.org",
+    "startTime": 1447113600,
+    "endTime": 1448323200,
+    "maxActiveSeconds": 86400,
+    "appName": ["Firefox"],
+    "channel": ["beta"],
+    "minBuildID": "20151109145326",
+    "sample": 0.1
+  }
+}
+