Bug 1467091 - Track application panel events with EventTelemetry draft
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 30 May 2018 14:35:48 +0200
changeset 804666 da8fffdaa53381ef17654c4cd38a26b7c1e277da
parent 804662 e566f9790eb893e13777678b99935ee3879f8da0
push id112431
push userjdescottes@mozilla.com
push dateWed, 06 Jun 2018 11:28:52 +0000
bugs1467091
milestone62.0a1
Bug 1467091 - 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/App.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
@@ -14,16 +14,17 @@ const { createFactory } = require("devto
 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 { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
 const Services = require("Services");
 
 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 = {
@@ -33,17 +34,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);
 
+    const telemetry = new Telemetry();
+
     const serviceContainer = {
+      recordEvent(action, extras) {
+        telemetry.recordEvent("devtools.main", action, "application", null, extras);
+      },
+
       selectTool(toolId) {
         return toolbox.selectTool(toolId);
       }
     };
 
     this.client.addListener("workerListChanged", this.updateWorkers);
     this.client.addListener("serviceWorkerRegistrationListChanged", this.updateWorkers);
     this.client.addListener("registration-changed", this.updateWorkers);
--- a/devtools/client/application/src/components/App.js
+++ b/devtools/client/application/src/components/App.js
@@ -37,17 +37,17 @@ class App extends Component {
     const isEmpty = workers.length === 0;
 
     return (
       LocalizationProvider(
         { messages: messageContexts },
         main(
           { className: `application ${isEmpty ? "application--empty" : ""}` },
           isEmpty ? WorkerListEmpty({ serviceContainer })
-                  : WorkerList({ workers, client })
+                  : WorkerList({ client, serviceContainer, workers })
         )
       )
     );
   }
 }
 
 // Exports
 
--- a/devtools/client/application/src/components/Worker.js
+++ b/devtools/client/application/src/components/Worker.js
@@ -24,16 +24,17 @@ loader.lazyRequireGetter(this, "gDevTool
  * 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
@@ -43,45 +44,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;
     }
 
     const { 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;
     }
 
     const { client, worker } = this.props;
     client.request({
       to: worker.registrationActor,
       type: "start"
     });
+
+    this.props.serviceContainer.recordEvent("start_serviceworker", {});
   }
 
   unregister() {
     const { 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
@@ -17,43 +17,50 @@ const Localized = createFactory(FluentRe
  * This component handles the list of service workers displayed in the application panel
  * and also displays a suggestion to use about debugging for debugging other service
  * workers.
  */
 class WorkerList extends Component {
   static get propTypes() {
     return {
       client: PropTypes.object.isRequired,
+      serviceContainer: PropTypes.object.isRequired,
       workers: PropTypes.object.isRequired,
     };
   }
 
+  openAboutDebugging() {
+    openTrustedLink("about:debugging#workers");
+    this.props.serviceContainer.recordEvent("open_aboutdebugging", {});
+  }
+
   render() {
-    const { workers, client } = this.props;
+    const { client, serviceContainer, workers } = this.props;
 
     return [
       article({ className: "workers-container" },
         Localized(
           { id: "serviceworker-list-header" },
           h1({})
         ),
         ul({},
           workers.map(worker => Worker({
             client,
             debugDisabled: false,
+            serviceContainer,
             worker,
           })))
       ),
       Localized(
         {
           id: "serviceworker-list-aboutdebugging",
           a: a(
             {
               className: "aboutdebugging-plug__link",
-              onClick: () => openTrustedLink("about:debugging#workers")
+              onClick: () => this.openAboutDebugging()
             }
           )
         },
         footer({ className: "aboutdebugging-plug" })
       )
     ];
   }
 }
--- a/devtools/client/application/src/components/WorkerListEmpty.js
+++ b/devtools/client/application/src/components/WorkerListEmpty.js
@@ -22,29 +22,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() {
+    const { recordEvent } = this.props.serviceContainer;
     openTrustedLink("about:debugging#workers");
+    recordEvent("open_help_link", { helpLink: "about:debugging#workers" });
   }
 
   openDocumentation() {
+    const { recordEvent } = this.props.serviceContainer;
     openWebLink(DOC_URL);
+    recordEvent("open_help_link", { helpLink: "mdn (Using_Service_Workers)" });
   }
 
   render() {
     return article(
       { className: "worker-list-empty" },
       Localized({
         id: "serviceworker-empty-intro",
         a: a({ className: "external-link", onClick: () => this.openDocumentation() })
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -371,22 +371,25 @@ 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) => {
-      const 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) => {
+        const 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() {
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -306,8 +306,53 @@ devtools.main:
     bug_numbers: [1463083]
     notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
     record_in_processes: ["main"]
     description: User has executed some JS in the Web Console.
     release_channel_collection: opt-out
     expiry_version: never
     extra_keys:
       lines: The number of lines contained in the command.
+  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
+