diff options
Diffstat (limited to 'toolkit/components/telemetry/other/UITelemetry.jsm')
-rw-r--r-- | toolkit/components/telemetry/other/UITelemetry.jsm | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/other/UITelemetry.jsm b/toolkit/components/telemetry/other/UITelemetry.jsm new file mode 100644 index 0000000000..b14b55bb2f --- /dev/null +++ b/toolkit/components/telemetry/other/UITelemetry.jsm @@ -0,0 +1,183 @@ +/* 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"; + +var EXPORTED_SYMBOLS = ["UITelemetry"]; + +ChromeUtils.import("resource://gre/modules/Services.jsm", this); +ChromeUtils.import("resource://gre/modules/TelemetryUtils.jsm", this); + +/** + * UITelemetry is a helper JSM used to record UI specific telemetry events. + * + * It implements nsIUITelemetryObserver, defined in nsIAndroidBridge.idl. + */ +var UITelemetry = { + _enabled: undefined, + _activeSessions: {}, + _measurements: [], + + // Lazily decide whether telemetry is enabled. + get enabled() { + if (this._enabled !== undefined) { + return this._enabled; + } + + // Set an observer to watch for changes at runtime. + Services.prefs.addObserver( + TelemetryUtils.Preferences.TelemetryEnabled, + this + ); + Services.obs.addObserver(this, "profile-before-change"); + + // Pick up the current value. + this._enabled = Services.prefs.getBoolPref( + TelemetryUtils.Preferences.TelemetryEnabled, + false + ); + + return this._enabled; + }, + + observe(aSubject, aTopic, aData) { + if (aTopic == "profile-before-change") { + Services.obs.removeObserver(this, "profile-before-change"); + Services.prefs.removeObserver( + TelemetryUtils.Preferences.TelemetryEnabled, + this + ); + this._enabled = undefined; + return; + } + + if (aTopic == "nsPref:changed") { + switch (aData) { + case TelemetryUtils.Preferences.TelemetryEnabled: + let on = Services.prefs.getBoolPref( + TelemetryUtils.Preferences.TelemetryEnabled + ); + this._enabled = on; + + // Wipe ourselves if we were just disabled. + if (!on) { + this._activeSessions = {}; + this._measurements = []; + } + break; + } + } + }, + + /** + * This exists exclusively for testing -- our events are not intended to + * be retrieved via an XPCOM interface. + */ + get wrappedJSObject() { + return this; + }, + + /** + * A hack to generate the relative timestamp from start when we don't have + * access to the Java timer. + * XXX: Bug 1007647 - Support realtime and/or uptime in JavaScript. + */ + uptimeMillis() { + return Date.now() - Services.startup.getStartupInfo().process; + }, + + /** + * Adds a single event described by a timestamp, an action, and the calling + * method. + * + * Optionally provide a string 'extras', which will be recorded as part of + * the event. + * + * All extant sessions will be recorded by name for each event. + */ + addEvent(aAction, aMethod, aTimestamp, aExtras) { + if (!this.enabled) { + return; + } + + let sessions = Object.keys(this._activeSessions); + let aEvent = { + type: "event", + action: aAction, + method: aMethod, + sessions, + timestamp: aTimestamp == undefined ? this.uptimeMillis() : aTimestamp, + }; + + if (aExtras) { + aEvent.extras = aExtras; + } + + this._recordEvent(aEvent); + }, + + /** + * Begins tracking a session by storing a timestamp for session start. + */ + startSession(aName, aTimestamp) { + if (!this.enabled) { + return; + } + + if (this._activeSessions[aName]) { + // Do not overwrite a previous event start if it already exists. + return; + } + this._activeSessions[aName] = + aTimestamp == undefined ? this.uptimeMillis() : aTimestamp; + }, + + /** + * Tracks the end of a session with a timestamp. + */ + stopSession(aName, aReason, aTimestamp) { + if (!this.enabled) { + return; + } + + let sessionStart = this._activeSessions[aName]; + delete this._activeSessions[aName]; + + if (!sessionStart) { + return; + } + + let aEvent = { + type: "session", + name: aName, + reason: aReason, + start: sessionStart, + end: aTimestamp == undefined ? this.uptimeMillis() : aTimestamp, + }; + + this._recordEvent(aEvent); + }, + + _recordEvent(aEvent) { + this._measurements.push(aEvent); + }, + + /** + * Called by TelemetrySession to populate the UI measurement + * blob. + * + * Optionally clears the set of measurements based on aClear. + */ + getUIMeasurements(aClear) { + if (!this.enabled) { + return []; + } + + let measurements = this._measurements.slice(); + if (aClear) { + this._measurements = []; + } + return measurements; + }, +}; |