Bug 1098374 - Telemetry: Stop all monkey patching in devtools telemetry tests r=harth
☠☠ backed out by 25013dd11944 ☠ ☠
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Sat, 29 Nov 2014 17:02:38 +0000
changeset 218142 f08caae7fcf99073508a7584beb1bfd8cd841b68
parent 218105 df3fc7cb7e8087edcd25a3afcd9540dbd8cc76ff
child 218143 33a786d187802d049ce07f339dee827428e660e4
push id27917
push usercbook@mozilla.com
push dateMon, 01 Dec 2014 11:03:31 +0000
treeherdermozilla-central@707a34b55e44 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersharth
bugs1098374
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1098374 - Telemetry: Stop all monkey patching in devtools telemetry tests r=harth
browser/devtools/canvasdebugger/canvasdebugger.js
browser/devtools/shadereditor/shadereditor.js
browser/devtools/shared/telemetry.js
browser/devtools/shared/test/browser_css_color.js
browser/devtools/shared/test/browser_observableobject.js
browser/devtools/shared/test/browser_outputparser.js
browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
browser/devtools/shared/test/browser_telemetry_button_responsive.js
browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
browser/devtools/shared/test/browser_telemetry_button_tilt.js
browser/devtools/shared/test/browser_telemetry_sidebar.js
browser/devtools/shared/test/browser_telemetry_toolbox.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js
browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
browser/devtools/shared/test/head.js
browser/devtools/storage/ui.js
browser/devtools/webaudioeditor/controller.js
browser/devtools/webaudioeditor/includes.js
browser/devtools/webide/test/head.js
browser/devtools/webide/test/test_telemetry.html
--- a/browser/devtools/canvasdebugger/canvasdebugger.js
+++ b/browser/devtools/canvasdebugger/canvasdebugger.js
@@ -10,18 +10,16 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const { CallWatcherFront } = require("devtools/server/actors/call-watcher");
 const { CanvasFront } = require("devtools/server/actors/canvas");
-const Telemetry = require("devtools/shared/telemetry");
-const telemetry = new Telemetry();
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
@@ -116,27 +114,25 @@ function shutdownCanvasDebugger() {
 /**
  * Functions handling target-related lifetime events.
  */
 let EventsHandler = {
   /**
    * Listen for events emitted by the current tab target.
    */
   initialize: function() {
-    telemetry.toolOpened("canvasdebugger");
     this._onTabNavigated = this._onTabNavigated.bind(this);
     gTarget.on("will-navigate", this._onTabNavigated);
     gTarget.on("navigate", this._onTabNavigated);
   },
 
   /**
    * Remove events emitted by the current tab target.
    */
   destroy: function() {
-    telemetry.toolClosed("canvasdebugger");
     gTarget.off("will-navigate", this._onTabNavigated);
     gTarget.off("navigate", this._onTabNavigated);
   },
 
   /**
    * Called for each location change in the debugged tab.
    */
   _onTabNavigated: function(event) {
--- a/browser/devtools/shadereditor/shadereditor.js
+++ b/browser/devtools/shadereditor/shadereditor.js
@@ -11,18 +11,16 @@ Cu.import("resource://gre/modules/Task.j
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const Editor = require("devtools/sourceeditor/editor");
-const Telemetry = require("devtools/shared/telemetry");
-const telemetry = new Telemetry();
 
 // The panel's window global is an EventEmitter firing the following events:
 const EVENTS = {
   // When new programs are received from the server.
   NEW_PROGRAM: "ShaderEditor:NewProgram",
   PROGRAMS_ADDED: "ShaderEditor:ProgramsAdded",
 
   // When the vertex and fragment sources were shown in the editor.
@@ -80,33 +78,31 @@ function shutdownShaderEditor() {
 /**
  * Functions handling target-related lifetime events.
  */
 let EventsHandler = {
   /**
    * Listen for events emitted by the current tab target.
    */
   initialize: function() {
-    telemetry.toolOpened("shadereditor");
     this._onHostChanged = this._onHostChanged.bind(this);
     this._onTabNavigated = this._onTabNavigated.bind(this);
     this._onProgramLinked = this._onProgramLinked.bind(this);
     this._onProgramsAdded = this._onProgramsAdded.bind(this);
     gToolbox.on("host-changed", this._onHostChanged);
     gTarget.on("will-navigate", this._onTabNavigated);
     gTarget.on("navigate", this._onTabNavigated);
     gFront.on("program-linked", this._onProgramLinked);
 
   },
 
   /**
    * Remove events emitted by the current tab target.
    */
   destroy: function() {
-    telemetry.toolClosed("shadereditor");
     gToolbox.off("host-changed", this._onHostChanged);
     gTarget.off("will-navigate", this._onTabNavigated);
     gTarget.off("navigate", this._onTabNavigated);
     gFront.off("program-linked", this._onProgramLinked);
   },
 
   /**
    * Handles a host change event on the parent toolbox.
--- a/browser/devtools/shared/telemetry.js
+++ b/browser/devtools/shared/telemetry.js
@@ -14,27 +14,18 @@
  * 2. Add your chart entries to browser/devtools/shared/telemetry.js
  *    (Telemetry.prototype._histograms):
  *    mytoolname: {
  *      histogram: "DEVTOOLS_MYTOOLNAME_OPENED_BOOLEAN",
  *      userHistogram: "DEVTOOLS_MYTOOLNAME_OPENED_PER_USER_FLAG",
  *      timerHistogram: "DEVTOOLS_MYTOOLNAME_TIME_ACTIVE_SECONDS"
  *    },
  *
- * 3. Include this module at the top of your tool. Use:
- *      let Telemetry = require("devtools/shared/telemetry")
- *
- * 4. Create a telemetry instance in your tool's constructor:
- *      this._telemetry = new Telemetry();
- *
- * 5. When your tool is opened call:
- *      this._telemetry.toolOpened("mytoolname");
- *
- * 6. When your tool is closed call:
- *      this._telemetry.toolClosed("mytoolname");
+ * 3. toolbox.js will automatically ping telemetry with your tools opening and
+ *    timing information.
  *
  * Note:
  * You can view telemetry stats for your local Firefox instance via
  * about:telemetry.
  *
  * You can view telemetry stats for large groups of Firefox users at
  * telemetry.mozilla.org.
  */
@@ -281,16 +272,20 @@ Telemetry.prototype = {
         lastVersionHistogramUpdated !== currentVersion) {
       latestObj[perUserHistogram] = currentVersion;
       latest = JSON.stringify(latestObj);
       Services.prefs.setCharPref(TOOLS_OPENED_PREF, latest);
       this.log(perUserHistogram, value);
     }
   },
 
+  clearToolsOpenedPref: function() {
+    Services.prefs.clearUserPref(TOOLS_OPENED_PREF);
+  },
+
   destroy: function() {
     for (let histogramId of this._timers.keys()) {
       this.stopTimer(histogramId);
     }
   }
 };
 
 XPCOMUtils.defineLazyGetter(this, "appInfo", function() {
--- a/browser/devtools/shared/test/browser_css_color.js
+++ b/browser/devtools/shared/test/browser_css_color.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
 
 let origColorUnit;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
 let {colorUtils} = devtools.require("devtools/css-color");
 
 function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
@@ -134,17 +132,17 @@ function testProcessCSSString() {
                  "background-color: transparent; " +
                  "border-top-color: rgba(0, 0, 255, 0.5);";
   let after = colorUtils.processCSSString(before);
 
   is(after, expected, "CSS string processed correctly");
 }
 
 function finishUp() {
-  Services = colorUtils = Loader = null;
+  colorUtils = null;
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function getTestData() {
   return [
     {authored: "aliceblue", name: "aliceblue", hex: "#F0F8FF", hsl: "hsl(208, 100%, 97%)", rgb: "rgb(240, 248, 255)"},
     {authored: "antiquewhite", name: "antiquewhite", hex: "#FAEBD7", hsl: "hsl(34, 78%, 91%)", rgb: "rgb(250, 235, 215)"},
--- a/browser/devtools/shared/test/browser_observableobject.js
+++ b/browser/devtools/shared/test/browser_observableobject.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
-  let tmp = {};
-  Cu.import("resource://gre/modules/devtools/Loader.jsm", tmp);
-  let ObservableObject = tmp.devtools.require("devtools/shared/observable-object");
+  let ObservableObject = devtools.require("devtools/shared/observable-object");
 
   let rawObject = {};
   let oe = new ObservableObject(rawObject);
 
   function str(o) {
     return JSON.stringify(o);
   }
 
--- a/browser/devtools/shared/test/browser_outputparser.js
+++ b/browser/devtools/shared/test/browser_outputparser.js
@@ -1,13 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
 let {OutputParser} = devtools.require("devtools/output-parser");
 
 let parser;
 let doc;
 
 function test() {
   waitForExplicitFinish();
 
@@ -91,12 +89,12 @@ function testParseNonCssHTMLAttribute() 
 
   is(target.innerHTML, expected, "Non-CSS HTML Attribute correctly parsed");
   target.innerHTML = "";
   finishUp();
 }
 
 
 function finishUp() {
-  Services = Loader = OutputParser = parser = doc = null;
+  OutputParser = parser = doc = null;
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
@@ -3,54 +3,35 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_paintflashing.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
+  startTelemetry();
   testButton("command-button-paintflashing");
 }
 
 function testButton(id) {
   info("Testing " + id);
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     info("inspector opened");
 
     let button = toolbox.doc.querySelector("#" + id);
     ok(button, "Captain, we have the button");
 
     delayedClicks(button, 4).then(function() {
-      checkResults("_PAINTFLASHING_");
+      checkResults();
     });
   }).then(null, console.error);
 }
 
 function delayedClicks(node, clicks) {
   let deferred = promise.defer();
   let clicked = 0;
 
@@ -65,61 +46,42 @@ function delayedClicks(node, clicks) {
     } else {
       setTimeout(delayedClick, TOOL_DELAY);
     }
   }, TOOL_DELAY);
 
   return deferred.promise;
 }
 
-function checkResults(histIdFocus) {
-  let result = Telemetry.prototype.telemetryInfo;
+function checkResults() {
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
-        !histId.contains(histIdFocus)) {
-      // Inspector stats are tested in
-      // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
-      // because we only open the inspector once for this test.
-      continue;
-    }
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
 
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
+  checkTelemetry("DEVTOOLS_PAINTFLASHING_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
 
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_button_responsive.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_responsive.js
@@ -3,54 +3,35 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_responsive.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
+  startTelemetry();
   testButton("command-button-responsive");
 }
 
 function testButton(id) {
   info("Testing " + id);
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     info("inspector opened");
 
     let button = toolbox.doc.querySelector("#" + id);
     ok(button, "Captain, we have the button");
 
     delayedClicks(button, 4).then(function() {
-      checkResults("_RESPONSIVE_");
+      checkResults();
     });
   }).then(null, console.error);
 }
 
 function delayedClicks(node, clicks) {
   let deferred = promise.defer();
   let clicked = 0;
 
@@ -65,61 +46,42 @@ function delayedClicks(node, clicks) {
     } else {
       setTimeout(delayedClick, TOOL_DELAY);
     }
   }, TOOL_DELAY);
 
   return deferred.promise;
 }
 
-function checkResults(histIdFocus) {
-  let result = Telemetry.prototype.telemetryInfo;
+function checkResults() {
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
-        !histId.contains(histIdFocus)) {
-      // Inspector stats are tested in
-      // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
-      // because we only open the inspector once for this test.
-      continue;
-    }
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
 
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
+  checkTelemetry("DEVTOOLS_RESPONSIVE_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
 
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
@@ -10,39 +10,21 @@ thisTestLeaksUncaughtRejectionsAndShould
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_scratchpad.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 let numScratchpads = 0;
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
+  startTelemetry();
 
   Services.ww.registerNotification(windowObserver);
   testButton("command-button-scratchpad");
 }
 
 function testButton(id) {
   info("Testing " + id);
 
@@ -71,17 +53,17 @@ function windowObserver(aSubject, aTopic
             numScratchpads++;
             win.close();
 
             info("another scratchpad was opened and closed, count is now " + numScratchpads);
 
             if (numScratchpads === 4) {
               Services.ww.unregisterNotification(windowObserver);
               info("4 scratchpads have been opened and closed, checking results");
-              checkResults("_SCRATCHPAD_");
+              checkResults();
             }
           },
         });
       }
     }, false);
   }
 }
 
@@ -100,61 +82,41 @@ function delayedClicks(node, clicks) {
     } else {
       setTimeout(delayedClick, TOOL_DELAY);
     }
   }, TOOL_DELAY);
 
   return deferred.promise;
 }
 
-function checkResults(histIdFocus) {
-  let result = Telemetry.prototype.telemetryInfo;
+function checkResults() {
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
-        !histId.contains(histIdFocus)) {
-      // Inspector stats are tested in
-      // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
-      // because we only open the inspector once for this test.
-      continue;
-    }
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
 
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
 
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_SCRATCHPAD_OPENED_BOOLEAN", [0,4,0]);
+  checkTelemetry("DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG", [0,1,0]);
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
 
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = numScratchpads = null;
+  TargetFactory = promise = numScratchpads = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_button_tilt.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_tilt.js
@@ -3,54 +3,35 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_tilt.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
+  startTelemetry();
   testButton("command-button-tilt");
 }
 
 function testButton(id) {
   info("Testing " + id);
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     info("inspector opened");
 
     let button = toolbox.doc.querySelector("#" + id);
     ok(button, "Captain, we have the button");
 
     delayedClicks(button, 4).then(function() {
-      checkResults("_TILT_");
+      checkResults();
     });
   }).then(null, console.error);
 }
 
 function delayedClicks(node, clicks) {
   let deferred = promise.defer();
   let clicked = 0;
 
@@ -65,61 +46,42 @@ function delayedClicks(node, clicks) {
     } else {
       setTimeout(delayedClick, TOOL_DELAY);
     }
   }, TOOL_DELAY);
 
   return deferred.promise;
 }
 
-function checkResults(histIdFocus) {
-  let result = Telemetry.prototype.telemetryInfo;
+function checkResults() {
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
-        !histId.contains(histIdFocus)) {
-      // Inspector stats are tested in
-      // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
-      // because we only open the inspector once for this test.
-      continue;
-    }
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
 
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
 
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_TILT_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TILT_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TILT_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
 
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_sidebar.js
+++ b/browser/devtools/shared/test/browser_telemetry_sidebar.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_sidebar.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
+  startTelemetry();
   testSidebar();
 }
 
 function testSidebar() {
   info("Testing sidebar");
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
@@ -56,60 +37,50 @@ function testSidebar() {
       } else {
         checkResults();
       }
     }, TOOL_DELAY);
   });
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.startsWith("DEVTOOLS_INSPECTOR_")) {
-      // Inspector stats are tested in browser_telemetry_toolboxtabs.js so we
-      // skip them here because we only open the inspector once for this test.
-      continue;
-    }
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+
+  checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId === "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN") {
-      is(value.length, 1, histId + " has only one entry");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
+  checkTelemetry("DEVTOOLS_LAYOUTVIEW_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,3,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
 
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolbox.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolbox.js
@@ -3,95 +3,69 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolbox.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
-  openToolboxThreeTimes();
+  startTelemetry();
+  openToolboxFourTimes();
 }
 
 let pass = 0;
-function openToolboxThreeTimes() {
+function openToolboxFourTimes() {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     info("Toolbox opened");
 
     toolbox.once("destroyed", function() {
       if (pass++ === 3) {
         checkResults();
       } else {
-        openToolboxThreeTimes();
+        openToolboxFourTimes();
       }
     });
     // We use a timeout to check the toolbox's active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, console.error);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,4,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,4,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,4,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js
@@ -3,40 +3,22 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_canvasdebugger.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
 
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 let originalPref = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled");
 Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true);
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("canvasdebugger", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -51,61 +33,39 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
   Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", originalPref);
 
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_inspector.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("inspector", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,41 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_jsdebugger.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("jsdebugger", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,41 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_SOURCES_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_JSDEBUGGER_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_jsprofiler.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("jsprofiler", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,37 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_JSPROFILER_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_netmonitor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("netmonitor", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,37 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_NETMONITOR_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_options.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("options", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,37 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_OPTIONS_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
@@ -10,40 +10,22 @@ thisTestLeaksUncaughtRejectionsAndShould
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_shadereditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
 
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 let originalPref = Services.prefs.getBoolPref("devtools.shadereditor.enabled");
 Services.prefs.setBoolPref("devtools.shadereditor.enabled", true);
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("shadereditor", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -58,61 +40,39 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_SHADEREDITOR_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
   Services.prefs.setBoolPref("devtools.shadereditor.enabled", originalPref);
 
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js
@@ -3,41 +3,22 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_storage.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 let STORAGE_PREF = "devtools.storage.enabled";
 Services.prefs.setBoolPref(STORAGE_PREF, true);
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("storage", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -52,62 +33,39 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_STORAGE_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
   Services.prefs.clearUserPref(STORAGE_PREF);
 
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_styleeditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("styleeditor", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,37 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_STYLEEDITOR_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js
@@ -3,41 +3,22 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_webaudioeditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 let originalPref = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
 Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("webaudioeditor", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -52,61 +33,38 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
   Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", originalPref);
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
@@ -3,38 +3,19 @@
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_styleeditor_webconsole.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
 
 function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
+  startTelemetry();
   openToolboxTabTwice("webconsole", false);
 }
 
 function openToolboxTabTwice(id, secondPass) {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gDevTools.showToolbox(target, id).then(function(toolbox) {
     info("Toolbox tab " + id + " opened");
@@ -49,60 +30,37 @@ function openToolboxTabTwice(id, secondP
     // We use a timeout to check the tools active time
     setTimeout(function() {
       gDevTools.closeToolbox(target);
     }, TOOL_DELAY);
   }).then(null, reportError);
 }
 
 function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+  // here.
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries");
+  checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries");
 
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-  finishUp();
-}
+  checkTelemetry("DEVTOOLS_WEBCONSOLE_OPENED_BOOLEAN", [0,2,0]);
+  checkTelemetry("DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG", [0,1,0]);
+  checkTelemetry("DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS", null, "hasentries");
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
   finishUp();
 }
 
 function finishUp() {
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
+  TargetFactory = promise = null;
 
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
--- a/browser/devtools/shared/test/head.js
+++ b/browser/devtools/shared/test/head.js
@@ -1,18 +1,22 @@
 /* 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/. */
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
+let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
 let TargetFactory = devtools.TargetFactory;
+let Telemetry = devtools.require("devtools/shared/telemetry");
+let oldCanRecord = Services.telemetry.canRecord;
 
 gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
+registerCleanupFunction(() => {
+  _stopTelemetry();
   gDevTools.testing = false;
 });
 
 const TEST_URI_ROOT = "http://example.com/browser/browser/devtools/shared/test/";
 
 /**
  * Open a new tab at a URL and call a callback on load
  */
@@ -140,8 +144,126 @@ function* createHost(type = "bottom", sr
   yield new Promise(resolve => {
     let domHelper = new DOMHelpers(iframe.contentWindow);
     iframe.setAttribute("src", src);
     domHelper.onceDOMReady(resolve);
   });
 
   return [host, iframe.contentWindow, iframe.contentDocument];
 }
+
+function reportError(error) {
+  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
+
+  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
+            error.lineNumber + "\n\nStack trace:" + stack);
+
+  if (finishUp) {
+    finishUp();
+  }
+}
+
+function startTelemetry() {
+  Services.telemetry.canRecord = true;
+}
+
+/**
+ * This method is automatically called on teardown.
+ */
+function _stopTelemetry() {
+  let telemetry = new Telemetry();
+  telemetry.clearToolsOpenedPref();
+
+  Services.telemetry.canRecord = oldCanRecord;
+
+  // Clean up telemetry histogram changes
+  for (let histId in Services.telemetry.histogramSnapshots) {
+    try {
+      let histogram = Services.telemetry.getHistogramById(histId);
+      histogram.clear();
+    } catch(e) {
+      // Histograms is not listed in histograms.json, do nothing.
+    }
+  }
+}
+
+/**
+ * Check the value of a given telemetry histogram.
+ *
+ * @param  {String} histId
+ *         Histogram id
+ * @param  {Array|Number} expected
+ *         Expected value
+ * @param  {String} checkType
+ *         "array" (default) - Check that an array matches the histogram data.
+ *         "hasentries"  - For non-enumerated linear and exponential
+ *                             histograms. This checks for at least one entry.
+ */
+function checkTelemetry(histId, expected, checkType="array") {
+  let actual = Services.telemetry.getHistogramById(histId).snapshot().counts;
+
+  switch (checkType) {
+    case "array":
+      is(JSON.stringify(actual), JSON.stringify(expected), histId + " correct.");
+    break;
+    case "hasentries":
+      let hasEntry = actual.some(num => num > 0);
+      ok(hasEntry, histId + " has at least one entry.");
+    break;
+  }
+}
+
+/**
+ * Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_")
+ * from your result checking code in telemetry tests. It logs checkTelemetry
+ * calls for all changed telemetry values.
+ *
+ * @param  {String} prefix
+ *         Optionally limits results to histogram ids starting with prefix.
+ */
+function generateTelemetryTests(prefix="") {
+  dump("=".repeat(80) + "\n");
+  for (let histId in Services.telemetry.histogramSnapshots) {
+    if (!histId.startsWith(prefix)) {
+      continue;
+    }
+
+    let snapshot = Services.telemetry.histogramSnapshots[histId];
+    let actual = snapshot.counts;
+
+    switch (snapshot.histogram_type) {
+      case Services.telemetry.HISTOGRAM_EXPONENTIAL:
+      case Services.telemetry.HISTOGRAM_LINEAR:
+        let total = 0;
+        for (let val of actual) {
+          total += val;
+        }
+
+        if (histId.endsWith("_ENUMERATED")) {
+          if (total > 0) {
+            dump("checkTelemetry(\"" + histId + "\", " + JSON.stringify(actual) + ");\n");
+          }
+          continue;
+        }
+
+        dump("checkTelemetry(\"" + histId + "\", null, \"hasentries\");\n");
+      break;
+      case Services.telemetry.HISTOGRAM_BOOLEAN:
+        actual = JSON.stringify(actual);
+
+        if (actual !== "[0,0,0]") {
+          dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n");
+        }
+      break;
+      case Services.telemetry.HISTOGRAM_FLAG:
+        actual = JSON.stringify(actual);
+
+        if (actual !== "[1,0,0]") {
+          dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n");
+        }
+      break;
+      case Services.telemetry.HISTOGRAM_COUNT:
+        dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n");
+      break;
+    }
+  }
+  dump("=".repeat(80) + "\n");
+}
--- a/browser/devtools/storage/ui.js
+++ b/browser/devtools/storage/ui.js
@@ -16,18 +16,16 @@ XPCOMUtils.defineLazyGetter(this, "Table
   () => require("devtools/shared/widgets/TableWidget").TableWidget);
 XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
   "resource://gre/modules/devtools/event-emitter.js");
 XPCOMUtils.defineLazyModuleGetter(this, "ViewHelpers",
   "resource:///modules/devtools/ViewHelpers.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
   "resource:///modules/devtools/VariablesView.jsm");
 
-let Telemetry = require("devtools/shared/telemetry");
-
 /**
  * Localization convenience methods.
  */
 let L10N = new ViewHelpers.L10N(STORAGE_STRINGS);
 
 const GENERIC_VARIABLES_VIEW_SETTINGS = {
   lazyEmpty: true,
   lazyEmptyDelay: 10, // ms
@@ -82,32 +80,28 @@ this.StorageUI = function StorageUI(fron
   this.front.listStores().then(storageTypes => {
     this.populateStorageTree(storageTypes);
   });
   this.onUpdate = this.onUpdate.bind(this);
   this.front.on("stores-update", this.onUpdate);
 
   this.handleKeypress = this.handleKeypress.bind(this);
   this._panelDoc.addEventListener("keypress", this.handleKeypress);
-
-  this._telemetry = new Telemetry();
-  this._telemetry.toolOpened("storage");
 }
 
 exports.StorageUI = StorageUI;
 
 StorageUI.prototype = {
 
   storageTypes: null,
   shouldResetColumns: true,
 
   destroy: function() {
     this.front.off("stores-update", this.onUpdate);
     this._panelDoc.removeEventListener("keypress", this.handleKeypress);
-    this._telemetry.toolClosed("storage");
   },
 
   /**
    * Empties and hides the object viewer sidebar
    */
   hideSidebar: function() {
     this.view.empty();
     this.sidebar.hidden = true;
--- a/browser/devtools/webaudioeditor/controller.js
+++ b/browser/devtools/webaudioeditor/controller.js
@@ -33,17 +33,16 @@ function shutdownWebAudioEditor() {
 /**
  * Functions handling target-related lifetime events.
  */
 let WebAudioEditorController = {
   /**
    * Listen for events emitted by the current tab target.
    */
   initialize: function() {
-    telemetry.toolOpened("webaudioeditor");
     this._onTabNavigated = this._onTabNavigated.bind(this);
     this._onThemeChange = this._onThemeChange.bind(this);
 
     gTarget.on("will-navigate", this._onTabNavigated);
     gTarget.on("navigate", this._onTabNavigated);
     gFront.on("start-context", this._onStartContext);
     gFront.on("create-node", this._onCreateNode);
     gFront.on("connect-node", this._onConnectNode);
@@ -57,17 +56,16 @@ let WebAudioEditorController = {
     // with CSS
     gDevTools.on("pref-changed", this._onThemeChange);
   },
 
   /**
    * Remove events emitted by the current tab target.
    */
   destroy: function() {
-    telemetry.toolClosed("webaudioeditor");
     gTarget.off("will-navigate", this._onTabNavigated);
     gTarget.off("navigate", this._onTabNavigated);
     gFront.off("start-context", this._onStartContext);
     gFront.off("create-node", this._onCreateNode);
     gFront.off("connect-node", this._onConnectNode);
     gFront.off("connect-param", this._onConnectParam);
     gFront.off("disconnect-node", this._onDisconnectNode);
     gFront.off("change-param", this._onChangeParam);
--- a/browser/devtools/webaudioeditor/includes.js
+++ b/browser/devtools/webaudioeditor/includes.js
@@ -14,18 +14,16 @@ const require = Cu.import("resource://gr
 
 let { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 let { EventTarget } = require("sdk/event/target");
 const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 const { Class } = require("sdk/core/heritage");
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"
 const L10N = new ViewHelpers.L10N(STRINGS_URI);
-const Telemetry = require("devtools/shared/telemetry");
-const telemetry = new Telemetry();
 
 // Override DOM promises with Promise.jsm helpers
 const { defer, all } = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
 
 /* Events fired on `window` to indicate state or actions*/
 const EVENTS = {
   // Fired when the first AudioNode has been created, signifying
   // that the AudioContext is being used and should be tracked via the editor.
--- a/browser/devtools/webide/test/head.js
+++ b/browser/devtools/webide/test/head.js
@@ -8,16 +8,19 @@ const {utils: Cu, classes: Cc, interface
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 const {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const {require} = devtools;
 const {AppProjects} = require("devtools/app-manager/app-projects");
+const Telemetry = devtools.require("devtools/shared/telemetry");
+
+let oldCanRecord = Services.telemetry.canRecord;
 
 let TEST_BASE;
 if (window.location === "chrome://browser/content/browser.xul") {
   TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/webide/test/";
 } else {
   TEST_BASE = "chrome://mochitests/content/chrome/browser/devtools/webide/test/";
 }
 
@@ -27,16 +30,24 @@ Services.prefs.setBoolPref("devtools.web
 Services.prefs.setCharPref("devtools.webide.addonsURL", TEST_BASE + "addons/simulators.json");
 Services.prefs.setCharPref("devtools.webide.simulatorAddonsURL", TEST_BASE + "addons/fxos_#SLASHED_VERSION#_simulator-#OS#.xpi");
 Services.prefs.setCharPref("devtools.webide.adbAddonURL", TEST_BASE + "addons/adbhelper-#OS#.xpi");
 Services.prefs.setCharPref("devtools.webide.adaptersAddonURL", TEST_BASE + "addons/fxdt-adapters-#OS#.xpi");
 Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "templates.json");
 
 
 SimpleTest.registerCleanupFunction(() => {
+  _stopTelemetry();
+
+  // Clean up telemetry histogram changes
+  for (let histId in Services.telemetry.histogramSnapshots) {
+    let histogram = Services.telemetry.getHistogramById(histId);
+    histogram.clear();
+  }
+
   Services.prefs.clearUserPref("devtools.webide.enabled");
   Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
   Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper");
   Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters");
 });
 
 function openWebIDE(autoInstallAddons) {
   info("opening WebIDE");
@@ -193,8 +204,115 @@ function connectToLocalRuntime(aWindow) 
   items[1].click();
   return deferred.promise;
 }
 
 function handleError(aError) {
   ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
   finish();
 }
+
+function startTelemetry() {
+  Services.telemetry.canRecord = true;
+}
+
+/**
+ * This method is automatically called on teardown.
+ */
+function _stopTelemetry() {
+  let telemetry = new Telemetry();
+  telemetry.clearToolsOpenedPref();
+
+  Services.telemetry.canRecord = oldCanRecord;
+
+  // Clean up telemetry histogram changes
+  for (let histId in Services.telemetry.histogramSnapshots) {
+    try {
+      let histogram = Services.telemetry.getHistogramById(histId);
+      histogram.clear();
+    } catch(e) {
+      // Histograms is not listed in histograms.json, do nothing.
+    }
+  }
+}
+
+/**
+ * Check the value of a given telemetry histogram.
+ *
+ * @param  {String} histId
+ *         Histogram id
+ * @param  {Array|Number} expected
+ *         Expected value
+ * @param  {String} checkType
+ *         "array" (default) - Check that an array matches the histogram data.
+ *         "hasentries"  - For non-enumerated linear and exponential
+ *                             histograms. This checks for at least one entry.
+ */
+function checkTelemetry(histId, expected, checkType="array") {
+  let actual = Services.telemetry.getHistogramById(histId).snapshot().counts;
+
+  switch (checkType) {
+    case "array":
+      is(JSON.stringify(actual), JSON.stringify(expected), histId + " correct.");
+    break;
+    case "hasentries":
+      let hasEntry = actual.some(num => num > 0);
+      ok(hasEntry, histId + " has at least one entry.");
+    break;
+  }
+}
+
+/**
+ * Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_")
+ * from your result checking code in telemetry tests. It logs checkTelemetry
+ * calls for all changed telemetry values.
+ *
+ * @param  {String} prefix
+ *         Optionally limits results to histogram ids starting with prefix.
+ */
+function generateTelemetryTests(prefix="") {
+  dump("=".repeat(80) + "\n");
+  for (let histId in Services.telemetry.histogramSnapshots) {
+    if (!histId.startsWith(prefix)) {
+      continue;
+    }
+
+    let snapshot = Services.telemetry.histogramSnapshots[histId];
+    let actual = snapshot.counts;
+
+    switch (snapshot.histogram_type) {
+      case Services.telemetry.HISTOGRAM_EXPONENTIAL:
+      case Services.telemetry.HISTOGRAM_LINEAR:
+        let total = 0;
+        for (let val of actual) {
+          total += val;
+        }
+
+        if (histId.endsWith("_ENUMERATED")) {
+          if (total > 0) {
+            dump("checkTelemetry(\"" + histId + "\", " + JSON.stringify(actual) + ");\n");
+          }
+          continue;
+        }
+
+        dump("checkTelemetry(\"" + histId + "\", null, \"hasentries\");\n");
+      break;
+      case Services.telemetry.HISTOGRAM_BOOLEAN:
+        actual = JSON.stringify(actual);
+
+        if (actual !== "[0,0,0]") {
+          dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n");
+        }
+      break;
+      case Services.telemetry.HISTOGRAM_FLAG:
+        actual = JSON.stringify(actual);
+
+        if (actual !== "[1,0,0]") {
+          dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n");
+        }
+      break;
+      case Services.telemetry.HISTOGRAM_COUNT:
+        dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n");
+      break;
+    }
+  }
+  dump("=".repeat(80) + "\n");
+}
--- a/browser/devtools/webide/test/test_telemetry.html
+++ b/browser/devtools/webide/test/test_telemetry.html
@@ -10,44 +10,24 @@
     <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
     <script type="application/javascript;version=1.8" src="head.js"></script>
     <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   </head>
 
   <body>
 
     <script type="application/javascript;version=1.8">
-      const Telemetry = require("devtools/shared/telemetry");
       const { _DeprecatedUSBRuntime, _WiFiRuntime, _SimulatorRuntime,
               _gRemoteRuntime, _gLocalRuntime, RuntimeTypes }
             = require("devtools/webide/runtimes");
 
       // Because we need to gather stats for the period of time that a tool has
       // been opened we make use of setTimeout() to create tool active times.
       const TOOL_DELAY = 200;
 
-      function patchTelemetry() {
-        Telemetry.prototype.telemetryInfo = {};
-        Telemetry.prototype._oldlog = Telemetry.prototype.log;
-        Telemetry.prototype.log = function(histogramId, value) {
-          if (histogramId) {
-            if (!this.telemetryInfo[histogramId]) {
-              this.telemetryInfo[histogramId] = [];
-            }
-            this.telemetryInfo[histogramId].push(value);
-          }
-        }
-      }
-
-      function resetTelemetry() {
-        Telemetry.prototype.log = Telemetry.prototype._oldlog;
-        delete Telemetry.prototype._oldlog;
-        delete Telemetry.prototype.telemetryInfo;
-      }
-
       function cycleWebIDE() {
         return Task.spawn(function*() {
           let win = yield openWebIDE();
           // Wait a bit, so we're open for a non-zero time
           yield waitForTime(TOOL_DELAY);
           yield closeWebIDE(win);
         });
       }
@@ -144,95 +124,58 @@
       function connectToRuntime(win, type, index) {
         return Task.spawn(function*() {
           yield startConnection(win, type, index);
           yield waitUntilConnected(win);
         });
       }
 
       function checkResults() {
-        let result = Telemetry.prototype.telemetryInfo;
-        for (let [histId, value] of Iterator(result)) {
-          if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-            ok(value.length === 1 && !!value[0],
-               "Per user value " + histId + " has a single value of true");
-          } else if (histId.endsWith("OPENED_BOOLEAN")) {
-            ok(value.length > 1, histId + " has more than one entry");
-
-            let okay = value.every(function(element) {
-              return !!element;
-            });
-
-            ok(okay, "All " + histId + " entries are true");
-          } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-            ok(value.length > 1, histId + " has more than one entry");
-
-            let okay = value.every(function(element) {
-              return element > 0;
-            });
-
-            ok(okay, "All " + histId + " entries have time > 0");
-          } else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") {
-            ok(value.length === 6, histId + " has 6 connection results");
-
-            let okay = value.every(function(element) {
-              return !!element;
-            });
-
-            ok(okay, "All " + histId + " connections succeeded");
-          } else if (histId.endsWith("CONNECTION_RESULT")) {
-            ok(value.length === 1 && !!value[0],
-               histId + " has 1 successful connection");
-          } else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS") {
-            ok(value.length === 6, histId + " has 6 connection results");
-
-            let okay = value.every(function(element) {
-              return element > 0;
-            });
-
-            ok(okay, "All " + histId + " connections have time > 0");
-          } else if (histId.endsWith("USED")) {
-            ok(value.length === 6, histId + " has 6 connection actions");
-
-            let okay = value.every(function(element) {
-              return !element;
-            });
-
-            ok(okay, "All " + histId + " actions were skipped");
-          } else {
-            ok(false, "Unexpected " + histId + " was logged");
-          }
-        }
+        // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
+        // here.
+        checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS", null, "hasentries");
+        checkTelemetry("DEVTOOLS_WEBIDE_CONNECTION_DEBUG_USED", [6,0,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_CONNECTION_PLAY_USED", [6,0,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_CONNECTION_RESULT", [0,6,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS", null, "hasentries");
+        checkTelemetry("DEVTOOLS_WEBIDE_LOCAL_CONNECTION_RESULT", [0,1,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_OPENED_BOOLEAN", [0,2,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_OPENED_PER_USER_FLAG", [0,1,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_OTHER_CONNECTION_RESULT", [0,1,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_REMOTE_CONNECTION_RESULT", [0,1,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_SIMULATOR_CONNECTION_RESULT", [0,1,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS", null, "hasentries");
+        checkTelemetry("DEVTOOLS_WEBIDE_USB_CONNECTION_RESULT", [0,1,0]);
+        checkTelemetry("DEVTOOLS_WEBIDE_WIFI_CONNECTION_RESULT", [0,1,0]);
       }
 
       window.onload = function() {
         SimpleTest.waitForExplicitFinish();
 
         let win;
 
         SimpleTest.registerCleanupFunction(() => {
           Task.spawn(function*() {
             if (win) {
               yield closeWebIDE(win);
             }
             DebuggerServer.destroy();
             yield removeAllProjects();
-            resetTelemetry();
           });
         });
 
         Task.spawn(function*() {
           Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 
           if (!DebuggerServer.initialized) {
             DebuggerServer.init(function () { return true; });
             DebuggerServer.addBrowserActors();
           }
 
-          patchTelemetry();
+          startTelemetry();
 
           // Cycle once, so we can test for multiple opens
           yield cycleWebIDE();
 
           win = yield openWebIDE();
           // Wait a bit, so we're open for a non-zero time
           yield waitForTime(TOOL_DELAY);
           addFakeRuntimes(win);