mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 02:05:42 +00:00
Bug 1552464 - Add telemetry probe to count the number of viewport changes in RDM. r=mtigley,nchevobbe.
This patch adds telemetry instrumentation to count the number of times the RDM viewport properties are changed (dimensions and rotation). This count will be correlated with the panel open count and time spent open to refine the baseline for RDM usage and filter out accidental usage. A new Redux middleware, `telemetryMiddleware`, is introduced to the RDM Redux store. This observes actions dispatched to the store. For `RESIZE_VIEWPORT` and `ROTATE_VIEWPORT` actions, it increases a numeric value for the new scalar telemetry probe, `"devtools.responsive.viewport_change_count"`. Other actions may be observed in this middleware for future telemetry instrumentation of RDM. The `RESIZE_VIEWPORT` action is a dispatched with a high frequency when dragging to resize. Therefore, we debounce logging for this action. To ensure the test can reliably test counting this action without adding needless complexity to account for the asynchronicity, the `debounce()` utility is extended with an `immediate` parameter to cause the very first call to be executed immediately before going into the debounce behaviour. Differential Revision: https://phabricator.services.mozilla.com/D31645 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
d05eeb5f3a
commit
49cc754a87
@ -40,7 +40,7 @@ const bootstrap = {
|
||||
// toolbox session id.
|
||||
this.telemetry.toolOpened("responsive", -1, this);
|
||||
|
||||
const store = this.store = Store();
|
||||
const store = this.store = Store({ telemetry: this.telemetry });
|
||||
const provider = createElement(Provider, { store }, App());
|
||||
ReactDOM.render(provider, document.querySelector("#root"));
|
||||
message.post(window, "init:done");
|
||||
|
8
devtools/client/responsive.html/middleware/moz.build
Normal file
8
devtools/client/responsive.html/middleware/moz.build
Normal file
@ -0,0 +1,8 @@
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DevToolsModules(
|
||||
'telemetry.js',
|
||||
)
|
69
devtools/client/responsive.html/middleware/telemetry.js
Normal file
69
devtools/client/responsive.html/middleware/telemetry.js
Normal file
@ -0,0 +1,69 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { debounce } = require("devtools/shared/debounce");
|
||||
const {
|
||||
RESIZE_VIEWPORT,
|
||||
ROTATE_VIEWPORT,
|
||||
} = require("../actions/index");
|
||||
const TELEMETRY_SCALAR_VIEWPORT_CHANGE_COUNT =
|
||||
"devtools.responsive.viewport_change_count";
|
||||
|
||||
/**
|
||||
* Redux middleware to observe actions dispatched to the Redux store and log to Telemetry.
|
||||
*
|
||||
* `telemetryMiddleware()` is a wrapper function which receives the Telemetry
|
||||
* instance as its only argument and is used to create a closure to make that instance
|
||||
* available to the returned Redux middleware and functions nested within.
|
||||
*
|
||||
* To be used with `applyMiddleware()` helper when creating the Redux store.
|
||||
* @see https://redux.js.org/api/applymiddleware
|
||||
*
|
||||
* The wrapper returns the function that acts as the Redux middleware. This function
|
||||
* receives a single `store` argument (the Redux Middleware API, an object containing
|
||||
* `getState()` and `dispatch()`) and returns a function which receives a single `next`
|
||||
* argument (the next middleware in the chain) which itself returns a function that
|
||||
* receives a single `action` argument (the dispatched action).
|
||||
*
|
||||
* @param {Object} telemetry
|
||||
* Instance of the Telemetry API
|
||||
* @return {Function}
|
||||
*/
|
||||
function telemetryMiddleware(telemetry) {
|
||||
function logViewportChange() {
|
||||
telemetry.scalarAdd(TELEMETRY_SCALAR_VIEWPORT_CHANGE_COUNT, 1);
|
||||
}
|
||||
|
||||
// Debounced logging to use in response to high frequency actions like RESIZE_VIEWPORT.
|
||||
// Set debounce()'s `immediate` parameter to `true` to ensure the very first
|
||||
// call is executed immediately. This helps the tests to check that logging is working
|
||||
// without adding needless complexity to wait for the debounced call.
|
||||
const logViewportChangeDebounced = debounce(logViewportChange, 300, null, true);
|
||||
|
||||
// This cascade of functions is the Redux middleware signature.
|
||||
// @see https://redux.js.org/api/applymiddleware#arguments
|
||||
return store => next => action => {
|
||||
const res = next(action);
|
||||
// Pass through to the next middleware if a telemetry instance is not available, for
|
||||
// example when running unit tests.
|
||||
if (!telemetry) {
|
||||
return res;
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
case ROTATE_VIEWPORT:
|
||||
logViewportChange();
|
||||
break;
|
||||
case RESIZE_VIEWPORT:
|
||||
logViewportChangeDebounced();
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = telemetryMiddleware;
|
@ -9,6 +9,7 @@ DIRS += [
|
||||
'browser',
|
||||
'components',
|
||||
'images',
|
||||
'middleware',
|
||||
'reducers',
|
||||
'utils',
|
||||
]
|
||||
|
@ -8,10 +8,12 @@ const { combineReducers } = require("devtools/client/shared/vendor/redux");
|
||||
const createStore = require("devtools/client/shared/redux/create-store");
|
||||
const reducers = require("./reducers");
|
||||
const flags = require("devtools/shared/flags");
|
||||
const telemetryMiddleware = require("./middleware/telemetry");
|
||||
|
||||
module.exports = function() {
|
||||
module.exports = function(options = {}) {
|
||||
let shouldLog = false;
|
||||
let history;
|
||||
const { telemetry } = options;
|
||||
|
||||
// If testing, store the action history in an array
|
||||
// we'll later attach to the store
|
||||
@ -23,6 +25,7 @@ module.exports = function() {
|
||||
const store = createStore({
|
||||
log: shouldLog,
|
||||
history,
|
||||
middleware: [telemetryMiddleware(telemetry)],
|
||||
})(combineReducers(reducers), {});
|
||||
|
||||
if (history) {
|
||||
|
@ -64,6 +64,8 @@ skip-if = true # Bug 1413765
|
||||
[browser_tab_remoteness_change.js]
|
||||
[browser_target_blank.js]
|
||||
[browser_telemetry_activate_rdm.js]
|
||||
[browser_telemetry_viewport_change.js]
|
||||
skip-if = (os == "mac" && debug)
|
||||
[browser_toggle_zoom.js]
|
||||
[browser_toolbox_computed_view.js]
|
||||
[browser_toolbox_rule_view.js]
|
||||
|
@ -0,0 +1,29 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test that actions to change the RDM viewport size and rotation are logged to telemetry.
|
||||
*/
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,browser_telemetry_viewport_change.js";
|
||||
const TELEMETRY_SCALAR_VIEWPORT_CHANGE_COUNT =
|
||||
"devtools.responsive.viewport_change_count";
|
||||
|
||||
addRDMTask(TEST_URL, async function({ ui, manager }) {
|
||||
info("Clear any existing Telemetry scalars");
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
info("Resize the viewport");
|
||||
await setViewportSize(ui, manager, 100, 300);
|
||||
|
||||
info("Rotate the viewport");
|
||||
rotateViewport(ui);
|
||||
|
||||
const scalars = Services.telemetry.getSnapshotForScalars("main", false);
|
||||
ok(scalars.parent, "Telemetry scalars present");
|
||||
|
||||
const count = scalars.parent[TELEMETRY_SCALAR_VIEWPORT_CHANGE_COUNT];
|
||||
is(count, 2, "Scalar has correct number of viewport changes logged");
|
||||
});
|
@ -14,9 +14,12 @@
|
||||
* The wait period
|
||||
* @param {Object} scope
|
||||
* The scope to use for func
|
||||
* @param {Boolean} immediate
|
||||
* Whether to execute the method immediately on the first call.
|
||||
* Optional. Default `false`.
|
||||
* @return {Function} The debounced function
|
||||
*/
|
||||
exports.debounce = function(func, wait, scope) {
|
||||
exports.debounce = function(func, wait, scope, immediate = false) {
|
||||
let timer = null;
|
||||
|
||||
return function() {
|
||||
@ -29,5 +32,10 @@ exports.debounce = function(func, wait, scope) {
|
||||
timer = null;
|
||||
func.apply(scope, args);
|
||||
}, wait);
|
||||
|
||||
if (immediate) {
|
||||
immediate = false;
|
||||
func.apply(scope, args);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -1570,7 +1570,7 @@ devtools.responsive:
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- dev-developer-tools@lists.mozilla.org
|
||||
- jryans@mozilla.com
|
||||
- mbalfanz@mozilla.com
|
||||
record_in_processes:
|
||||
- main
|
||||
release_channel_collection: opt-out
|
||||
@ -1584,7 +1584,20 @@ devtools.responsive:
|
||||
keyed: true
|
||||
notification_emails:
|
||||
- dev-developer-tools@lists.mozilla.org
|
||||
- jryans@mozilla.com
|
||||
- mbalfanz@mozilla.com
|
||||
record_in_processes:
|
||||
- main
|
||||
release_channel_collection: opt-out
|
||||
viewport_change_count:
|
||||
bug_numbers:
|
||||
- 1552464
|
||||
description: >
|
||||
Number of times the viewport attributes changed while in Responsive Design Mode.
|
||||
expires: never
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- dev-developer-tools@lists.mozilla.org
|
||||
- mbalfanz@mozilla.com
|
||||
record_in_processes:
|
||||
- main
|
||||
release_channel_collection: opt-out
|
||||
|
Loading…
Reference in New Issue
Block a user