Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / devtools / docs / contributor / frontend / telemetry.md
blob97fb0644d832bcb2d250ffa6acef43196a75b87d
1 # Telemetry
3 We use telemetry to get metrics of usage of the different features and panels in DevTools. This will help us take better, informed decisions when prioritising our work.
5 ## Adding metrics to a tool
7 The process to add metrics to a tool roughly consists in:
9 1. Adding the probe to Firefox
10 2. Using Histograms.json probes in DevTools code
11 3. Using Scalars.yaml probes in DevTools code
12 4. Using Events.yaml probes in DevTools code for analysis in Amplitude.
13 5. Getting approval from the data team
15 ### 1. Adding the probe to Firefox
17 The first step involves creating entries for the probe in one of the files that contain declarations for all data that Firefox might report to Mozilla.
19 These files are:
21 - `toolkit/components/telemetry/Histograms.json`
22 - `toolkit/components/telemetry/Scalars.yaml`
23 - `toolkit/components/telemetry/Events.yaml`
25 Scalars allow collection of simple values, like counts, booleans and strings and are to be used whenever possible instead of histograms.
27 Histograms allow collection of multiple different values, but aggregate them into a number of buckets. Each bucket has a value range and a count of how many values we recorded.
29 Events allow collection of a number of properties keyed to a category, method, object and value. Event telemetry helps us tell a story about how a user is interacting with the browser.
31 Both scalars & histograms allow recording by keys. This allows for more flexible, two-level data collection.
33 #### The different file formats
35 The data team chose YAML for `Scalars.yaml` and `Events.yaml` because it is easy to write and provides a number of features not available in JSON including comments, extensible data types, relational anchors, strings without quotation marks, and mapping types preserving key order.
37 While we previously used JSON for similar purposes in histograms.json, we have used YAML here because it allows for comments and is generally easier to write.
39 The data team are considering moving the histograms over to YAML format at some point.
41 If it's the first time you add one of these, it's advised to follow the style of existing entries.
43 New data types have been added over the years, so it's quite feasible that some of our probes are not the most suitable nowadays.
45 There's more information about types (and telemetry in general) on [this page](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/start/adding-a-new-probe.html) and [this other page](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/collection/index.html).
47 And of course, in case of doubt, ask!
49 ### Adding probes to `Histograms.json`
51 Our entries are prefixed with `DEVTOOLS_`. For example:
53 ```
54   "DEVTOOLS_DOM_OPENED_COUNT": {
55     "alert_emails": ["dev-developer-tools@lists.mozilla.org"],
56     "expires_in_version": "never",
57     "kind": "count",
58     "bug_numbers": [1343501],
59     "description": "Number of times the DevTools DOM Inspector has been opened.",
60     "releaseChannelCollection": "opt-out"
61   },
62   "DEVTOOLS_DOM_TIME_ACTIVE_SECONDS": {
63     "alert_emails": ["dev-developer-tools@lists.mozilla.org"],
64     "expires_in_version": "never",
65     "kind": "exponential",
66     "bug_numbers": [1343501],
67     "high": 10000000,
68     "n_buckets": 100,
69     "description": "How long has the DOM inspector been active (seconds)"
70   },
71 ```
73 There are different types of probes you can use. These are specified by the `kind` field. Normally we use `count` for counting how many times the tools are opened, and `exponential` for how many times a panel is active.
75 ### Adding probes to `Scalars.yaml`
77 Our entries are prefixed with `devtools.`. For example:
79 ```yaml
80 devtools.toolbar.eyedropper:
81   opened:
82     bug_numbers:
83       - 1247985
84       - 1352115
85     description: Number of times the DevTools Eyedropper has been opened via the inspector toolbar.
86     expires: never
87     kind: uint
88     notification_emails:
89       - dev-developer-tools@lists.mozilla.org
90     release_channel_collection: opt-out
91     record_in_processes:
92       - 'main'
94 devtools.copy.unique.css.selector:
95   opened:
96     bug_numbers:
97       - 1323700
98       - 1352115
99     description: Number of times the DevTools copy unique CSS selector has been used.
100     expires: "57"
101     kind: uint
102     notification_emails:
103       - dev-developer-tools@lists.mozilla.org
104     release_channel_collection: opt-out
105     record_in_processes:
106       - 'main'
109 ### Adding probes to `Events.yaml`
111 Our entries are prefixed with `devtools.`. For example:
113 ```yaml
114 devtools.main:
115   open:
116     objects: ["tools"]
117     bug_numbers: [1416024]
118     notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
119     record_in_processes: ["main"]
120     description: User opens devtools toolbox.
121     release_channel_collection: opt-out
122     expiry_version: never
123     extra_keys:
124       entrypoint: How was the toolbox opened? CommandLine, ContextMenu, HamburgerMenu, KeyShortcut, SessionRestore or SystemMenu
125       first_panel: The name of the first panel opened.
126       host: "Toolbox host (positioning): bottom, side, window or other."
127       splitconsole: Indicates whether the split console was open.
128       width: Toolbox width (px).
131 ### 2. Using Histograms.json probes in DevTools code
133 Once the probe has been declared in the `Histograms.json` file, you'll need to actually use it in our code.
135 First, you need to give it an id in `devtools/client/shared/telemetry.js`. Similarly to the `Histograms.json` case, you'll want to follow the style of existing entries. For example:
137 ```js
138 dom: {
139   histogram: "DEVTOOLS_DOM_OPENED_COUNT",
140   timerHistogram: "DEVTOOLS_DOM_TIME_ACTIVE_SECONDS"
144 ... would correspond to the probes we declared in the previous section.
146 Then, include that module on each tool that requires telemetry:
148 ```js
149 let Telemetry = require("devtools/client/shared/telemetry");
152 Create a telemetry instance on the tool constructor:
154 ```js
155 this._telemetry = new Telemetry({ useSessionId: true });
157 `useSessionId` allows to aggregate all records behind a randomly unique "session_id"
158 extra attribute. For example, this helps aggregate all data recorded for one precise
159 toolbox instance.
161 And use the instance to report e.g. tool opening...
163 ```js
164 this._telemetry.toolOpened("mytoolname", this);
167 ... or closing:
169 ```js
170 this._telemetry.toolClosed("mytoolname", this);
173 Note that `mytoolname` is the id we declared in the `telemetry.js` module.
175 ### 3. Using Scalars.yaml probes in DevTools code
177 Once the probe has been declared in the `Scalars.yaml` file, you'll need to actually use it in our code.
179 First, you need to give it an id in `devtools/client/shared/telemetry.js`. You will want to follow the style of existing lowercase histogram entries. For example:
181 ```js
182 toolbareyedropper: {
183   scalar: "devtools.toolbar.eyedropper.opened", // Note that the scalar is lowercase
185 copyuniquecssselector: {
186   scalar: "devtools.copy.unique.css.selector.opened",
190 ... would correspond to the probes we declared in the previous section.
192 Then, include that module on each tool that requires telemetry:
194 ```js
195 let Telemetry = require("devtools/client/shared/telemetry");
198 Create a telemetry instance on the tool constructor:
200 ```js
201 this._telemetry = new Telemetry();
204 And use the instance to report e.g. tool opening...
206 ```js
207 this._telemetry.toolOpened("mytoolname", this);
210 Notes:
212 - `mytoolname` is the id we declared in the `Scalars.yaml` module.
213 - Because we are not logging tool's time opened in `Scalars.yaml` we don't care
214   about toolClosed. Of course, if there was an accompanying `timerHistogram`
215   field defined in `telemetry.js` and `histograms.json` then `toolClosed` should
216   also be added.
218 ### 4. Using Events.yaml probes in DevTools code
220 Once the probe has been declared in the `Events.yaml` file, you'll need to actually use it in our code.
222 It is crucial to understand that event telemetry have a string identifier which is constructed from the `category`, `method`, `object` (name) and `value` on which the event occurred. This key points to an "extra" object that contains further information about the event (we will give examples later in this section).
224 Because these "extra" objects can be from completely independent code paths we
225 can send events and leave them in a pending state until all of the expected extra properties have been received.
227 First, include the telemetry module in each tool that requires telemetry:
229 ```js
230 let Telemetry = require("devtools/client/shared/telemetry");
233 Create a telemetry instance on the tool constructor:
235 ```js
236 this._telemetry = new Telemetry();
239 And use the instance to report e.g. tool opening...
241 ```js
242 // If you already have all the properties for the event you can send the
243 // telemetry event using:
244 // this._telemetry.recordEvent(method, object, value, extra) e.g.
245 this._telemetry.recordEvent("open", "tools", null, {
246   "entrypoint": "ContextMenu",
247   "first_panel": "Inspector",
248   "host": "bottom",
249   "splitconsole": false,
250   "width": 1024,
253 // If your "extra" properties are in different code paths you will need to
254 // create a "pending event." These events contain a list of expected properties
255 // that can be populated before or after creating the pending event.
257 // Use the category, method, object, value combinations above to add a
258 // property... we do this before creating the pending event simply to
259 // demonstrate that properties can be sent before the pending event is created.
260 this._telemetry.addEventProperty(
261   this, "open", "tools", null, "entrypoint", "ContextMenu");
263 // In this example `"open", "tools", null` make up the
264 // signature of the event and needs to be sent with all properties.
266 // Create the pending event using
267 // this._telemetry.preparePendingEvent(this, method, object, value,
268 // expectedPropertyNames) e.g.
269 this._telemetry.preparePendingEvent(this, "open", "tools", null,
270   ["entrypoint", "first_panel", "host", "splitconsole", "width", "session_id"]
273 // Use the category, method, object, value combinations above to add each
274 // property.
275 this._telemetry.addEventProperty(
276   this, "open", "tools", null, "first_panel", "inspector");
277 this._telemetry.addEventProperty(
278   this, "open", "tools", null, "host", "bottom");
279 this._telemetry.addEventProperty(
280   this, "open", "tools", null, "splitconsole", false);
281 this._telemetry.addEventProperty(
282   this, "open", "tools", null, "width", 1024);
284 // You can also add properties in batches using e.g.:
285 this._telemetry.addEventProperties(this, "open", "tools", null, {
286   "first_panel": "inspector",
287   "host": "bottom",
288   "splitconsole": false,
289   "width": 1024
294 Notes:
296 - `mytoolname` is the id we declared in the `Scalars.yaml` module.
297 - Because we are not logging tool's time opened in `Scalars.yaml` we don't care
298   about toolClosed. Of course, if there was an accompanying `timerHistogram`
299   field defined in `telemetry.js` and `histograms.json` then `toolClosed` should
300   also be added.
302 #### Note on top level panels
304 The code for the tabs uses their ids to automatically report telemetry when you switch between panels, so you don't need to explicitly call `toolOpened` and `toolClosed` on top level panels.
306 You will still need to call those functions on subpanels, or tools such as `about:debugging` which are not opened as tabs.
308 #### Testing
310 The telemetry module will print warnings to stdout if there are missing ids. It is strongly advisable to ensure this is working correctly, as the module will attribute usage for undeclared ids to a generic `custom` bucket. This is not good for accurate results!
312 To see these warnings, you need to have the `browser.dom.window.dump.enabled` browser preference set to `true` in `about:config` (and restart the browser).
314 Then, try doing things that trigger telemetry calls (e.g. opening a tool). Imagine we had a typo when reporting the tool was opened:
316 ```js
317 this._telemetry.toolOpened('mytoolnmae', this);
318                                   ^^^^ typo, should be *mytoolname*
321 Would report an error to stdout:
323 ```text
324 Warning: An attempt was made to write to the mytoolnmae histogram, which is not defined in Histograms.json
327 So watch out for errors.
329 #### Testing Event Telemetry
331 This is best shown via an example:
333 ```js
334 /* Any copyright is dedicated to the Public Domain.
335  * http://creativecommons.org/publicdomain/zero/1.0/ */
337 "use strict";
339 const { Toolbox } = require("devtools/client/framework/toolbox");
340 const { TelemetryTestUtils } = ChromeUtils.importESModule("resource://testing-common/TelemetryTestUtils.sys.mjs");
342 const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_close.js";
343 const { RIGHT, BOTTOM } = Toolbox.HostType;
344 const DATA = [
345   {
346     category: "devtools.main",
347     method: "close",
348     object: "tools",
349     value: null,
350     extra: {
351       host: "right",
352       width: w => w > 0,
353     }
354   },
355   {
356     category: "devtools.main",
357     method: "close",
358     object: "tools",
359     value: null,
360     extra: {
361       host: "bottom",
362       width: w => w > 0,
363     }
364   }
367 add_task(async function() {
368   // Let's reset the counts.
369   Services.telemetry.clearEvents();
371   // Ensure no events have been logged
372   TelemetryTestUtils.assertNumberOfEvents(0);
374   await openAndCloseToolbox("webconsole", SIDE);
375   await openAndCloseToolbox("webconsole", BOTTOM);
377   checkResults();
380 async function openAndCloseToolbox(toolId, host) {
381   const tab = await addTab(URL);
382   const toolbox = await gDevTools.showToolboxForTab(tab, { toolId });
384   await toolbox.switchHost(host);
385   await toolbox.destroy();
388 function checkResults() {
389   TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
393 #### Compile it
395 You need to do a full Firefox build if you have edited either `Histograms.json` or `Events.yaml`, as they are processed at build time, and various checks will be run on them to guarantee they are valid.
397 ```bash
398 ./mach build
401 If you use `mach build faster` or artifact builds, the checks will not be performed, and your try builds will fail ("bust") when the checks are run there.
403 Save yourself some time and run the checks locally.
405 NOTE: Changes to `Scalars.yaml` *are* processed when doing an artifact build.
407 ### 4. Getting approval from the data team
409 This is required before the changes make their way into `mozilla-central`.
411 To get approval, attach your patch to the bug in Bugzilla, and set two flags:
413 - a `review?` flag for a data steward.
414 - a `needinfo?` flag to hkirschner (our product manager, so he vouches that we're using the data)
416 Be sure to explain very clearly what is the new probe for. E.g. "We're seeking approval for tracking opens of a new panel for debugging Web API ABCD" is much better than just asking for feedback without background info.
418 This review shouldn't take too long: if there's something wrong, they should tell you what to fix. If you see no signs of activity after a few days, you can ask in `#developers`.
420 Note that this review is *in addition* to normal colleague reviews.
422 Click [here](https://wiki.mozilla.org/Firefox/Data_Collection#Requesting_Data_Collection) for more details.
424 ## Accessing existing data
426 ### Local data
428 Go to `about:telemetry` to see stats relating to your local instance.
430 ### Global data
432 Data aggregated from large groups of Firefox users is available at [telemetry.mozilla.org](https://telemetry.mozilla.org).
434 Reports are written with SQL. For example, here's one comparing [usage of some DevTools panels](https://sql.telemetry.mozilla.org/queries/1000#table).
436 If you want to get better understanding of how people are using the tools, you are encouraged to explore this data set by writing your own reports.
438 The easiest way to get started is to *fork* an existing report and modify it to get used to the syntax, as SQL for massive data tables is very different from SQL for a humble blog engine, and you'll find some new operators that might look unfamiliar.
440 It's also recommended to take small steps and run the queries often to detect errors before they're too complicated to solve, particularly if you're not experienced with this (yet).
442 Slow queries will be interrupted by the system, so don't worry about "fetching too much data" or "using too many resources". There's built-in protection to avoid your code eating up the Telemetry database.
444 Funnily, if you're based in Europe, you might be in luck, as the website tends to be more responsive during European working hours than it is at Pacific working hours, as seemingly there's less people in Europe interacting with it.