--- a/devtools/client/framework/toolbox-host-manager.js
+++ b/devtools/client/framework/toolbox-host-manager.js
@@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Services = require("Services");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+const Telemetry = require("devtools/client/shared/telemetry");
loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
loader.lazyRequireGetter(this, "Hosts", "devtools/client/framework/toolbox-hosts", true);
/**
* Implement a wrapper on the chrome side to setup a Toolbox within Firefox UI.
*
* This component handles iframe creation within Firefox, in which we are loading
@@ -47,37 +48,44 @@ function ToolboxHostManager(target, host
if (!Hosts[hostType]) {
// If the preference value is unexpected, restore to the default value.
Services.prefs.clearUserPref(LAST_HOST);
hostType = Services.prefs.getCharPref(LAST_HOST);
}
}
this.host = this.createHost(hostType, hostOptions);
this.hostType = hostType;
+ this.telemetry = new Telemetry();
}
ToolboxHostManager.prototype = {
async create(toolId) {
await this.host.create();
this.host.frame.setAttribute("aria-label", L10N.getStr("toolbox.label"));
this.host.frame.ownerDocument.defaultView.addEventListener("message", this);
// We have to listen on capture as no event fires on bubble
this.host.frame.addEventListener("unload", this, true);
+ const msSinceProcessStart = parseInt(this.telemetry.msSinceProcessStart(), 10);
const toolbox = new Toolbox(this.target, toolId, this.host.type,
- this.host.frame.contentWindow, this.frameId);
+ this.host.frame.contentWindow, this.frameId,
+ msSinceProcessStart);
// Prevent reloading the toolbox when loading the tools in a tab
// (e.g. from about:debugging)
const location = this.host.frame.contentWindow.location;
if (!location.href.startsWith("about:devtools-toolbox")) {
this.host.frame.setAttribute("src", "about:devtools-toolbox");
}
+ // We set an attribute on the toolbox iframe so that apps do not need
+ // access to the toolbox internals in order to get the session ID.
+ this.host.frame.setAttribute("session_id", msSinceProcessStart);
+
return toolbox;
},
handleEvent(event) {
switch (event.type) {
case "message":
this.onMessage(event);
break;
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -95,23 +95,32 @@ loader.lazyGetter(this, "registerHarOver
* Tool to select initially
* @param {Toolbox.HostType} hostType
* Type of host that will host the toolbox (e.g. sidebar, window)
* @param {DOMWindow} contentWindow
* The window object of the toolbox document
* @param {string} frameId
* A unique identifier to differentiate toolbox documents from the
* chrome codebase when passing DOM messages
+ * @param {Number} msSinceProcessStart
+ * the number of milliseconds since process start using monotonic
+ * timestamps (unaffected by system clock changes).
*/
-function Toolbox(target, selectedTool, hostType, contentWindow, frameId) {
+function Toolbox(target, selectedTool, hostType, contentWindow, frameId,
+ msSinceProcessStart) {
this._target = target;
this._win = contentWindow;
this.frameId = frameId;
this.telemetry = new Telemetry();
+ // The session ID is used to determine which telemetry events belong to which
+ // toolbox session. Because we use Amplitude to analyse the telemetry data we
+ // must use the time since the system wide epoch as the session ID.
+ this.sessionId = msSinceProcessStart;
+
// Map of the available DevTools WebExtensions:
// Map<extensionUUID, extensionName>
this._webExtensions = new Map();
this._toolPanels = new Map();
// Map of tool startup components for given tool id.
this._toolStartups = new Map();
this._inspectorExtensionSidebars = new Map();
@@ -719,18 +728,20 @@ Toolbox.prototype = {
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?"
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", "shortcut", "splitconsole", "width"]);
+ this.telemetry.preparePendingEvent("devtools.main", "open", "tools", null, [
+ "entrypoint", "first_panel", "host", "shortcut",
+ "splitconsole", "width", "session_id"
+ ]);
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
@@ -1888,44 +1899,55 @@ Toolbox.prototype = {
const prevPanelName = this.getTelemetryPanelNameOrOther(this.currentToolId);
const cold = !this.getPanel(id);
this.telemetry.addEventProperties("devtools.main", "enter", panelName, null, {
"host": this._hostType,
"width": width,
"start_state": reason,
"panel_name": panelName,
- "cold": cold
+ "cold": cold,
+ // "session_id" is included at the end of this method.
});
// On first load this.currentToolId === undefined so we need to skip sending
// a devtools.main.exit telemetry event.
if (this.currentToolId) {
this.telemetry.recordEvent("devtools.main", "exit", prevPanelName, null, {
"host": this._hostType,
"width": width,
"panel_name": prevPanelName,
"next_panel": panelName,
- "reason": reason
+ "reason": reason,
+ "session_id": this.sessionId
});
}
- const pending = ["host", "width", "start_state", "panel_name", "cold"];
+ const pending = ["host", "width", "start_state", "panel_name", "cold", "session_id"];
if (id === "webconsole") {
pending.push("message_count");
// Cold webconsole event message_count is handled in
// devtools/client/webconsole/webconsole-output-wrapper.js
if (!cold) {
this.telemetry.addEventProperty(
"devtools.main", "enter", "webconsole", null, "message_count", 0);
}
}
this.telemetry.preparePendingEvent(
"devtools.main", "enter", panelName, null, pending);
+ this.telemetry.addEventProperty(
+ "devtools.main", "open", "tools", null, "session_id", this.sessionId
+ );
+ // We send the "enter" session ID here to ensure it is always sent *after*
+ // the "open" session ID.
+ this.telemetry.addEventProperty(
+ "devtools.main", "enter", panelName, null, "session_id", this.sessionId
+ );
+
this.telemetry.toolOpened(id);
},
/**
* Focus a tool's panel by id
* @param {string} id
* The id of tool to focus
*/
@@ -1986,17 +2008,18 @@ Toolbox.prototype = {
if (iframe) {
this.setIframeVisible(iframe, true);
}
return this.loadTool("webconsole").then(() => {
this.component.setIsSplitConsoleActive(true);
this.telemetry.recordEvent("devtools.main", "activate", "split_console", null, {
"host": this._getTelemetryHostString(),
- "width": Math.ceil(this.win.outerWidth / 50) * 50
+ "width": Math.ceil(this.win.outerWidth / 50) * 50,
+ "session_id": this.sessionId
});
this.emit("split-console");
this.focusConsoleInput();
});
},
/**
* Closes the split console.
@@ -2007,17 +2030,18 @@ Toolbox.prototype = {
closeSplitConsole: function() {
this._splitConsole = false;
Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, false);
this._refreshConsoleDisplay();
this.component.setIsSplitConsoleActive(false);
this.telemetry.recordEvent("devtools.main", "deactivate", "split_console", null, {
"host": this._getTelemetryHostString(),
- "width": Math.ceil(this.win.outerWidth / 50) * 50
+ "width": Math.ceil(this.win.outerWidth / 50) * 50,
+ "session_id": this.sessionId
});
this.emit("split-console");
if (this._lastFocusedElement) {
this._lastFocusedElement.focus();
}
return promise.resolve();
@@ -2932,25 +2956,27 @@ Toolbox.prototype = {
// We need to grab a reference to win before this._host is destroyed.
const win = this.win;
const host = this._getTelemetryHostString();
const width = Math.ceil(win.outerWidth / 50) * 50;
const prevPanelName = this.getTelemetryPanelNameOrOther(this.currentToolId);
this.telemetry.toolClosed("toolbox");
this.telemetry.recordEvent("devtools.main", "close", "tools", null, {
- host: host,
- width: width
+ "host": host,
+ "width": width,
+ "session_id": this.sessionId
});
this.telemetry.recordEvent("devtools.main", "exit", prevPanelName, null, {
"host": host,
"width": width,
"panel_name": this.getTelemetryPanelNameOrOther(this.currentToolId),
"next_panel": "none",
- "reason": "toolbox_close"
+ "reason": "toolbox_close",
+ "session_id": this.sessionId
});
// Finish all outstanding tasks (which means finish destroying panels and
// then destroying the host, successfully or not) before destroying the
// target.
deferred.resolve(settleAll(outstanding)
.catch(console.error)
.then(() => {
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -1537,17 +1537,18 @@ MarkupView.prototype = {
if (commit) {
this.updateNodeOuterHTML(node, value, oldValue);
}
const end = this.telemetry.msSystemNow();
this.telemetry.recordEvent("devtools.main", "edit_html", "inspector", null, {
"made_changes": commit,
- "time_open": end - start
+ "time_open": end - start,
+ "session_id": this.toolbox.sessionId
});
});
this.emit("begin-editing");
});
},
/**
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -599,17 +599,19 @@ RuleEditor.prototype = {
// these entries
this.multipleAddedProperties =
parseNamedDeclarations(this.rule.cssProperties.isKnown, value, true);
// Blur the editor field now and deal with adding declarations later when
// the field gets destroyed (see _newPropertyDestroy)
this.editor.input.blur();
- this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview");
+ this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview", null, {
+ "session_id": this.toolbox.sessionId
+ });
},
/**
* Called when the new property editor is destroyed.
* This is where the properties (type TextProperty) are actually being
* added, since we want to wait until after the inplace editor `destroy`
* event has been fired to keep consistent UI state.
*/
--- a/devtools/client/inspector/rules/views/text-property-editor.js
+++ b/devtools/client/inspector/rules/views/text-property-editor.js
@@ -79,19 +79,19 @@ function TextPropertyEditor(ruleEditor,
this.popup = this.ruleView.popup;
this.prop = property;
this.prop.editor = this;
this.browserWindow = this.doc.defaultView.top;
this._populatedComputed = false;
this._hasPendingClick = false;
this._clickedElementOptions = null;
- const toolbox = this.ruleView.inspector.toolbox;
- this.telemetry = toolbox.telemetry;
- this.cssProperties = getCssProperties(toolbox);
+ this.toolbox = this.ruleView.inspector.toolbox;
+ this.telemetry = this.toolbox.telemetry;
+ this.cssProperties = getCssProperties(this.toolbox);
this.getGridlineNames = this.getGridlineNames.bind(this);
this.update = this.update.bind(this);
this.updatePropertyState = this.updatePropertyState.bind(this);
this._onEnableClicked = this._onEnableClicked.bind(this);
this._onExpandClicked = this._onExpandClicked.bind(this);
this._onNameDone = this._onNameDone.bind(this);
this._onStartEditing = this._onStartEditing.bind(this);
@@ -736,17 +736,19 @@ TextPropertyEditor.prototype = {
const checked = this.enable.hasAttribute("checked");
if (checked) {
this.enable.removeAttribute("checked");
} else {
this.enable.setAttribute("checked", "");
}
this.prop.setEnabled(!checked);
event.stopPropagation();
- this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview");
+ this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview", null, {
+ "session_id": this.toolbox.sessionId
+ });
},
/**
* Handles clicks on the computed property expander. If the computed list is
* open due to user expanding or style filtering, collapse the computed list
* and close the expander. Otherwise, add user-open attribute which is used to
* expand the computed list and tracks whether or not the computed list is
* expanded by manually by the user.
@@ -807,17 +809,19 @@ TextPropertyEditor.prototype = {
*/
_onNameDone: function(value, commit, direction) {
const isNameUnchanged = (!commit && !this.ruleEditor.isEditing) ||
this.committed.name === value;
if (this.prop.value && isNameUnchanged) {
return;
}
- this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview");
+ this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview", null, {
+ "session_id": this.toolbox.sessionId
+ });
// Remove a property if the name is empty
if (!value.trim()) {
this.remove(direction);
return;
}
// Remove a property if the property value is empty and the property
@@ -900,17 +904,19 @@ TextPropertyEditor.prototype = {
// its original value and enabled or disabled state
if (value.trim() && isValueUnchanged) {
this.ruleEditor.rule.previewPropertyValue(this.prop, val.value,
val.priority);
this.rule.setPropertyEnabled(this.prop, this.prop.enabled);
return;
}
- this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview");
+ this.telemetry.recordEvent("devtools.main", "edit_rule", "ruleview", null, {
+ "session_id": this.toolbox.sessionId
+ });
// Since the value was changed, check if the original propertywas a flex or grid
// display declaration and hide their respective highlighters.
if (this.isDisplayFlex()) {
this.ruleView.highlighters.hideFlexboxHighlighter();
}
if (this.isDisplayGrid()) {
--- a/devtools/client/inspector/toolsidebar.js
+++ b/devtools/client/inspector/toolsidebar.js
@@ -332,18 +332,19 @@ ToolSidebar.prototype = {
return;
}
if (previousToolId) {
this._telemetry.toolClosed(previousToolId);
this._telemetry.recordEvent("devtools.main", "sidepanel_changed", "inspector", null,
{
- oldpanel: previousToolId,
- newpanel: currentToolId
+ "oldpanel": previousToolId,
+ "newpanel": currentToolId,
+ "session_id": this._toolPanel._toolbox.sessionId
}
);
}
this._telemetry.toolOpened(currentToolId);
},
/**
* Show the sidebar.
--- a/devtools/client/responsive.html/manager.js
+++ b/devtools/client/responsive.html/manager.js
@@ -97,17 +97,18 @@ const ResponsiveUIManager = exports.Resp
const hasToolbox = !!toolbox;
const tel = this._telemetry;
if (hasToolbox) {
tel.scalarAdd("devtools.responsive.toolbox_opened_first", 1);
}
tel.recordEvent("devtools.main", "activate", "responsive_design", null, {
"host": hostType,
- "width": Math.ceil(window.outerWidth / 50) * 50
+ "width": Math.ceil(window.outerWidth / 50) * 50,
+ "session_id": toolbox ? toolbox.sessionId : -1
});
// Track opens keyed by the UI entry point used.
let { trigger } = options;
if (!trigger) {
trigger = "unknown";
}
tel.keyedScalarAdd("devtools.responsive.open_trigger", trigger, 1);
@@ -136,28 +137,38 @@ const ResponsiveUIManager = exports.Resp
* - `menu`: Web Developer menu item
* - `shortcut`: Keyboard shortcut
* - `reason`: String detailing the specific cause for closing
* @return Promise
* Resolved (with no value) when closing is complete.
*/
async closeIfNeeded(window, tab, options = {}) {
if (this.isActiveForTab(tab)) {
+ const isKnownTab = TargetFactory.isKnownTab(tab);
+ const target = TargetFactory.forTab(tab);
+ const toolbox = gDevTools.getToolbox(target);
+
+ if (!toolbox && !isKnownTab) {
+ // Destroy the tabTarget to avoid a memory leak.
+ target.destroy();
+ }
+
const ui = this.activeTabs.get(tab);
const destroyed = await ui.destroy(options);
if (!destroyed) {
// Already in the process of destroying, abort.
return;
}
- const hostType = Services.prefs.getStringPref("devtools.toolbox.host");
+ const hostType = toolbox ? toolbox.hostType : "none";
const t = this._telemetry;
t.recordEvent("devtools.main", "deactivate", "responsive_design", null, {
"host": hostType,
- "width": Math.ceil(window.outerWidth / 50) * 50
+ "width": Math.ceil(window.outerWidth / 50) * 50,
+ "session_id": toolbox ? toolbox.sessionId : -1
});
this.activeTabs.delete(tab);
if (!this.isActiveForWindow(window)) {
this.removeMenuCheckListenerFor(window);
}
this.emit("off", { tab });
--- a/devtools/client/responsive.html/test/browser/browser_telemetry_activate_rdm.js
+++ b/devtools/client/responsive.html/test/browser/browser_telemetry_activate_rdm.js
@@ -17,17 +17,17 @@ const DATA = [
}
}, {
timestamp: null,
category: "devtools.main",
method: "deactivate",
object: "responsive_design",
value: null,
extra: {
- host: "bottom",
+ host: "none",
width: "1300"
}
}, {
timestamp: null,
category: "devtools.main",
method: "activate",
object: "responsive_design",
value: null,
--- a/devtools/client/shared/telemetry.js
+++ b/devtools/client/shared/telemetry.js
@@ -40,16 +40,24 @@ class Telemetry {
* Time since the system wide epoch. This is not a monotonic timer but
* can be used across process boundaries.
*/
msSystemNow() {
return Services.telemetry.msSystemNow();
}
/**
+ * The number of milliseconds since process start using monotonic
+ * timestamps (unaffected by system clock changes).
+ */
+ msSinceProcessStart() {
+ return Services.telemetry.msSinceProcessStart();
+ }
+
+ /**
* Starts a timer associated with a telemetry histogram. The timer can be
* directly associated with a histogram, or with a pair of a histogram and
* an object.
*
* @param {String} histogramId
* A string which must be a valid histogram name.
* @param {Object} obj
* Optional parameter. If specified, the timer is associated with this
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -473,16 +473,17 @@ class JSTerm extends Component {
* - selectedNodeActor: tells the NodeActor ID of the current selection
* in the Inspector, if such a selection exists. This is used by
* helper functions that can evaluate on the current selection.
* @return object
* A promise object that is resolved when the server response is
* received.
*/
requestEvaluation(str, options = {}) {
+ const toolbox = gDevTools.getToolbox(this.hud.owner.target);
const deferred = defer();
function onResult(response) {
if (!response.error) {
deferred.resolve(response);
} else {
deferred.reject(response);
}
@@ -497,18 +498,21 @@ class JSTerm extends Component {
bindObjectActor: options.bindObjectActor,
frameActor: frameActor,
selectedNodeActor: options.selectedNodeActor,
selectedObjectActor: options.selectedObjectActor,
};
this.webConsoleClient.evaluateJSAsync(str, onResult, evalOptions);
+ // Send telemetry event. If we are in the browser toolbox we send -1 as the
+ // toolbox session id.
this._telemetry.recordEvent("devtools.main", "execute_js", "webconsole", null, {
- lines: str.split(/\n/).length
+ "lines": str.split(/\n/).length,
+ "session_id": toolbox ? toolbox.sessionId : -1
});
return deferred.promise;
}
/**
* Copy the object/variable by invoking the server
* which invokes the `copy(variable)` command and makes it
--- a/devtools/docs/frontend/telemetry.md
+++ b/devtools/docs/frontend/telemetry.md
@@ -238,40 +238,42 @@ And use the instance to report e.g. tool
```js
// Event telemetry is disabled by default so enable it for your category.
this._telemetry.setEventRecordingEnabled("devtools.main", true);
// If you already have all the properties for the event you can send the
// telemetry event using:
// this._telemetry.recordEvent(category, method, object, value, extra) e.g.
this._telemetry.recordEvent("devtools.main", "open", "tools", null, {
- entrypoint: "ContextMenu",
- first_panel: "Inspector",
- host: "bottom",
- splitconsole: false,
- width: 1024
+ "entrypoint": "ContextMenu",
+ "first_panel": "Inspector",
+ "host": "bottom",
+ "splitconsole": false,
+ "width": 1024,
+ "session_id": this.toolbox.sessionId
});
// If your "extra" properties are in different code paths you will need to
// create a "pending event." These events contain a list of expected properties
// that can be populated before or after creating the pending event.
// Use the category, method, object, value combinations above to add a
// property... we do this before creating the pending event simply to
// demonstrate that properties can be sent before the pending event is created.
this._telemetry.addEventProperty(
"devtools.main", "open", "tools", null, "entrypoint", "ContextMenu");
// In this example `"devtools.main", "open", "tools", null` make up the
// signature of the event and needs to be sent with all properties.
// Create the pending event using
-// this._telemetry.preparePendingEvent(category, method, object, value, expectedPropertyNames) e.g.
+// this._telemetry.preparePendingEvent(category, method, object, value,
+// expectedPropertyNames) e.g.
this._telemetry.preparePendingEvent("devtools.main", "open", "tools", null,
- ["entrypoint", "first_panel", "host", "splitconsole", "width"]
+ ["entrypoint", "first_panel", "host", "splitconsole", "width", "session_id"]
);
// Use the category, method, object, value combinations above to add each
// property.
this._telemetry.addEventProperty(
"devtools.main", "open", "tools", null, "first_panel", "inspector");
this._telemetry.addEventProperty(
"devtools.main", "open", "tools", null, "host", "bottom");
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -406,110 +406,121 @@ devtools.main:
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.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
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
extra_keys:
host: "Toolbox host (positioning): bottom, side, window or other."
width: Toolbox width rounded up to the nearest 50px.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
enter:
objects: ["webconsole", "inspector", "jsdebugger", "styleeditor", "netmonitor", "storage", "other"]
bug_numbers: [1441070]
notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
record_in_processes: ["main"]
description: User opens a tool in the devtools toolbox.
release_channel_collection: opt-out
expiry_version: never
extra_keys:
host: "Toolbox host (positioning): bottom, side, window or other."
width: Toolbox width rounded up to the nearest 50px.
message_count: The number of cached console messages.
start_state: debuggerStatement, breakpoint, exception, tab_switch, toolbox_show, initial_panel, toggle_settings_off, toggle_settings_on, key_shortcut, select_next_key, select_prev_key, tool_unloaded, inspect_dom, unknown etc.
panel_name: The name of the panel opened, webconsole, inspector, jsdebugger, styleeditor, netmonitor, storage or other
cold: Is this the first time the current panel has been opened in this toolbox?
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
exit:
objects: ["webconsole", "inspector", "jsdebugger", "styleeditor", "netmonitor", "storage", "other"]
bug_numbers: [1455270]
notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
record_in_processes: ["main"]
description: User closes a tool in the devtools toolbox.
release_channel_collection: opt-out
expiry_version: never
extra_keys:
host: "Toolbox host (positioning): bottom, side, window or other."
width: Toolbox width rounded up to the nearest 50px.
next_panel: The name of the panel closed, webconsole, inspector, jsdebugger, styleeditor, netmonitor, storage or other.
panel_name: The name of the panel opened, webconsole, inspector, jsdebugger, styleeditor, netmonitor, storage or other
reason: debuggerStatement, breakpoint, exception, tab_switch, toolbox_show, initial_panel, toggle_settings_off, toggle_settings_on, key_shortcut, select_next_key, select_prev_key, tool_unloaded, inspect_dom, toolbox_closed, unknown etc.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
activate:
objects: ["responsive_design", "split_console"]
bug_numbers: [1455273]
notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
record_in_processes: ["main"]
description: User activates the responsive_design or split_console in the devtools toolbox.
release_channel_collection: opt-out
expiry_version: never
extra_keys:
host: "Toolbox host (positioning): bottom, side, window or other."
width: Toolbox width rounded up to the nearest 50px.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
deactivate:
objects: ["responsive_design", "split_console"]
bug_numbers: [1455275]
notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
record_in_processes: ["main"]
description: User deactivates the responsive_design or split_console in the devtools toolbox.
release_channel_collection: opt-out
expiry_version: never
extra_keys:
host: "Toolbox host (positioning): bottom, side, window or other."
width: Toolbox width rounded up to the nearest 50px.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
edit_html:
objects: ["inspector"]
bug_numbers: [1463080]
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.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
edit_rule:
objects: ["ruleview"]
bug_numbers: [1463081]
notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
record_in_processes: ["main"]
description: User is editing a CSS rule by clicking on or next to a CSS property, enabling / disabling a rule or creating a new property.
release_channel_collection: opt-out
expiry_version: never
+ extra_keys:
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
sidepanel_changed:
objects: ["inspector"]
bug_numbers: [1463083]
notification_emails: ["dev-developer-tools@lists.mozilla.org", "hkirschner@mozilla.com"]
record_in_processes: ["main"]
description: User has switched sidepanel tabs.
release_channel_collection: opt-out
expiry_version: never
extra_keys:
oldpanel: The panel the user is switching from
newpanel: The panel the user is switching to
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.
execute_js:
objects: ["webconsole"]
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.
+ session_id: The start time of the session in milliseconds since epoch (Unix Timestamp) e.g. 1396381378123.