Bug 1451734 - Track application panel events with EventTelemetry draft
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 30 May 2018 14:35:48 +0200
changeset 801444 505b00c8463226f3ec42d0e2bd009915f6974f55
parent 801443 e015a5b31c5f277de0deca209822b4a23dd03aea
push id111673
push userjdescottes@mozilla.com
push dateWed, 30 May 2018 14:01:03 +0000
bugs1451734
milestone62.0a1
Bug 1451734 - Track application panel events with EventTelemetry Events tracked here: - service worker debug (with duration) - service worker start - service worker unregister - click on aboutdebugging link at bottom of sw list - click on any help link MozReview-Commit-ID: J2RYy6iHXw9
devtools/client/application/initializer.js
devtools/client/application/src/components/Worker.js
devtools/client/application/src/components/WorkerList.js
devtools/client/application/src/components/WorkerListEmpty.js
devtools/client/framework/devtools-browser.js
toolkit/components/telemetry/Events.yaml
--- a/devtools/client/application/initializer.js
+++ b/devtools/client/application/initializer.js
@@ -12,16 +12,17 @@ const require = BrowserLoader({
 
 const { createFactory } = require("devtools/client/shared/vendor/react");
 const { render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
 const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
 const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
 
 const { configureStore } = require("./src/create-store");
 const actions = require("./src/actions/index");
+const Telemetry = require("devtools/client/shared/telemetry");
 
 const App = createFactory(require("./src/components/App"));
 
 /**
  * Global Application object in this panel. This object is expected by panel.js and is
  * called to start the UI for the panel.
  */
 window.Application = {
@@ -31,17 +32,23 @@ window.Application = {
 
     this.mount = document.querySelector("#mount");
     this.toolbox = toolbox;
     this.client = toolbox.target.client;
 
     this.store = configureStore();
     this.actions = bindActionCreators(actions, this.store.dispatch);
 
+    let telemetry = new Telemetry();
+
     const serviceContainer = {
+      recordEvent(action, extras) {
+        telemetry.recordEvent("devtools.main", action, "application", null, extras);
+      },
+
       openWebLink(url) {
         let win = toolbox.doc.defaultView.top;
         win.openWebLinkIn(url, "tab", { relatedToCurrent: true });
       },
 
       openTrustedLink(url) {
         let win = toolbox.doc.defaultView.top;
         win.openTrustedLinkIn(url, "tab", { relatedToCurrent: true });
--- a/devtools/client/application/src/components/Worker.js
+++ b/devtools/client/application/src/components/Worker.js
@@ -4,16 +4,17 @@
 
 "use strict";
 
 const { Component } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { a, br, button, dd, dl, dt, header, li, section, span, time } =
   require("devtools/client/shared/vendor/react-dom-factories");
 const Services = require("Services");
+
 const { getUnicodeUrl, getUnicodeUrlPath } = require("devtools/client/shared/unicode-url");
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/debugger-client", true);
 loader.lazyRequireGetter(this, "gDevToolsBrowser",
   "devtools/client/framework/devtools-browser", true);
 
 const Strings = Services.strings.createBundle(
@@ -25,16 +26,17 @@ const Strings = Services.strings.createB
  * the worker as well as action links and buttons to interact with the worker (e.g. debug,
  * unregister, update etc...).
  */
 class Worker extends Component {
   static get propTypes() {
     return {
       client: PropTypes.instanceOf(DebuggerClient).isRequired,
       debugDisabled: PropTypes.bool,
+      serviceContainer: PropTypes.object.isRequired,
       worker: PropTypes.shape({
         active: PropTypes.bool,
         name: PropTypes.string.isRequired,
         scope: PropTypes.string.isRequired,
         // registrationActor can be missing in e10s.
         registrationActor: PropTypes.string,
         workerActor: PropTypes.string
       }).isRequired
@@ -44,45 +46,55 @@ class Worker extends Component {
   constructor(props) {
     super(props);
 
     this.debug = this.debug.bind(this);
     this.start = this.start.bind(this);
     this.unregister = this.unregister.bind(this);
   }
 
-  debug() {
+  async debug() {
     if (!this.isRunning()) {
       console.log("Service workers cannot be debugged if they are not running");
       return;
     }
 
     let { client, worker } = this.props;
-    gDevToolsBrowser.openWorkerToolbox(client, worker.workerActor);
+
+    const start = performance.now();
+    const toolbox = await gDevToolsBrowser.openWorkerToolbox(client, worker.workerActor);
+    toolbox.once("destroy", () => {
+      const duration = performance.now() - start;
+      this.props.serviceContainer.recordEvent("debug_serviceworker", { duration });
+    });
   }
 
   start() {
     if (!this.isActive() || this.isRunning()) {
       console.log("Running or inactive service workers cannot be started");
       return;
     }
 
     let { client, worker } = this.props;
     client.request({
       to: worker.registrationActor,
       type: "start"
     });
+
+    this.props.serviceContainer.recordEvent("start_serviceworker", {});
   }
 
   unregister() {
     let { client, worker } = this.props;
     client.request({
       to: worker.registrationActor,
       type: "unregister"
     });
+
+    this.props.serviceContainer.recordEvent("unregister_serviceworker", {});
   }
 
   isRunning() {
     // We know the worker is running if it has a worker actor.
     return !!this.props.worker.workerActor;
   }
 
   isActive() {
--- a/devtools/client/application/src/components/WorkerList.js
+++ b/devtools/client/application/src/components/WorkerList.js
@@ -18,34 +18,41 @@ class WorkerList extends Component {
   static get propTypes() {
     return {
       client: PropTypes.object.isRequired,
       workers: PropTypes.object.isRequired,
       serviceContainer: PropTypes.object.isRequired,
     };
   }
 
+  openAboutDebugging() {
+    this.props.serviceContainer.openTrustedLink("about:debugging#workers");
+    this.props.serviceContainer.recordEvent("open_aboutdebugging", {});
+  }
+
   render() {
-    const { workers, client, serviceContainer } = this.props;
-    const { openTrustedLink } = serviceContainer;
+    const { client, serviceContainer, workers } = this.props;
 
     return [
       article({ className: "workers-container" },
         h1({}, "Service Workers"),
         ul({},
           workers.map(worker => Worker({
             client,
             debugDisabled: false,
+            serviceContainer,
             worker,
           })))
       ),
       footer({ className: "aboutdebugging-plug" },
         "See about:debugging for Service Workers from other domains",
-        a({ className: "aboutdebugging-plug__link",
-            onClick: () => openTrustedLink("about:debugging#workers") },
+        a({
+            className: "aboutdebugging-plug__link",
+            onClick: () => this.openAboutDebugging()
+          },
           "Open about:debugging"
         )
       )
     ];
   }
 }
 
 // Exports
--- a/devtools/client/application/src/components/WorkerListEmpty.js
+++ b/devtools/client/application/src/components/WorkerListEmpty.js
@@ -17,29 +17,37 @@ const DOC_URL = "https://developer.mozil
 class WorkerListEmpty extends Component {
   static get propTypes() {
     return {
       serviceContainer: PropTypes.object.isRequired,
     };
   }
 
   switchToConsole() {
-    this.props.serviceContainer.selectTool("webconsole");
+    const { recordEvent, selectTool } = this.props.serviceContainer;
+    selectTool("webconsole");
+    recordEvent("open_help_link", { helpLink: "webconsole" });
   }
 
   switchToDebugger() {
-    this.props.serviceContainer.selectTool("jsdebugger");
+    const { recordEvent, selectTool } = this.props.serviceContainer;
+    selectTool("jsdebugger");
+    recordEvent("open_help_link", { helpLink: "jsdebugger" });
   }
 
   openAboutDebugging() {
-    this.props.serviceContainer.openTrustedLink("about:debugging#workers");
+    const { recordEvent, openTrustedLink } = this.props.serviceContainer;
+    openTrustedLink("about:debugging#workers");
+    recordEvent("open_help_link", { helpLink: "about:debugging#workers" });
   }
 
   openDocumentation() {
-    this.props.serviceContainer.openWebLink(DOC_URL);
+    const { recordEvent, openTrustedLink } = this.props.serviceContainer;
+    openTrustedLink(DOC_URL);
+    recordEvent("open_help_link", { helpLink: "mdn (Using_Service_Workers)" });
   }
 
   render() {
     return article(
       { className: "worker-list-empty" },
       h1(
         { className: "worker-list-empty__title" },
         "You need to register a Service Worker to inspect it here.",
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -371,23 +371,26 @@ var gDevToolsBrowser = exports.gDevTools
    * Open a window-hosted toolbox to debug the worker associated to the provided
    * worker actor.
    *
    * @param  {DebuggerClient} client
    * @param  {Object} workerActor
    *         worker actor form to debug
    */
   openWorkerToolbox(client, workerActor) {
-    client.attachWorker(workerActor, (response, workerClient) => {
-      let workerTarget = TargetFactory.forWorker(workerClient);
-      gDevTools.showToolbox(workerTarget, null, Toolbox.HostType.WINDOW)
-        .then(toolbox => {
-          toolbox.once("destroy", () => workerClient.detach());
-        });
-    });
+    return new Promise(resolve => {
+      client.attachWorker(workerActor, (response, workerClient) => {
+        let workerTarget = TargetFactory.forWorker(workerClient);
+        gDevTools.showToolbox(workerTarget, null, Toolbox.HostType.WINDOW)
+          .then(toolbox => {
+            toolbox.once("destroy", () => workerClient.detach());
+            resolve(toolbox);
+          });
+      });
+    })
   },
 
   /**
    * Install WebIDE widget
    */
   // Used by itself
   installWebIDEWidget() {
     if (this.isWebIDEWidgetInstalled()) {
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -277,8 +277,53 @@ devtools.main:
     notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
     record_in_processes: ["main"]
     description: User is editing HTML via the context menu item in the markup view.
     release_channel_collection: opt-out
     expiry_version: never
     extra_keys:
       made_changes: Indicates whether changes were made.
       time_open: The amount of time in ms that the HTML editor was open.
+  start_serviceworker:
+    objects: ["application"]
+    bug_numbers: [1451734]
+    notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
+    record_in_processes: ["main"]
+    description: User clicked on the Start link for a serviceworker in the application panel.
+    release_channel_collection: opt-out
+    expiry_version: never
+  debug_serviceworker:
+    objects: ["application"]
+    bug_numbers: [1451734]
+    notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
+    record_in_processes: ["main"]
+    description: User clicked on the Debug link for a serviceworker in the application panel.
+    release_channel_collection: opt-out
+    expiry_version: never
+    extra_keys:
+      duration: How much time the debugging toolbox was opened
+  unregister_serviceworker:
+    objects: ["application"]
+    bug_numbers: [1451734]
+    notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
+    record_in_processes: ["main"]
+    description: User clicked on the Unregister button for a serviceworker in the application panel.
+    release_channel_collection: opt-out
+    expiry_version: never
+  open_aboutdebugging:
+    objects: ["application"]
+    bug_numbers: [1451734]
+    notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
+    record_in_processes: ["main"]
+    description: User clicked on the aboutdebugging link displayed in the list of service workers of the application panel.
+    release_channel_collection: opt-out
+    expiry_version: never
+  open_help_link:
+    objects: ["application"]
+    bug_numbers: [1451734]
+    notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
+    record_in_processes: ["main"]
+    description: User clicked on a help link from the application panel empty screen.
+    release_channel_collection: opt-out
+    expiry_version: never
+    extra_keys:
+      helpLink: Action (toolid, or URL) triggered by clicking on the link
+