Bug 1456984 - Instrument inspection of shortcut combination used for toolbox opening with event telemetry r?yulia draft
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Wed, 23 May 2018 13:14:25 +0100
changeset 798704 c5ca95697a0c318c5572c9dcadbe852209435e7f
parent 798691 d36cd8bdbc5c0df1d1d7a167f5fedb95c3a3648e
push id110833
push usermratcliffe@mozilla.com
push dateWed, 23 May 2018 12:17:30 +0000
reviewersyulia
bugs1456984
milestone62.0a1
Bug 1456984 - Instrument inspection of shortcut combination used for toolbox opening with event telemetry r?yulia MozReview-Commit-ID: HA6Tasq2iZu
devtools/client/framework/toolbox.js
devtools/client/shared/telemetry.js
devtools/startup/devtools-startup.js
toolkit/components/telemetry/Events.yaml
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -714,23 +714,24 @@ Toolbox.prototype = {
 
   _pingTelemetry: function() {
     this.telemetry.toolOpened("toolbox");
 
     this.telemetry.getHistogramById(HOST_HISTOGRAM).add(this._getTelemetryHostId());
 
     // Log current theme. The question we want to answer is:
     // "What proportion of users use which themes?"
-    let currentTheme = Services.prefs.getCharPref("devtools.theme");
+    const currentTheme = Services.prefs.getCharPref("devtools.theme");
     this.telemetry.keyedScalarAdd(CURRENT_THEME_SCALAR, currentTheme, 1);
 
-    this.telemetry.preparePendingEvent(
-      "devtools.main", "open", "tools", null,
-      ["entrypoint", "first_panel", "host", "splitconsole", "width"]
-    );
+    const props = ["entrypoint", "first_panel", "host", "splitconsole", "width"];
+    if (this.telemetry.hasEventProperty("devtools.main", "open", "tools", null, "shortcut")) {
+      props.push("shortcut");
+    }
+    this.telemetry.preparePendingEvent("devtools.main", "open", "tools", null, props);
     this.telemetry.addEventProperty(
       "devtools.main", "open", "tools", null, "host", this._getTelemetryHostString()
     );
   },
 
   /**
    * Create a simple object to store the state of a toolbox button. The checked state of
    * a button can be updated arbitrarily outside of the scope of the toolbar and its
--- a/devtools/client/shared/telemetry.js
+++ b/devtools/client/shared/telemetry.js
@@ -424,16 +424,50 @@ class Telemetry {
    */
   addEventProperties(category, method, object, value, pendingObject) {
     for (let [key, val] of Object.entries(pendingObject)) {
       this.addEventProperty(category, method, object, value, key, val);
     }
   }
 
   /**
+   * Check if a pending property exists.
+   *
+   * @param {String} category
+   *        The telemetry event category (a group name for events and helps to
+   *        avoid name conflicts) e.g. "devtools.main"
+   * @param {String} method
+   *        The telemetry event method (describes the type of event that
+   *        occurred e.g. "open")
+   * @param {String} object
+   *        The telemetry event object name (the name of the object the event
+   *        occurred on) e.g. "tools" or "setting"
+   * @param {String|null} value
+   *        The telemetry event value (a user defined value, providing context
+   *        for the event) e.g. "console"
+   * @param {String} propName
+   *        The property name to check for.
+   */
+  hasEventProperty(category, method, object, value, propName) {
+    const sig = `${category},${method},${object},${value}`;
+
+    if (PENDING_EVENT_PROPERTIES.has(sig)) {
+      const props = PENDING_EVENT_PROPERTIES.get(sig);
+      return Object.keys(props).includes(propName);
+    }
+
+    if (PENDING_EVENTS.has(sig)) {
+      const { expected } = PENDING_EVENTS.get(sig);
+      return expected && expected.has(propName);
+    }
+
+    return false;
+  }
+
+  /**
    * A private method that is not to be used externally. This method is used to
    * prepare a pending telemetry event for sending and then send it via
    * recordEvent().
    *
    * @param {String} category
    *        The telemetry event category (a group name for events and helps to
    *        avoid name conflicts) e.g. "devtools.main"
    * @param {String} method
--- a/devtools/startup/devtools-startup.js
+++ b/devtools/startup/devtools-startup.js
@@ -574,17 +574,17 @@ DevToolsStartup.prototype = {
     if (!Services.prefs.getBoolPref(DEVTOOLS_ENABLED_PREF)) {
       let id = key.toolId || key.id;
       this.openInstallPage("KeyShortcut", id);
     } else {
       // Record the timing at which this event started in order to compute later in
       // gDevTools.showToolbox, the complete time it takes to open the toolbox.
       // i.e. especially take `initDevTools` into account.
       let startTime = Cu.now();
-      let require = this.initDevTools("KeyShortcut");
+      let require = this.initDevTools("KeyShortcut", key);
       let { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
       gDevToolsBrowser.onKeyShortcut(window, key, startTime);
     }
   },
 
   // Create a <xul:key> DOM Element
   createKey(doc, { id, toolId, shortcut, modifiers: mod }, oncommand) {
     let k = doc.createElement("key");
@@ -602,24 +602,24 @@ DevToolsStartup.prototype = {
 
     // Bug 371900: command event is fired only if "oncommand" attribute is set.
     k.setAttribute("oncommand", ";");
     k.addEventListener("command", oncommand);
 
     return k;
   },
 
-  initDevTools: function(reason) {
+  initDevTools: function(reason, key = "") {
     // If an entry point is fired and tools are not enabled open the installation page
     if (!Services.prefs.getBoolPref(DEVTOOLS_ENABLED_PREF)) {
       this.openInstallPage(reason);
       return null;
     }
 
-    this.sendEntryPointTelemetry(reason);
+    this.sendEntryPointTelemetry(reason, key);
 
     this.initialized = true;
     let { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
     // Ensure loading main devtools module that hooks up into browser UI
     // and initialize all devtools machinery.
     require("devtools/client/framework/devtools-browser");
     return require;
   },
@@ -822,21 +822,35 @@ DevToolsStartup.prototype = {
       dump("Unable to start debugger server on " + portOrPath + ": " + e);
     }
 
     if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
       cmdLine.preventDefault = true;
     }
   },
 
-  sendEntryPointTelemetry(reason) {
+  sendEntryPointTelemetry(reason, key = "") {
     if (!reason) {
       return;
     }
 
+    if (reason === "KeyShortcut") {
+      let { modifiers, shortcut } = key;
+
+      modifiers = modifiers.replace(",", "+");
+
+      if (shortcut.startsWith("VK_")) {
+        shortcut = shortcut.substr(3);
+      }
+
+      this.telemetry.addEventProperty(
+        "devtools.main", "open", "tools", null, "shortcut", `${modifiers}+${shortcut}`
+      );
+    }
+
     this.telemetry.addEventProperty(
       "devtools.main", "open", "tools", null, "entrypoint", reason
     );
 
     if (this.recorded) {
       return;
     }
 
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -191,28 +191,29 @@ telemetry.test.second:
     description: This is a test entry for Telemetry.
     expiry_version: never
     extra_keys:
       key1: This is just a test description.
 
 devtools.main:
   open:
     objects: ["tools"]
-    bug_numbers: [1416024]
+    bug_numbers: [1416024, 1456984]
     notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
     record_in_processes: ["main"]
     description: User opens devtools toolbox.
     release_channel_collection: opt-out
     expiry_version: never
     extra_keys:
       entrypoint: How was the toolbox opened? CommandLine, ContextMenu, DeveloperToolbar, HamburgerMenu, KeyShortcut, SessionRestore or SystemMenu
       first_panel: The name of the first panel opened.
       host: "Toolbox host (positioning): bottom, side, window or other."
       splitconsole: Indicates whether the split console was open.
       width: Toolbox width rounded up to the nearest 50px.
+      shortcut: The key combination pressed. Used only in the case that entrypoint === KeyShortcut.
   close:
     objects: ["tools"]
     bug_numbers: [1453312]
     notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
     record_in_processes: ["main"]
     description: User closes devtools toolbox.
     release_channel_collection: opt-out
     expiry_version: never