diff options
author | Moonchild <moonchild@palemoon.org> | 2021-10-29 19:53:54 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2022-04-02 14:42:57 +0200 |
commit | d60103257eb83db103f9acab54b1755486b7e9c1 (patch) | |
tree | fdfdc5a4c70204d0539461c88597fe4a54c2dce2 /toolkit | |
parent | ee86d3eb9c468edbb81550d27114ed66b3d71ee5 (diff) | |
download | uxp-d60103257eb83db103f9acab54b1755486b7e9c1.tar.gz |
Issue #21 - Remove Telemetry accumulation/structures from toolkit js.
This fixes toolkit modules and prevents toolkit component breakage.
Also removes about:telemetry
Diffstat (limited to 'toolkit')
41 files changed, 22 insertions, 3577 deletions
diff --git a/toolkit/components/addoncompat/CompatWarning.jsm b/toolkit/components/addoncompat/CompatWarning.jsm index b32409a46b..c4d45adeee 100644 --- a/toolkit/components/addoncompat/CompatWarning.jsm +++ b/toolkit/components/addoncompat/CompatWarning.jsm @@ -47,11 +47,6 @@ var CompatWarning = { } alreadyWarned = true; - if (addon) { - let histogram = Services.telemetry.getKeyedHistogramById("ADDON_SHIM_USAGE"); - histogram.add(addon, warning ? warning.number : 0); - } - if (!Preferences.get("dom.ipc.shims.enabledWarnings", false)) return; diff --git a/toolkit/components/alerts/resources/content/alert.js b/toolkit/components/alerts/resources/content/alert.js index e9725bedb0..b2ebedbc0e 100644 --- a/toolkit/components/alerts/resources/content/alert.js +++ b/toolkit/components/alerts/resources/content/alert.js @@ -329,8 +329,6 @@ function doNotDisturb() { .getService(Ci.nsIAlertsService) .QueryInterface(Ci.nsIAlertsDoNotDisturb); alertService.manualDoNotDisturb = true; - Services.telemetry.getHistogramById("WEB_NOTIFICATION_MENU") - .add(0); onAlertClose(); } diff --git a/toolkit/components/asyncshutdown/AsyncShutdown.jsm b/toolkit/components/asyncshutdown/AsyncShutdown.jsm index 9cdf9e126d..43fdc6bf1e 100644 --- a/toolkit/components/asyncshutdown/AsyncShutdown.jsm +++ b/toolkit/components/asyncshutdown/AsyncShutdown.jsm @@ -9,12 +9,11 @@ * sequentially. Typically, each shutdown phase removes some * capabilities from the application. For instance, at the end of * phase profileBeforeChange, no service is permitted to write to the - * profile directory (with the exception of Telemetry). Consequently, - * if any service has requested I/O to the profile directory before or - * during phase profileBeforeChange, the system must be informed that - * these requests need to be completed before the end of phase - * profileBeforeChange. Failing to inform the system of this - * requirement can (and has been known to) cause data loss. + * profile directory. Consequently, if any service has requested I/O + * to the profile directory before or during phase profileBeforeChange, + * the system must be informed that these requests need to be completed + * before the end of phase profileBeforeChange. Failing to inform the + * system of this requirement can (and has been known to) cause data loss. * * Example: At some point during shutdown, the Add-On Manager needs to * ensure that all add-ons have safely written their data to disk, @@ -1001,7 +1000,6 @@ if (!isContent) { this.AsyncShutdown.profileChangeTeardown = getPhase("profile-change-teardown"); this.AsyncShutdown.profileBeforeChange = getPhase("profile-before-change"); this.AsyncShutdown.placesClosingInternalConnection = getPhase("places-will-close-connection"); - this.AsyncShutdown.sendTelemetry = getPhase("profile-before-change-telemetry"); } // Notifications that fire in the parent and content process, but should diff --git a/toolkit/components/asyncshutdown/nsAsyncShutdown.js b/toolkit/components/asyncshutdown/nsAsyncShutdown.js index bd2c9a2fdf..70fea9076b 100644 --- a/toolkit/components/asyncshutdown/nsAsyncShutdown.js +++ b/toolkit/components/asyncshutdown/nsAsyncShutdown.js @@ -230,7 +230,6 @@ function nsAsyncShutdownService() { "profileBeforeChange", "profileChangeTeardown", "quitApplicationGranted", - "sendTelemetry", // Child processes "contentChildShutdown", diff --git a/toolkit/components/asyncshutdown/nsIAsyncShutdown.idl b/toolkit/components/asyncshutdown/nsIAsyncShutdown.idl index 216c8047e0..2f8ca50463 100644 --- a/toolkit/components/asyncshutdown/nsIAsyncShutdown.idl +++ b/toolkit/components/asyncshutdown/nsIAsyncShutdown.idl @@ -192,11 +192,6 @@ interface nsIAsyncShutdownService: nsISupports { */ readonly attribute nsIAsyncShutdownClient quitApplicationGranted; - /** - * Barrier for notification profile-before-change-telemetry. - */ - readonly attribute nsIAsyncShutdownClient sendTelemetry; - // Barriers for global shutdown stages in all processes. diff --git a/toolkit/components/blocklist/nsBlocklistService.js b/toolkit/components/blocklist/nsBlocklistService.js index fd4e9fee07..188fdfb387 100644 --- a/toolkit/components/blocklist/nsBlocklistService.js +++ b/toolkit/components/blocklist/nsBlocklistService.js @@ -740,10 +740,7 @@ Blocklist.prototype = { return; } - let telemetry = Services.telemetry; - if (this._isBlocklistPreloaded()) { - telemetry.getHistogramById("BLOCKLIST_SYNC_FILE_LOAD").add(false); this._loadBlocklistFromString(this._preloadedBlocklistContent); delete this._preloadedBlocklistContent; return; @@ -754,8 +751,6 @@ Blocklist.prototype = { return; } - telemetry.getHistogramById("BLOCKLIST_SYNC_FILE_LOAD").add(true); - let text = ""; let fstream = null; let cstream = null; diff --git a/toolkit/components/crashes/CrashManager.jsm b/toolkit/components/crashes/CrashManager.jsm index 3aac33254a..537ab328d9 100644 --- a/toolkit/components/crashes/CrashManager.jsm +++ b/toolkit/components/crashes/CrashManager.jsm @@ -14,7 +14,6 @@ Cu.import("resource://gre/modules/Services.jsm", this); Cu.import("resource://gre/modules/Task.jsm", this); Cu.import("resource://gre/modules/Timer.jsm", this); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); -Cu.import("resource://gre/modules/TelemetryController.jsm"); Cu.import("resource://gre/modules/KeyValueParser.jsm"); this.EXPORTED_SYMBOLS = [ @@ -64,9 +63,6 @@ function dateToDays(date) { * storeDir (string) * Directory we will use for our data store. This instance will write * data files into the directory specified. - * - * telemetryStoreSizeKey (string) - * Telemetry histogram to report store size under. */ this.CrashManager = function (options) { for (let k of ["pendingDumpsDir", "submittedDumpsDir", "eventsDirs", @@ -98,10 +94,6 @@ this.CrashManager = function (options) { this._storeDir = v; break; - case "telemetryStoreSizeKey": - this._telemetryStoreSizeKey = v; - break; - default: throw new Error("Unknown property in options: " + k); } @@ -531,48 +523,6 @@ this.CrashManager.prototype = Object.freeze({ store.addCrash(this.PROCESS_TYPE_MAIN, this.CRASH_TYPE_CRASH, crashID, date, metadata); - // If we have a saved environment, use it. Otherwise report - // the current environment. - let crashEnvironment = null; - let sessionId = null; - let stackTraces = null; - let reportMeta = Cu.cloneInto(metadata, myScope); - if ('TelemetryEnvironment' in reportMeta) { - try { - crashEnvironment = JSON.parse(reportMeta.TelemetryEnvironment); - } catch (e) { - Cu.reportError(e); - } - delete reportMeta.TelemetryEnvironment; - } - if ('TelemetrySessionId' in reportMeta) { - sessionId = reportMeta.TelemetrySessionId; - delete reportMeta.TelemetrySessionId; - } - if ('StackTraces' in reportMeta) { - try { - stackTraces = JSON.parse(reportMeta.StackTraces); - } catch (e) { - Cu.reportError(e); - } - delete reportMeta.StackTraces; - } - TelemetryController.submitExternalPing("crash", - { - version: 1, - crashDate: date.toISOString().slice(0, 10), // YYYY-MM-DD - sessionId: sessionId, - crashId: entry.id, - stackTraces: stackTraces, - metadata: reportMeta, - hasCrashEnvironment: (crashEnvironment !== null), - }, - { - retentionDays: 180, - addClientId: true, - addEnvironment: true, - overrideEnvironment: crashEnvironment, - }); break; case "crash.submission.1": @@ -665,8 +615,7 @@ this.CrashManager.prototype = Object.freeze({ unixMode: OS.Constants.libc.S_IRWXU, }); - let store = new CrashStore(this._storeDir, - this._telemetryStoreSizeKey); + let store = new CrashStore(this._storeDir); yield store.load(); this._store = store; @@ -756,13 +705,9 @@ var gCrashManager; * * @param storeDir (string) * Directory the store should be located in. - * @param telemetrySizeKey (string) - * The telemetry histogram that should be used to store the size - * of the data file. */ -function CrashStore(storeDir, telemetrySizeKey) { +function CrashStore(storeDir) { this._storeDir = storeDir; - this._telemetrySizeKey = telemetrySizeKey; this._storePath = OS.Path.join(storeDir, "store.json.mozlz4"); @@ -950,9 +895,6 @@ CrashStore.prototype = Object.freeze({ let size = yield OS.File.writeAtomic(this._storePath, data, { tmpPath: this._storePath + ".tmp", compression: "lz4"}); - if (this._telemetrySizeKey) { - Services.telemetry.getHistogramById(this._telemetrySizeKey).add(size); - } }.bind(this)); }, @@ -1209,8 +1151,6 @@ CrashStore.prototype = Object.freeze({ } submission.requestDate = date; - Services.telemetry.getKeyedHistogramById("PROCESS_CRASH_SUBMIT_ATTEMPT") - .add(crash.type, 1); return true; }, @@ -1229,8 +1169,6 @@ CrashStore.prototype = Object.freeze({ submission.responseDate = date; submission.result = result; - Services.telemetry.getKeyedHistogramById("PROCESS_CRASH_SUBMIT_SUCCESS") - .add(crash.type, result == "ok"); return true; }, @@ -1333,7 +1271,6 @@ XPCOMUtils.defineLazyGetter(this.CrashManager, "Singleton", function () { submittedDumpsDir: OS.Path.join(crPath, "submitted"), eventsDirs: [OS.Path.join(crPath, "events"), OS.Path.join(storePath, "events")], storeDir: storePath, - telemetryStoreSizeKey: "CRASH_STORE_COMPRESSED_BYTES", }); // Automatically aggregate event files shortly after startup. This diff --git a/toolkit/components/gfx/SanityTest.js b/toolkit/components/gfx/SanityTest.js index a563ec3619..03b9067ef5 100644 --- a/toolkit/components/gfx/SanityTest.js +++ b/toolkit/components/gfx/SanityTest.js @@ -55,31 +55,6 @@ function testPixel(ctx, x, y, r, g, b, a, fuzz) { return false; } -function reportResult(val) { - try { - let histogram = Services.telemetry.getHistogramById("GRAPHICS_SANITY_TEST"); - histogram.add(val); - } catch (e) {} - - Preferences.set(RUNNING_PREF, false); - Services.prefs.savePrefFile(null); -} - -function reportTestReason(val) { - let histogram = Services.telemetry.getHistogramById("GRAPHICS_SANITY_TEST_REASON"); - histogram.add(val); -} - -function annotateCrashReport(value) { - try { - // "1" if we're annotating the crash report, "" to remove the annotation. - var crashReporter = Cc['@mozilla.org/toolkit/crash-reporter;1']. - getService(Ci.nsICrashReporter); - crashReporter.annotateCrashReport("GraphicsSanityTest", value ? "1" : ""); - } catch (e) { - } -} - function setTimeout(aMs, aCallback) { var timer = Cc['@mozilla.org/timer;1']. createInstance(Ci.nsITimer); @@ -125,18 +100,15 @@ function testCompositor(win, ctx) { var testPassed = true; if (!verifyVideoRendering(ctx)) { - reportResult(TEST_FAILED_VIDEO); Preferences.set(DISABLE_VIDEO_PREF, true); testPassed = false; } if (!verifyLayersRendering(ctx)) { - reportResult(TEST_FAILED_RENDER); testPassed = false; } if (testPassed) { - reportResult(TEST_PASSED); } return testPassed; @@ -160,7 +132,6 @@ var listener = { .getInterface(Ci.nsIDOMWindowUtils); setTimeout(TIMEOUT_SEC * 1000, () => { if (this.win) { - reportResult(TEST_TIMEOUT); this.endTest(); } }); @@ -227,10 +198,6 @@ var listener = { this.mm = null; } - - // Remove the annotation after we've cleaned everything up, to catch any - // incidental crashes from having performed the sanity test. - annotateCrashReport(false); } }; @@ -248,7 +215,6 @@ SanityTest.prototype = { if (Preferences.get(RUNNING_PREF, false)) { Preferences.set(DISABLE_VIDEO_PREF, true); - reportResult(TEST_CRASHED); return false; } @@ -257,11 +223,6 @@ SanityTest.prototype = { if (prefValue == value) { return true; } - if (prefValue === undefined) { - reportTestReason(REASON_FIRST_RUN); - } else { - reportTestReason(reason); - } return false; } @@ -296,8 +257,6 @@ SanityTest.prototype = { if (!this.shouldRunTest()) return; - annotateCrashReport(true); - // Open a tiny window to render our test page, and notify us when it's loaded var sanityTest = Services.ww.openWindow(null, "chrome://gfxsanity/content/sanityparent.html", diff --git a/toolkit/components/osfile/NativeOSFileInternals.cpp b/toolkit/components/osfile/NativeOSFileInternals.cpp index 36517d9ec7..801c8c37d5 100644 --- a/toolkit/components/osfile/NativeOSFileInternals.cpp +++ b/toolkit/components/osfile/NativeOSFileInternals.cpp @@ -169,7 +169,7 @@ public: * as the AbstractResult is cycle-collected. * * @param aStartDate The instant at which the operation was - * requested. Used to collect Telemetry statistics. + * requested. */ explicit AbstractResult(TimeStamp aStartDate) : mStartDate(aStartDate) @@ -182,7 +182,7 @@ public: * Setup the AbstractResult once data is available. * * @param aDispatchDate The instant at which the IO thread received - * the operation request. Used to collect Telemetry statistics. + * the operation request. * @param aExecutionDuration The duration of the operation on the * IO thread. */ diff --git a/toolkit/components/osfile/modules/osfile_async_front.jsm b/toolkit/components/osfile/modules/osfile_async_front.jsm index 698ac87323..826266ce5f 100644 --- a/toolkit/components/osfile/modules/osfile_async_front.jsm +++ b/toolkit/components/osfile/modules/osfile_async_front.jsm @@ -434,34 +434,11 @@ var Scheduler = this.Scheduler = { Scheduler.Debugging.latestReceived = [Date.now(), error.message, error.fileName, error.lineNumber]; throw error; } finally { - if (firstLaunch) { - Scheduler._updateTelemetry(); - } Scheduler.restartTimer(); } }.bind(this))); - }, - - /** - * Post Telemetry statistics. - * - * This is only useful on first launch. - */ - _updateTelemetry: function() { - let worker = this.worker; - let workerTimeStamps = worker.workerTimeStamps; - if (!workerTimeStamps) { - // If the first call to OS.File results in an uncaught errors, - // the timestamps are absent. As this case is a developer error, - // let's not waste time attempting to extract telemetry from it. - return; - } - let HISTOGRAM_LAUNCH = Services.telemetry.getHistogramById("OSFILE_WORKER_LAUNCH_MS"); - HISTOGRAM_LAUNCH.add(worker.workerTimeStamps.entered - worker.launchTimeStamp); - - let HISTOGRAM_READY = Services.telemetry.getHistogramById("OSFILE_WORKER_READY_MS"); - HISTOGRAM_READY.add(worker.workerTimeStamps.loaded - worker.launchTimeStamp); } + }; const PREF_OSFILE_LOG = "toolkit.osfile.log"; diff --git a/toolkit/components/osfile/modules/osfile_async_worker.js b/toolkit/components/osfile/modules/osfile_async_worker.js index 84287c75e7..3ae99e7054 100644 --- a/toolkit/components/osfile/modules/osfile_async_worker.js +++ b/toolkit/components/osfile/modules/osfile_async_worker.js @@ -12,7 +12,6 @@ if (this.Components) { (function(exports) { "use strict"; - // Timestamps, for use in Telemetry. // The object is set to |null| once it has been sent // to the main thread. let timeStamps = { diff --git a/toolkit/components/parentalcontrols/nsIParentalControlsService.idl b/toolkit/components/parentalcontrols/nsIParentalControlsService.idl index 45d349addc..b9d49131f5 100644 --- a/toolkit/components/parentalcontrols/nsIParentalControlsService.idl +++ b/toolkit/components/parentalcontrols/nsIParentalControlsService.idl @@ -36,8 +36,7 @@ interface nsIParentalControlsService : nsISupports const short ADVANCED_SETTINGS = 17; // Advanced settings const short CAMERA_MICROPHONE = 18; // Camera and microphone (WebRTC) const short BLOCK_LIST = 19; // Block websites that include sensitive content - const short TELEMETRY = 20; // Submit telemetry data - const short HEALTH_REPORT = 21; // Submit FHR data + // 20 and 21 are unused. Was: Telemetry, FHR const short DEFAULT_THEME = 22; // Use default theme or a special parental controls theme /** diff --git a/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm b/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm index 5351e45b23..abd7c7fb4c 100644 --- a/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm +++ b/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm @@ -145,6 +145,5 @@ this.InsecurePasswordUtils = { passwordSafety = 5; } - Services.telemetry.getHistogramById("PWMGR_LOGIN_PAGE_SAFETY").add(passwordSafety); }, }; diff --git a/toolkit/components/passwordmgr/LoginManagerContent.jsm b/toolkit/components/passwordmgr/LoginManagerContent.jsm index 60805530d3..e8dcf8ad38 100644 --- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -1068,8 +1068,6 @@ var LoginManagerContent = { } // Nothing to do if we have no matching logins available. - // Only insecure pages reach this block and logs the same - // telemetry flag. if (foundLogins.length == 0) { // We don't log() here since this is a very common case. autofillResult = AUTOFILL_RESULT.NO_SAVED_LOGINS; @@ -1234,9 +1232,6 @@ var LoginManagerContent = { } if (!userTriggered) { - // Ignore fills as a result of user action for this probe. - Services.telemetry.getHistogramById("PWMGR_FORM_AUTOFILL_RESULT").add(autofillResult); - if (usernameField) { let focusedElement = this._formFillService.focusedInput; if (usernameField == focusedElement && diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js index de601f4dd8..4db3e81b9a 100644 --- a/toolkit/components/passwordmgr/content/passwordManager.js +++ b/toolkit/components/passwordmgr/content/passwordManager.js @@ -90,7 +90,6 @@ function Startup() { } SignonColumnSort(sortField); - Services.telemetry.getKeyedHistogramById("PWMGR_MANAGE_SORTED").add(sortField); }); LoadSignons(); @@ -100,9 +99,6 @@ function Startup() { window.arguments[0] && window.arguments[0].filterString) { setFilter(window.arguments[0].filterString); - Services.telemetry.getHistogramById("PWMGR_MANAGE_OPENED").add(1); - } else { - Services.telemetry.getHistogramById("PWMGR_MANAGE_OPENED").add(0); } FocusFilterBox(); @@ -434,7 +430,6 @@ function DeleteAllSignons() { removeButton.setAttribute("disabled", "true"); removeAllButton.setAttribute("disabled", "true"); FinalizeSignonDeletions(syncNeeded); - Services.telemetry.getHistogramById("PWMGR_MANAGE_DELETED_ALL").add(1); } function TogglePasswordVisible() { @@ -449,7 +444,6 @@ function TogglePasswordVisible() { // Notify observers that the password visibility toggling is // completed. (Mostly useful for tests) Services.obs.notifyObservers(null, "passwordmgr-password-toggle-complete", null); - Services.telemetry.getHistogramById("PWMGR_MANAGE_VISIBILITY_TOGGLED").add(showingPasswords); } function AskUserShowPasswords() { @@ -466,7 +460,6 @@ function AskUserShowPasswords() { function FinalizeSignonDeletions(syncNeeded) { for (let s = 0; s < deletedSignons.length; s++) { Services.logins.removeLogin(deletedSignons[s]); - Services.telemetry.getHistogramById("PWMGR_MANAGE_DELETED").add(1); } // If the deletion has been performed in a filtered view, reflect the deletion in the unfiltered table. // See bug 405389. @@ -640,7 +633,6 @@ function CopyPassword() { let row = signonsTree.currentIndex; let password = signonsTreeView.getCellText(row, {id : "passwordCol" }); clipboard.copyString(password); - Services.telemetry.getHistogramById("PWMGR_MANAGE_COPIED_PASSWORD").add(1); } function CopyUsername() { @@ -650,7 +642,6 @@ function CopyUsername() { let row = signonsTree.currentIndex; let username = signonsTreeView.getCellText(row, {id : "userCol" }); clipboard.copyString(username); - Services.telemetry.getHistogramById("PWMGR_MANAGE_COPIED_USERNAME").add(1); } function EditCellInSelectedRow(columnName) { @@ -729,7 +720,7 @@ function escapeKeyHandler() { #if defined(MC_BASILISK) || defined(HYPE_ICEWEASEL) function OpenMigrator() { const { MigrationUtils } = Cu.import("resource:///modules/MigrationUtils.jsm", {}); - // We pass in the type of source we're using for use in telemetry: + // We pass in the type of source we're using: MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_PASSWORDS]); } #endif diff --git a/toolkit/components/passwordmgr/nsLoginManager.js b/toolkit/components/passwordmgr/nsLoginManager.js index 84b0319cb5..7d249ab9e6 100644 --- a/toolkit/components/passwordmgr/nsLoginManager.js +++ b/toolkit/components/passwordmgr/nsLoginManager.js @@ -107,7 +107,6 @@ LoginManager.prototype = { this._initStorage(); } - Services.obs.addObserver(this._observer, "gather-telemetry", false); }, @@ -168,91 +167,17 @@ LoginManager.prototype = { Services.obs.notifyObservers(null, "passwordmgr-storage-replace-complete", null); }.bind(this)); - } else if (topic == "gather-telemetry") { - // When testing, the "data" parameter is a string containing the - // reference time in milliseconds for time-based statistics. - this._pwmgr._gatherTelemetry(data ? parseInt(data) - : new Date().getTime()); } else { log.debug("Oops! Unexpected notification:", topic); } } }, - /** - * Collects statistics about the current logins and settings. The telemetry - * histograms used here are not accumulated, but are reset each time this - * function is called, since it can be called multiple times in a session. - * - * This function might also not be called at all in the current session. - * - * @param referenceTimeMs - * Current time used to calculate time-based statistics, expressed as - * the number of milliseconds since January 1, 1970, 00:00:00 UTC. - * This is set to a fake value during unit testing. - */ - _gatherTelemetry(referenceTimeMs) { - function clearAndGetHistogram(histogramId) { - let histogram = Services.telemetry.getHistogramById(histogramId); - histogram.clear(); - return histogram; - } - - clearAndGetHistogram("PWMGR_BLOCKLIST_NUM_SITES").add( - this.getAllDisabledHosts({}).length - ); - clearAndGetHistogram("PWMGR_NUM_SAVED_PASSWORDS").add( - this.countLogins("", "", "") - ); - clearAndGetHistogram("PWMGR_NUM_HTTPAUTH_PASSWORDS").add( - this.countLogins("", null, "") - ); - - // This is a boolean histogram, and not a flag, because we don't want to - // record any value if _gatherTelemetry is not called. - clearAndGetHistogram("PWMGR_SAVING_ENABLED").add(this._remember); - - // Don't try to get logins if MP is enabled, since we don't want to show a MP prompt. - if (!this.isLoggedIn) { - return; - } - - let logins = this.getAllLogins({}); - - let usernamePresentHistogram = clearAndGetHistogram("PWMGR_USERNAME_PRESENT"); - let loginLastUsedDaysHistogram = clearAndGetHistogram("PWMGR_LOGIN_LAST_USED_DAYS"); - - let hostnameCount = new Map(); - for (let login of logins) { - usernamePresentHistogram.add(!!login.username); - - let hostname = login.hostname; - hostnameCount.set(hostname, (hostnameCount.get(hostname) || 0 ) + 1); - - login.QueryInterface(Ci.nsILoginMetaInfo); - let timeLastUsedAgeMs = referenceTimeMs - login.timeLastUsed; - if (timeLastUsedAgeMs > 0) { - loginLastUsedDaysHistogram.add( - Math.floor(timeLastUsedAgeMs / MS_PER_DAY) - ); - } - } - - let passwordsCountHistogram = clearAndGetHistogram("PWMGR_NUM_PASSWORDS_PER_HOSTNAME"); - for (let count of hostnameCount.values()) { - passwordsCountHistogram.add(count); - } - }, - - - /* ---------- Primary Public interfaces ---------- */ - - /** * @type Promise * This promise is resolved when initialization is complete, and is rejected diff --git a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js index 5fb1ee83e6..7adabf2147 100644 --- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js +++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js @@ -19,14 +19,6 @@ const LoginInfo = const BRAND_BUNDLE = "chrome://branding/locale/brand.properties"; /** - * Constants for password prompt telemetry. */ -const PROMPT_DISPLAYED = 0; - -const PROMPT_ADD_OR_UPDATE = 1; -const PROMPT_NOTNOW = 2; -const PROMPT_NEVER = 3; - -/** * Implements nsIPromptFactory * * Invoked by [toolkit/components/prompts/src/nsPrompter.js] @@ -825,7 +817,7 @@ LoginManagerPrompter.prototype = { * new password. * @param {string} type * This is "password-save" or "password-change" depending on the - * original notification type. This is used for telemetry and tests. + * original notification type. This is used for tests. */ _showLoginCaptureDoorhanger(login, type) { let { browser } = this._getNotifyWindow(); @@ -855,11 +847,6 @@ LoginManagerPrompter.prototype = { let promptMsg = type == "password-save" ? this._getLocalizedString(saveMsgNames.prompt, [brandShortName]) : this._getLocalizedString(changeMsgNames.prompt); - let histogramName = type == "password-save" ? "PWMGR_PROMPT_REMEMBER_ACTION" - : "PWMGR_PROMPT_UPDATE_ACTION"; - let histogram = Services.telemetry.getHistogramById(histogramName); - histogram.add(PROMPT_DISPLAYED); - let chromeDoc = browser.ownerDocument; let currentNotification; @@ -986,10 +973,6 @@ LoginManagerPrompter.prototype = { label: this._getLocalizedString(initialMsgNames.buttonLabel), accessKey: this._getLocalizedString(initialMsgNames.buttonAccessKey), callback: () => { - histogram.add(PROMPT_ADD_OR_UPDATE); - if (histogramName == "PWMGR_PROMPT_REMEMBER_ACTION") { - Services.obs.notifyObservers(null, 'LoginStats:NewSavedPassword', null); - } readDataFromUI(); persistData(); browser.focus(); @@ -1001,7 +984,6 @@ LoginManagerPrompter.prototype = { label: this._getLocalizedString("notifyBarNeverRememberButtonText"), accessKey: this._getLocalizedString("notifyBarNeverRememberButtonAccessKey"), callback: () => { - histogram.add(PROMPT_NEVER); Services.logins.setLoginSavingEnabled(login.hostname, false); browser.focus(); } diff --git a/toolkit/components/perfmonitoring/AddonWatcher.jsm b/toolkit/components/perfmonitoring/AddonWatcher.jsm index 58decba857..e5b95d1d80 100644 --- a/toolkit/components/perfmonitoring/AddonWatcher.jsm +++ b/toolkit/components/perfmonitoring/AddonWatcher.jsm @@ -19,9 +19,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/Console.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PerformanceWatcher", "resource://gre/modules/PerformanceWatcher.jsm"); -XPCOMUtils.defineLazyServiceGetter(this, "Telemetry", - "@mozilla.org/base/telemetry;1", - Ci.nsITelemetry); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "IdleService", @@ -123,15 +120,6 @@ this.AddonWatcher = { return; } - // Report immediately to Telemetry, regardless of whether we report to - // the user. - for (let {source: {addonId}, details} of addons) { - Telemetry.getKeyedHistogramById("PERF_MONITORING_SLOW_ADDON_JANK_US"). - add(addonId, details.highestJank); - Telemetry.getKeyedHistogramById("PERF_MONITORING_SLOW_ADDON_CPOW_US"). - add(addonId, details.highestCPOW); - } - // We expect that users don't care about real-time alerts unless their // browser is going very, very slowly. Therefore, we use the following // heuristic: diff --git a/toolkit/components/places/BookmarkHTMLUtils.jsm b/toolkit/components/places/BookmarkHTMLUtils.jsm index c10ef85d60..6b4ea79340 100644 --- a/toolkit/components/places/BookmarkHTMLUtils.jsm +++ b/toolkit/components/places/BookmarkHTMLUtils.jsm @@ -220,14 +220,6 @@ this.BookmarkHTMLUtils = Object.freeze({ let exporter = new BookmarkExporter(bookmarks); yield exporter.exportToFile(aFilePath); - try { - Services.telemetry - .getHistogramById("PLACES_EXPORT_TOHTML_MS") - .add(Date.now() - startTime); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } - return count; }); }, diff --git a/toolkit/components/places/BookmarkJSONUtils.jsm b/toolkit/components/places/BookmarkJSONUtils.jsm index 7f8d3fd8f5..f212ba07db 100644 --- a/toolkit/components/places/BookmarkJSONUtils.jsm +++ b/toolkit/components/places/BookmarkJSONUtils.jsm @@ -144,14 +144,6 @@ this.BookmarkJSONUtils = Object.freeze({ let [bookmarks, count] = yield PlacesBackups.getBookmarksTree(); let startTime = Date.now(); let jsonString = JSON.stringify(bookmarks); - // Report the time taken to convert the tree to JSON. - try { - Services.telemetry - .getHistogramById("PLACES_BACKUPS_TOJSON_MS") - .add(Date.now() - startTime); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } let hash = generateHash(jsonString); diff --git a/toolkit/components/places/PlacesBackups.jsm b/toolkit/components/places/PlacesBackups.jsm index 8315aeb3ac..3cf89d530a 100644 --- a/toolkit/components/places/PlacesBackups.jsm +++ b/toolkit/components/places/PlacesBackups.jsm @@ -1,5 +1,4 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab filetype=javascript * 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/. */ @@ -537,13 +536,6 @@ this.PlacesBackups = { includeItemIds: true }); - try { - Services.telemetry - .getHistogramById("PLACES_BACKUPS_BOOKMARKSTREE_MS") - .add(Date.now() - startTime); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } return [root, root.itemsCount]; }) } diff --git a/toolkit/components/places/PlacesCategoriesStarter.js b/toolkit/components/places/PlacesCategoriesStarter.js index bab14db52d..dd0ff2a252 100644 --- a/toolkit/components/places/PlacesCategoriesStarter.js +++ b/toolkit/components/places/PlacesCategoriesStarter.js @@ -1,5 +1,4 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab * 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/. */ @@ -10,9 +9,6 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; -// Fired by TelemetryController when async telemetry data should be collected. -const TOPIC_GATHER_TELEMETRY = "gather-telemetry"; - // Seconds between maintenance runs. const MAINTENANCE_INTERVAL_SECONDS = 7 * 86400; @@ -30,7 +26,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesDBUtils", */ function PlacesCategoriesStarter() { - Services.obs.addObserver(this, TOPIC_GATHER_TELEMETRY, false); Services.obs.addObserver(this, PlacesUtils.TOPIC_SHUTDOWN, false); // nsINavBookmarkObserver implementation. @@ -63,7 +58,6 @@ PlacesCategoriesStarter.prototype = { switch (aTopic) { case PlacesUtils.TOPIC_SHUTDOWN: Services.obs.removeObserver(this, PlacesUtils.TOPIC_SHUTDOWN); - Services.obs.removeObserver(this, TOPIC_GATHER_TELEMETRY); let globalObj = Cu.getGlobalForObject(PlacesCategoriesStarter.prototype); let descriptor = @@ -72,9 +66,6 @@ PlacesCategoriesStarter.prototype = { PlacesDBUtils.shutdown(); } break; - case TOPIC_GATHER_TELEMETRY: - PlacesDBUtils.telemetry(); - break; case "idle-daily": // Once a week run places.sqlite maintenance tasks. let lastMaintenance = diff --git a/toolkit/components/places/PlacesDBUtils.jsm b/toolkit/components/places/PlacesDBUtils.jsm index 4ac6ea2610..cfb38db70b 100644 --- a/toolkit/components/places/PlacesDBUtils.jsm +++ b/toolkit/components/places/PlacesDBUtils.jsm @@ -1,5 +1,4 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab filetype=javascript * 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/. */ @@ -51,13 +50,6 @@ this.PlacesDBUtils = { } else { // All tasks have been completed. - // Telemetry the time it took for maintenance, if a start time exists. - if (aTasks._telemetryStart) { - Services.telemetry.getHistogramById("PLACES_IDLE_MAINTENANCE_TIME_MS") - .add(Date.now() - aTasks._telemetryStart); - aTasks._telemetryStart = 0; - } - if (aTasks.callback) { let scope = aTasks.scope || Cu.getGlobalForObject(aTasks.callback); aTasks.callback.call(scope, aTasks.messages); @@ -89,7 +81,6 @@ this.PlacesDBUtils = { , this.checkCoherence , this._refreshUI ]); - tasks._telemetryStart = Date.now(); tasks.callback = function() { Services.prefs.setIntPref("places.database.lastMaintenance", parseInt(Date.now() / 1000)); @@ -857,181 +848,6 @@ this.PlacesDBUtils = { }, /** - * Collects telemetry data and reports it to Telemetry. - * - * @param [optional] aTasks - * Tasks object to execute. - */ - telemetry: function PDBU_telemetry(aTasks) - { - let tasks = new Tasks(aTasks); - - // This will be populated with one integer property for each probe result, - // using the histogram name as key. - let probeValues = {}; - - // The following array contains an ordered list of entries that are - // processed to collect telemetry data. Each entry has these properties: - // - // histogram: Name of the telemetry histogram to update. - // query: This is optional. If present, contains a database command - // that will be executed asynchronously, and whose result will - // be added to the telemetry histogram. - // callback: This is optional. If present, contains a function that must - // return the value that will be added to the telemetry - // histogram. If a query is also present, its result is passed - // as the first argument of the function. If the function - // raises an exception, no data is added to the histogram. - // - // Since all queries are executed in order by the database backend, the - // callbacks can also use the result of previous queries stored in the - // probeValues object. - let probes = [ - { histogram: "PLACES_PAGES_COUNT", - query: "SELECT count(*) FROM moz_places" }, - - { histogram: "PLACES_BOOKMARKS_COUNT", - query: `SELECT count(*) FROM moz_bookmarks b - JOIN moz_bookmarks t ON t.id = b.parent - AND t.parent <> :tags_folder - WHERE b.type = :type_bookmark` }, - - { histogram: "PLACES_TAGS_COUNT", - query: `SELECT count(*) FROM moz_bookmarks - WHERE parent = :tags_folder` }, - - { histogram: "PLACES_KEYWORDS_COUNT", - query: "SELECT count(*) FROM moz_keywords" }, - - { histogram: "PLACES_SORTED_BOOKMARKS_PERC", - query: `SELECT IFNULL(ROUND(( - SELECT count(*) FROM moz_bookmarks b - JOIN moz_bookmarks t ON t.id = b.parent - AND t.parent <> :tags_folder AND t.parent > :places_root - WHERE b.type = :type_bookmark - ) * 100 / ( - SELECT count(*) FROM moz_bookmarks b - JOIN moz_bookmarks t ON t.id = b.parent - AND t.parent <> :tags_folder - WHERE b.type = :type_bookmark - )), 0)` }, - - { histogram: "PLACES_TAGGED_BOOKMARKS_PERC", - query: `SELECT IFNULL(ROUND(( - SELECT count(*) FROM moz_bookmarks b - JOIN moz_bookmarks t ON t.id = b.parent - AND t.parent = :tags_folder - ) * 100 / ( - SELECT count(*) FROM moz_bookmarks b - JOIN moz_bookmarks t ON t.id = b.parent - AND t.parent <> :tags_folder - WHERE b.type = :type_bookmark - )), 0)` }, - - { histogram: "PLACES_DATABASE_FILESIZE_MB", - callback: function () { - let DBFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile); - DBFile.append("places.sqlite"); - return parseInt(DBFile.fileSize / BYTES_PER_MEBIBYTE); - } - }, - - { histogram: "PLACES_DATABASE_PAGESIZE_B", - query: "PRAGMA page_size /* PlacesDBUtils.jsm PAGESIZE_B */" }, - - { histogram: "PLACES_DATABASE_SIZE_PER_PAGE_B", - query: "PRAGMA page_count", - callback: function (aDbPageCount) { - // Note that the database file size would not be meaningful for this - // calculation, because the file grows in fixed-size chunks. - let dbPageSize = probeValues.PLACES_DATABASE_PAGESIZE_B; - let placesPageCount = probeValues.PLACES_PAGES_COUNT; - return Math.round((dbPageSize * aDbPageCount) / placesPageCount); - } - }, - - { histogram: "PLACES_ANNOS_BOOKMARKS_COUNT", - query: "SELECT count(*) FROM moz_items_annos" }, - - { histogram: "PLACES_ANNOS_PAGES_COUNT", - query: "SELECT count(*) FROM moz_annos" }, - - { histogram: "PLACES_MAINTENANCE_DAYSFROMLAST", - callback: function () { - try { - let lastMaintenance = Services.prefs.getIntPref("places.database.lastMaintenance"); - let nowSeconds = parseInt(Date.now() / 1000); - return parseInt((nowSeconds - lastMaintenance) / 86400); - } catch (ex) { - return 60; - } - } - }, - ]; - - let params = { - tags_folder: PlacesUtils.tagsFolderId, - type_folder: PlacesUtils.bookmarks.TYPE_FOLDER, - type_bookmark: PlacesUtils.bookmarks.TYPE_BOOKMARK, - places_root: PlacesUtils.placesRootId - }; - - for (let i = 0; i < probes.length; i++) { - let probe = probes[i]; - - let promiseDone = new Promise((resolve, reject) => { - if (!("query" in probe)) { - resolve([probe]); - return; - } - - let stmt = DBConn.createAsyncStatement(probe.query); - for (let param in params) { - if (probe.query.indexOf(":" + param) > 0) { - stmt.params[param] = params[param]; - } - } - - try { - stmt.executeAsync({ - handleError: reject, - handleResult: function (aResultSet) { - let row = aResultSet.getNextRow(); - resolve([probe, row.getResultByIndex(0)]); - }, - handleCompletion: function () {} - }); - } finally { - stmt.finalize(); - } - }); - - // Report the result of the probe through Telemetry. - // The resulting promise cannot reject. - promiseDone.then( - // On success - ([aProbe, aValue]) => { - let value = aValue; - try { - if ("callback" in aProbe) { - value = aProbe.callback(value); - } - probeValues[aProbe.histogram] = value; - Services.telemetry.getHistogramById(aProbe.histogram).add(value); - } catch (ex) { - Components.utils.reportError("Error adding value " + value + - " to histogram " + aProbe.histogram + - ": " + ex); - } - }, - // On failure - this._handleError); - } - - PlacesDBUtils._executeTasks(tasks); - }, - - /** * Runs a list of tasks, notifying log messages to the callback. * * @param aTasks @@ -1068,7 +884,6 @@ function Tasks(aTasks) this._log = aTasks.messages; this.callback = aTasks.callback; this.scope = aTasks.scope; - this._telemetryStart = aTasks._telemetryStart; } } } @@ -1078,7 +893,6 @@ Tasks.prototype = { _log: [], callback: null, scope: null, - _telemetryStart: 0, /** * Adds a task to the top of the list. diff --git a/toolkit/components/places/UnifiedComplete.js b/toolkit/components/places/UnifiedComplete.js index 7b63e29bb4..3cce88b389 100644 --- a/toolkit/components/places/UnifiedComplete.js +++ b/toolkit/components/places/UnifiedComplete.js @@ -1,5 +1,4 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab * 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/. */ @@ -58,9 +57,6 @@ const QUERYTYPE_AUTOFILL_URL = 2; // "comment" back into the title and the tag. const TITLE_TAGS_SEPARATOR = " \u2013 "; -// Telemetry probes. -const TELEMETRY_1ST_RESULT = "PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS"; -const TELEMETRY_6_FIRST_RESULTS = "PLACES_AUTOCOMPLETE_6_FIRST_RESULTS_TIME_MS"; // The default frecency value used when inserting matches with unknown frecency. const FRECENCY_DEFAULT = 1000; diff --git a/toolkit/components/places/nsPlacesAutoComplete.js b/toolkit/components/places/nsPlacesAutoComplete.js index 9c6452ecd6..88de3a1f9f 100644 --- a/toolkit/components/places/nsPlacesAutoComplete.js +++ b/toolkit/components/places/nsPlacesAutoComplete.js @@ -81,9 +81,6 @@ const kBrowserUrlbarAutofillPref = "autoFill"; // Whether to search only typed entries. const kBrowserUrlbarAutofillTypedPref = "autoFill.typed"; -// The Telemetry histogram for urlInlineComplete query on domain -const DOMAIN_QUERY_TELEMETRY = "PLACES_AUTOCOMPLETE_URLINLINE_DOMAIN_QUERY_TIME_MS"; - //////////////////////////////////////////////////////////////////////////////// //// Globals @@ -553,7 +550,6 @@ nsPlacesAutoComplete.prototype = { queries.push(query); // Start executing our queries. - this._telemetryStartTime = Date.now(); this._executeQueries(queries); // Set up our persistent state for the duration of the search. @@ -810,19 +806,6 @@ nsPlacesAutoComplete.prototype = { } result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]); this._listener.onSearchResult(this, result); - if (this._telemetryStartTime) { - let elapsed = Date.now() - this._telemetryStartTime; - if (elapsed > 50) { - try { - Services.telemetry - .getHistogramById("PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS") - .add(elapsed); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } - } - this._telemetryStartTime = null; - } }, /** diff --git a/toolkit/components/places/nsPlacesExpiration.js b/toolkit/components/places/nsPlacesExpiration.js index 767a4d3458..0f376626da 100644 --- a/toolkit/components/places/nsPlacesExpiration.js +++ b/toolkit/components/places/nsPlacesExpiration.js @@ -1,5 +1,4 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab * 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/. */ @@ -708,22 +707,12 @@ nsPlacesExpiration.prototype = { aError.result + "', '" + aError.message + "'"); }, - // Number of expiration steps needed to reach a CLEAN status. - _telemetrySteps: 1, handleCompletion: function PEX_handleCompletion(aReason) { if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED) { if (this._mostRecentExpiredVisitDays) { - try { - Services.telemetry - .getHistogramById("PLACES_MOST_RECENT_EXPIRED_VISIT_DAYS") - .add(this._mostRecentExpiredVisitDays); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } finally { - delete this._mostRecentExpiredVisitDays; - } + delete this._mostRecentExpiredVisitDays; } if ("_expectedResultsCount" in this) { @@ -734,25 +723,6 @@ nsPlacesExpiration.prototype = { this.status = this._expectedResultsCount == 0 ? STATUS.DIRTY : STATUS.CLEAN; - // Collect or send telemetry data. - if (this.status == STATUS.DIRTY) { - this._telemetrySteps++; - } - else { - // Avoid reporting the common cases where the database is clean, or - // a single step is needed. - if (oldStatus == STATUS.DIRTY) { - try { - Services.telemetry - .getHistogramById("PLACES_EXPIRATION_STEPS_TO_CLEAN2") - .add(this._telemetrySteps); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } - } - this._telemetrySteps = 1; - } - delete this._expectedResultsCount; } diff --git a/toolkit/components/printing/content/printUtils.js b/toolkit/components/printing/content/printUtils.js index 4169541880..62602396c3 100644 --- a/toolkit/components/printing/content/printUtils.js +++ b/toolkit/components/printing/content/printUtils.js @@ -198,9 +198,6 @@ var PrintUtils = { this._sourceBrowser = aListenerObj.getSourceBrowser(); this._originalTitle = this._sourceBrowser.contentTitle; this._originalURL = this._sourceBrowser.currentURI.spec; - - // Here we log telemetry data for when the user enters print preview. - this.logTelemetry("PRINT_PREVIEW_OPENED_COUNT"); } else { // collapse the browser here -- it will be shown in // enterPrintPreview; this forces a reflow which fixes display @@ -536,9 +533,6 @@ var PrintUtils = { URL: this._originalURL, windowID: this._sourceBrowser.outerWindowID, }); - - // Here we log telemetry data for when the user enters simplify mode. - this.logTelemetry("PRINT_PREVIEW_SIMPLIFY_PAGE_OPENED_COUNT"); } } else { sendEnterPreviewMessage(this._sourceBrowser, false); @@ -597,7 +591,6 @@ var PrintUtils = { if (this._sourceBrowser.isArticle) { printPreviewTB.enableSimplifyPage(); } else { - this.logTelemetry("PRINT_PREVIEW_SIMPLIFY_PAGE_UNAVAILABLE_COUNT"); printPreviewTB.disableSimplifyPage(); } @@ -652,12 +645,6 @@ var PrintUtils = { this._listener.onExit(); }, - logTelemetry: function (ID) - { - let histogram = Services.telemetry.getHistogramById(ID); - histogram.add(true); - }, - onKeyDownPP: function (aEvent) { // Esc exits the PP diff --git a/toolkit/components/terminator/terminator.manifest b/toolkit/components/terminator/terminator.manifest index c1757ba86a..33cb143de9 100644 --- a/toolkit/components/terminator/terminator.manifest +++ b/toolkit/components/terminator/terminator.manifest @@ -1,5 +1 @@ category profile-after-change nsTerminator @mozilla.org/toolkit/shutdown-terminator;1 - -component {3f78ada1-cba2-442a-82dd-d5fb300ddea7} nsTerminatorTelemetry.js -contract @mozilla.org/toolkit/shutdown-terminator-telemetry;1 {3f78ada1-cba2-442a-82dd-d5fb300ddea7} -category profile-after-change nsTerminatorTelemetry @mozilla.org/toolkit/shutdown-terminator-telemetry;1 diff --git a/toolkit/components/thumbnails/BackgroundPageThumbs.jsm b/toolkit/components/thumbnails/BackgroundPageThumbs.jsm index 3ed32665de..77b7c8e2ca 100644 --- a/toolkit/components/thumbnails/BackgroundPageThumbs.jsm +++ b/toolkit/components/thumbnails/BackgroundPageThumbs.jsm @@ -10,8 +10,6 @@ const DEFAULT_CAPTURE_TIMEOUT = 30000; // ms const DESTROY_BROWSER_TIMEOUT = 60000; // ms const FRAME_SCRIPT_URL = "chrome://global/content/backgroundPageThumbsContent.js"; -const TELEMETRY_HISTOGRAM_ID_PREFIX = "FX_THUMBNAILS_BG_"; - const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const HTML_NS = "http://www.w3.org/1999/xhtml"; @@ -22,19 +20,6 @@ Cu.import("resource://gre/modules/PageThumbs.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); -// possible FX_THUMBNAILS_BG_CAPTURE_DONE_REASON_2 telemetry values -const TEL_CAPTURE_DONE_OK = 0; -const TEL_CAPTURE_DONE_TIMEOUT = 1; -// 2 and 3 were used when we had special handling for private-browsing. -const TEL_CAPTURE_DONE_CRASHED = 4; -const TEL_CAPTURE_DONE_BAD_URI = 5; - -// These are looked up on the global as properties below. -XPCOMUtils.defineConstant(this, "TEL_CAPTURE_DONE_OK", TEL_CAPTURE_DONE_OK); -XPCOMUtils.defineConstant(this, "TEL_CAPTURE_DONE_TIMEOUT", TEL_CAPTURE_DONE_TIMEOUT); -XPCOMUtils.defineConstant(this, "TEL_CAPTURE_DONE_CRASHED", TEL_CAPTURE_DONE_CRASHED); -XPCOMUtils.defineConstant(this, "TEL_CAPTURE_DONE_BAD_URI", TEL_CAPTURE_DONE_BAD_URI); - const global = this; // contains base64 version of a placeholder thumbnail @@ -67,8 +52,6 @@ const BackgroundPageThumbs = { this._captureQueue = this._captureQueue || []; this._capturesByURL = this._capturesByURL || new Map(); - tel("QUEUE_SIZE_ON_CAPTURE", this._captureQueue.length); - // We want to avoid duplicate captures for the same URL. If there is an // existing one, we just add the callback to that one and we are done. let existing = this._capturesByURL.get(url); @@ -237,7 +220,7 @@ const BackgroundPageThumbs = { // listener. Trying to send a message to the manager in that case // throws NS_ERROR_NOT_INITIALIZED. Services.tm.currentThread.dispatch(() => { - curCapture._done(null, TEL_CAPTURE_DONE_CRASHED); + curCapture._done(null); }, Ci.nsIEventTarget.DISPATCH_NORMAL); } // else: we must have been idle and not currently doing a capture (eg, @@ -286,9 +269,6 @@ const BackgroundPageThumbs = { throw new Error("The capture should be at the head of the queue."); this._captureQueue.shift(); this._capturesByURL.delete(capture.url); - if (capture.doneReason != TEL_CAPTURE_DONE_OK) { - Services.obs.notifyObservers(null, "page-thumbnail:error", capture.url); - } // Start the destroy-browser timer *before* processing the capture queue. let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); @@ -324,7 +304,6 @@ function Capture(url, captureCallback, options) { this.id = Capture.nextID++; this.creationDate = new Date(); this.doneCallbacks = []; - this.doneReason; if (options.onDone) this.doneCallbacks.push(options.onDone); } @@ -342,7 +321,6 @@ Capture.prototype = { */ start: function (messageManager) { this.startDate = new Date(); - tel("CAPTURE_QUEUE_TIME_MS", this.startDate - this.creationDate); // timeout timer let timeout; @@ -386,46 +364,30 @@ Capture.prototype = { // Called when the didCapture message is received. receiveMessage: function (msg) { - if (msg.data.imageData) - tel("CAPTURE_SERVICE_TIME_MS", new Date() - this.startDate); - // A different timed-out capture may have finally successfully completed, so // discard messages that aren't meant for this capture. if (msg.data.id != this.id) return; if (msg.data.failReason) { - let reason = global["TEL_CAPTURE_DONE_" + msg.data.failReason]; - this._done(null, reason); + this._done(null); return; } - this._done(msg.data, TEL_CAPTURE_DONE_OK); + this._done(msg.data); }, // Called when the timeout timer fires. notify: function () { - this._done(null, TEL_CAPTURE_DONE_TIMEOUT); + this._done(null); }, - _done: function (data, reason) { + _done: function (data) { // Note that _done will be called only once, by either receiveMessage or // notify, since it calls destroy here, which cancels the timeout timer and // removes the didCapture message listener. let { captureCallback, doneCallbacks, options } = this; this.destroy(); - this.doneReason = reason; - - if (typeof(reason) != "number") { - throw new Error("A done reason must be given."); - } - tel("CAPTURE_DONE_REASON_2", reason); - if (data && data.telemetry) { - // Telemetry is currently disabled in the content process (bug 680508). - for (let id in data.telemetry) { - tel(id, data.telemetry[id]); - } - } let done = () => { captureCallback(this); @@ -454,17 +416,6 @@ Capture.prototype = { Capture.nextID = 0; -/** - * Adds a value to one of this module's telemetry histograms. - * - * @param histogramID This is prefixed with this module's ID. - * @param value The value to add. - */ -function tel(histogramID, value) { - let id = TELEMETRY_HISTOGRAM_ID_PREFIX + histogramID; - Services.telemetry.getHistogramById(id).add(value); -} - function schedule(callback) { Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL); } diff --git a/toolkit/components/thumbnails/PageThumbs.jsm b/toolkit/components/thumbnails/PageThumbs.jsm index b0affee928..714bbbb77a 100644 --- a/toolkit/components/thumbnails/PageThumbs.jsm +++ b/toolkit/components/thumbnails/PageThumbs.jsm @@ -215,14 +215,10 @@ this.PageThumbs = { * fullScale - request that a non-downscaled image be returned. */ captureToCanvas: function (aBrowser, aCanvas, aCallback, aArgs) { - let telemetryCaptureTime = new Date(); let args = { fullScale: aArgs ? aArgs.fullScale : false }; this._captureToCanvas(aBrowser, aCanvas, args, (aCanvas) => { - Services.telemetry - .getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS") - .add(new Date() - telemetryCaptureTime); if (aCallback) { aCallback(aCanvas); } @@ -450,10 +446,7 @@ this.PageThumbs = { */ _store: function PageThumbs__store(aOriginalURL, aFinalURL, aData, aNoOverwrite) { return Task.spawn(function* () { - let telemetryStoreTime = new Date(); yield PageThumbsStorage.writeData(aFinalURL, aData, aNoOverwrite); - Services.telemetry.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS") - .add(new Date() - telemetryStoreTime); Services.obs.notifyObservers(null, "page-thumbnail:create", aFinalURL); // We've been redirected. Create a copy of the current thumbnail for diff --git a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js index 2103833b7b..ab39e73f72 100644 --- a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js +++ b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js @@ -169,10 +169,6 @@ const backgroundPageThumbsContent = { id: capture.id, imageData: fileReader.result, finalURL: capture.finalURL, - telemetry: { - CAPTURE_PAGE_LOAD_TIME_MS: capture.pageLoadTime, - CAPTURE_CANVAS_DRAW_TIME_MS: capture.canvasDrawTime, - }, }); }; fileReader.readAsArrayBuffer(capture.imageBlob); diff --git a/toolkit/components/viewsource/content/viewSourceUtils.js b/toolkit/components/viewsource/content/viewSourceUtils.js index 11b39ca54b..72f5dd787a 100644 --- a/toolkit/components/viewsource/content/viewSourceUtils.js +++ b/toolkit/components/viewsource/content/viewSourceUtils.js @@ -90,9 +90,6 @@ var gViewSourceUtils = { * The line number to focus on once the source is loaded. */ viewSourceInBrowser: function(aArgs) { - Services.telemetry - .getHistogramById("VIEW_SOURCE_IN_BROWSER_OPENED_BOOLEAN") - .add(true); let viewSourceBrowser = new ViewSourceBrowser(aArgs.viewSourceBrowser); viewSourceBrowser.loadViewSource(aArgs); }, @@ -160,9 +157,6 @@ var gViewSourceUtils = { } catch (ex) { } } - Services.telemetry - .getHistogramById("VIEW_SOURCE_IN_WINDOW_OPENED_BOOLEAN") - .add(true); openDialog("chrome://global/content/viewSource.xul", "_blank", "all,dialog=no", @@ -347,9 +341,6 @@ var gViewSourceUtils = { // Calls the callback, keeping in mind undefined or null values. handleCallBack: function(aCallBack, result, data) { - Services.telemetry - .getHistogramById("VIEW_SOURCE_EXTERNAL_RESULT_BOOLEAN") - .add(result); // if callback is undefined, default to the internal viewer if (aCallBack === undefined) { this.internalViewerFallback(result, data); diff --git a/toolkit/content/aboutTelemetry.css b/toolkit/content/aboutTelemetry.css deleted file mode 100644 index 6acf82c201..0000000000 --- a/toolkit/content/aboutTelemetry.css +++ /dev/null @@ -1,271 +0,0 @@ -/* 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/. */ - -.hidden { - display: none; -} - -html { - background-color: -moz-Dialog; - color: -moz-DialogText; - font: message-box; -} - -body { - padding: 0px; - margin: 0px; -} - -h2 { - font-size: medium; -} - -#page-description { - border: 1px solid threedshadow; - margin: 0px; - padding: 10px; -} - -#settings { - border: 1px solid lightgrey; - padding: 5px; -} - -.description-enabled, -.description-disabled { - margin: 0px; -} - -.description-enabled > span { - color: green; -} - -.description-disabled > span { - color: red; -} - -#ping-picker { - margin-top: 10px; - border: 1px solid lightgrey; - padding: 5px; -} - -#ping-source-picker { - margin-left: 5px; - margin-bottom: 10px; -} - -.data-section, -.data-subsection { - background-color: -moz-Field; - color: -moz-FieldText; - border-top: 1px solid threedshadow; - border-bottom: 1px solid threedshadow; - margin: 0px; - padding: 10px; -} - -.data-section:not(.has-data), -.data-subsection:not(.has-subdata) { - color: gray; -} - - -.section-name { - font-size: x-large; - display: inline; -} - -.has-data .section-name { - cursor: pointer; -} - - -.toggle-caption { - font-style: italic; - cursor: pointer; -} - -.data-section:not(.has-data) .toggle-caption, -.data-subsection:not(.has-subdata) .toggle-caption { - display: none; -} - - -.empty-caption { - font-style: italic; -} - -.has-data .empty-caption, -.has-subdata .empty-caption { - display: none; /* invisible when has-data */ -} - -.data, -.subdata { - margin: 15px; - display: none; -} - -.has-data.expanded .data, -.has-subdata.expanded .subdata { - display: block; -} - - -.stack-title { - font-size: medium; - font-weight: bold; - text-decoration: underline; -} - -#histograms, #addon-histograms, #thread-hang-stats>div { - overflow: hidden; -} - -.histogram { - float: left; - border: 1px solid gray; - white-space: nowrap; - padding: 10px; - position: relative; /* required for position:absolute of the contained .copy-node */ -} - -body[dir="rtl"] .histogram { - float: right; -} - -.histogram-title { - text-overflow: ellipsis; - width: 100%; - white-space: nowrap; - overflow: hidden; -} - -.keyed-histogram { - white-space: nowrap; - padding: 15px; - position: relative; /* required for position:absolute of the contained .copy-node */ - display: block; - overflow: hidden; -} - -.keyed-histogram-title { - text-overflow: ellipsis; - width: 100%; - margin: 10px; - font-weight: bold; - font-size: 120%; - white-space: nowrap; -} - - -.bar { - width: 2em; - margin: 2px; - text-align: center; - float: left; - font-family: monospace; -} - -body[dir="rtl"] .bar { - float: right; -} - -.bar-inner { - background-color: DeepSkyBlue; - border: 1px solid #0000b0; -} - -th { - font-weight: bold; - white-space: nowrap; - text-align: left; -} - -body[dir="rtl"] th { - text-align: right; -} - -caption { - font-weight: bold; - white-space: nowrap; - text-align: left; - font-size: large; -} - -body[dir="rtl"] caption { - text-align: right; -} - -.copy-node { - visibility: hidden; - position: absolute; - bottom: 1px; - right: 1px; -} - -body[dir="rtl"] .copy-node { - left: 1px; -} - -.histogram:hover .copy-node { - visibility: visible; -} - - -.statebox { - display: none; -} - - -.filter-ui { - padding-inline-start: 10em; - display: none; -} - -.has-data.expanded .filter-ui { - display: inline; -} - -.processes-ui { - display: none; -} - -.has-data.expanded .processes-ui { - display: initial; -} - -.filter-blocked { - display: none; -} - -#raw-ping-data-section { - width: 100%; - height: 100%; - background-color:-moz-Dialog; -} - -#raw-ping-data { - background-color:white; - margin: 0px; -} - -#hide-raw-ping { - float: right; - cursor: pointer; - font-size: 20px; - background-color:#d8d8d8; - padding: 5px 10px; -} - -/* addon subsection style */ -.addon-caption { - font-size: larger; - margin: 5px 0; -} - -.process-picker { - margin: 0 0.5em; -} diff --git a/toolkit/content/aboutTelemetry.js b/toolkit/content/aboutTelemetry.js deleted file mode 100644 index 97dcba9e26..0000000000 --- a/toolkit/content/aboutTelemetry.js +++ /dev/null @@ -1,2168 +0,0 @@ -/* 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 Ci = Components.interfaces; -var Cc = Components.classes; -var Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/TelemetryTimestamps.jsm"); -Cu.import("resource://gre/modules/TelemetryController.jsm"); -Cu.import("resource://gre/modules/TelemetrySession.jsm"); -Cu.import("resource://gre/modules/TelemetryArchive.jsm"); -Cu.import("resource://gre/modules/TelemetryUtils.jsm"); -Cu.import("resource://gre/modules/TelemetryLog.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); - -const Telemetry = Services.telemetry; -const bundle = Services.strings.createBundle( - "chrome://global/locale/aboutTelemetry.properties"); -const brandBundle = Services.strings.createBundle( - "chrome://branding/locale/brand.properties"); - -// Maximum height of a histogram bar (in em for html, in chars for text) -const MAX_BAR_HEIGHT = 18; -const MAX_BAR_CHARS = 25; -const PREF_TELEMETRY_SERVER_OWNER = "toolkit.telemetry.server_owner"; -const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; -const PREF_DEBUG_SLOW_SQL = "toolkit.telemetry.debugSlowSql"; -const PREF_SYMBOL_SERVER_URI = "profiler.symbolicationUrl"; -const DEFAULT_SYMBOL_SERVER_URI = "http://symbolapi.mozilla.org"; -const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled"; - -// ms idle before applying the filter (allow uninterrupted typing) -const FILTER_IDLE_TIMEOUT = 500; - -const isWindows = (Services.appinfo.OS == "WINNT"); -const EOL = isWindows ? "\r\n" : "\n"; - -// This is the ping object currently displayed in the page. -var gPingData = null; - -// Cached value of document's RTL mode -var documentRTLMode = ""; - -/** - * Helper function for determining whether the document direction is RTL. - * Caches result of check on first invocation. - */ -function isRTL() { - if (!documentRTLMode) - documentRTLMode = window.getComputedStyle(document.body).direction; - return (documentRTLMode == "rtl"); -} - -function isArray(arg) { - return Object.prototype.toString.call(arg) === '[object Array]'; -} - -function isFlatArray(obj) { - if (!isArray(obj)) { - return false; - } - return !obj.some(e => typeof(e) == "object"); -} - -/** - * This is a helper function for explodeObject. - */ -function flattenObject(obj, map, path, array) { - if (!obj) { - return; - } - - for (let k of Object.keys(obj)) { - let newPath = [...path, array ? "[" + k + "]" : k]; - let v = obj[k]; - if (!v || (typeof(v) != "object")) { - map.set(newPath.join("."), v); - } else if (isFlatArray(v)) { - map.set(newPath.join("."), "[" + v.join(", ") + "]"); - } else { - flattenObject(v, map, newPath, isArray(v)); - } - } -} - -/** - * This turns a JSON object into a "flat" stringified form. - * - * For an object like {a: "1", b: {c: "2", d: "3"}} it returns a Map of the - * form Map(["a","1"], ["b.c", "2"], ["b.d", "3"]). - */ -function explodeObject(obj) { - let map = new Map(); - flattenObject(obj, map, []); - return map; -} - -function filterObject(obj, filterOut) { - let ret = {}; - for (let k of Object.keys(obj)) { - if (filterOut.indexOf(k) == -1) { - ret[k] = obj[k]; - } - } - return ret; -} - - -/** - * This turns a JSON object into a "flat" stringified form, separated into top-level sections. - * - * For an object like: - * { - * a: {b: "1"}, - * c: {d: "2", e: {f: "3"}} - * } - * it returns a Map of the form: - * Map([ - * ["a", Map(["b","1"])], - * ["c", Map([["d", "2"], ["e.f", "3"]])] - * ]) - */ -function sectionalizeObject(obj) { - let map = new Map(); - for (let k of Object.keys(obj)) { - map.set(k, explodeObject(obj[k])); - } - return map; -} - -/** - * Obtain the main DOMWindow for the current context. - */ -function getMainWindow() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); -} - -/** - * Obtain the DOMWindow that can open a preferences pane. - * - * This is essentially "get the browser chrome window" with the added check - * that the supposed browser chrome window is capable of opening a preferences - * pane. - * - * This may return null if we can't find the browser chrome window. - */ -function getMainWindowWithPreferencesPane() { - let mainWindow = getMainWindow(); - if (mainWindow && "openAdvancedPreferences" in mainWindow) { - return mainWindow; - } - return null; -} - -/** - * Remove all child nodes of a document node. - */ -function removeAllChildNodes(node) { - while (node.hasChildNodes()) { - node.removeChild(node.lastChild); - } -} - -/** - * Pad a number to two digits with leading "0". - */ -function padToTwoDigits(n) { - return (n > 9) ? n: "0" + n; -} - -/** - * Return yesterdays date with the same time. - */ -function yesterday(date) { - let d = new Date(date); - d.setDate(d.getDate() - 1); - return d; -} - -/** - * This returns a short date string of the form YYYY/MM/DD. - */ -function shortDateString(date) { - return date.getFullYear() - + "/" + padToTwoDigits(date.getMonth() + 1) - + "/" + padToTwoDigits(date.getDate()); -} - -/** - * This returns a short time string of the form hh:mm:ss. - */ -function shortTimeString(date) { - return padToTwoDigits(date.getHours()) - + ":" + padToTwoDigits(date.getMinutes()) - + ":" + padToTwoDigits(date.getSeconds()); -} - -var Settings = { - SETTINGS: [ - // data upload - { - pref: PREF_FHR_UPLOAD_ENABLED, - defaultPrefValue: false, - descriptionEnabledId: "description-upload-enabled", - descriptionDisabledId: "description-upload-disabled", - }, - // extended "Telemetry" recording - { - pref: PREF_TELEMETRY_ENABLED, - defaultPrefValue: false, - descriptionEnabledId: "description-extended-recording-enabled", - descriptionDisabledId: "description-extended-recording-disabled", - }, - ], - - attachObservers: function() { - for (let s of this.SETTINGS) { - let setting = s; - Preferences.observe(setting.pref, this.render, this); - } - - let elements = document.getElementsByClassName("change-data-choices-link"); - for (let el of elements) { - el.addEventListener("click", function() { - // Show the data choices preferences on desktop. - let mainWindow = getMainWindowWithPreferencesPane(); - mainWindow.openAdvancedPreferences("dataChoicesTab"); - }, false); - } - }, - - detachObservers: function() { - for (let setting of this.SETTINGS) { - Preferences.ignore(setting.pref, this.render, this); - } - }, - - /** - * Updates the button & text at the top of the page to reflect Telemetry state. - */ - render: function() { - for (let setting of this.SETTINGS) { - let enabledElement = document.getElementById(setting.descriptionEnabledId); - let disabledElement = document.getElementById(setting.descriptionDisabledId); - - if (Preferences.get(setting.pref, setting.defaultPrefValue)) { - enabledElement.classList.remove("hidden"); - disabledElement.classList.add("hidden"); - } else { - enabledElement.classList.add("hidden"); - disabledElement.classList.remove("hidden"); - } - } - } -}; - -var PingPicker = { - viewCurrentPingData: null, - viewStructuredPingData: null, - _archivedPings: null, - - attachObservers: function() { - let elements = document.getElementsByName("choose-ping-source"); - for (let el of elements) { - el.addEventListener("change", () => this.onPingSourceChanged(), false); - } - - let displays = document.getElementsByName("choose-ping-display"); - for (let el of displays) { - el.addEventListener("change", () => this.onPingDisplayChanged(), false); - } - - document.getElementById("show-subsession-data").addEventListener("change", () => { - this._updateCurrentPingData(); - }); - - document.getElementById("choose-ping-week").addEventListener("change", () => { - this._renderPingList(); - this._updateArchivedPingData(); - }, false); - document.getElementById("choose-ping-id").addEventListener("change", () => { - this._updateArchivedPingData() - }, false); - - document.getElementById("newer-ping") - .addEventListener("click", () => this._movePingIndex(-1), false); - document.getElementById("older-ping") - .addEventListener("click", () => this._movePingIndex(1), false); - document.getElementById("choose-payload") - .addEventListener("change", () => displayPingData(gPingData), false); - document.getElementById("histograms-processes") - .addEventListener("change", () => displayPingData(gPingData), false); - document.getElementById("keyed-histograms-processes") - .addEventListener("change", () => displayPingData(gPingData), false); - }, - - onPingSourceChanged: function() { - this.update(); - }, - - onPingDisplayChanged: function() { - this.update(); - }, - - update: Task.async(function*() { - let viewCurrent = document.getElementById("ping-source-current").checked; - let viewStructured = document.getElementById("ping-source-structured").checked; - let currentChanged = viewCurrent !== this.viewCurrentPingData; - let structuredChanged = viewStructured !== this.viewStructuredPingData; - this.viewCurrentPingData = viewCurrent; - this.viewStructuredPingData = viewStructured; - - // If we have no archived pings, disable the ping archive selection. - // This can happen on new profiles or if the ping archive is disabled. - let archivedPingList = yield TelemetryArchive.promiseArchivedPingList(); - let sourceArchived = document.getElementById("ping-source-archive"); - sourceArchived.disabled = (archivedPingList.length == 0); - - if (currentChanged) { - if (this.viewCurrentPingData) { - document.getElementById("current-ping-picker").classList.remove("hidden"); - document.getElementById("archived-ping-picker").classList.add("hidden"); - this._updateCurrentPingData(); - } else { - document.getElementById("current-ping-picker").classList.add("hidden"); - yield this._updateArchivedPingList(archivedPingList); - document.getElementById("archived-ping-picker").classList.remove("hidden"); - } - } - - if (structuredChanged) { - if (this.viewStructuredPingData) { - this._showStructuredPingData(); - } else { - this._showRawPingData(); - } - } - }), - - _updateCurrentPingData: function() { - const subsession = document.getElementById("show-subsession-data").checked; - const ping = TelemetryController.getCurrentPingData(subsession); - if (!ping) { - return; - } - displayPingData(ping, true); - }, - - _updateArchivedPingData: function() { - let id = this._getSelectedPingId(); - return TelemetryArchive.promiseArchivedPingById(id) - .then((ping) => displayPingData(ping, true)); - }, - - _updateArchivedPingList: Task.async(function*(pingList) { - // The archived ping list is sorted in ascending timestamp order, - // but descending is more practical for the operations we do here. - pingList.reverse(); - - this._archivedPings = pingList; - - // Collect the start dates for all the weeks we have pings for. - let weekStart = (date) => { - let weekDay = (date.getDay() + 6) % 7; - let monday = new Date(date); - monday.setDate(date.getDate() - weekDay); - return TelemetryUtils.truncateToDays(monday); - }; - - let weekStartDates = new Set(); - for (let p of pingList) { - weekStartDates.add(weekStart(new Date(p.timestampCreated)).getTime()); - } - - // Build a list of the week date ranges we have ping data for. - let plusOneWeek = (date) => { - let d = date; - d.setDate(d.getDate() + 7); - return d; - }; - - this._weeks = Array.from(weekStartDates.values(), startTime => ({ - startDate: new Date(startTime), - endDate: plusOneWeek(new Date(startTime)), - })); - - // Render the archive data. - this._renderWeeks(); - this._renderPingList(); - - // Update the displayed ping. - yield this._updateArchivedPingData(); - }), - - _renderWeeks: function() { - let weekSelector = document.getElementById("choose-ping-week"); - removeAllChildNodes(weekSelector); - - let index = 0; - for (let week of this._weeks) { - let text = shortDateString(week.startDate) - + " - " + shortDateString(yesterday(week.endDate)); - - let option = document.createElement("option"); - let content = document.createTextNode(text); - option.appendChild(content); - weekSelector.appendChild(option); - } - }, - - _getSelectedWeek: function() { - let weekSelector = document.getElementById("choose-ping-week"); - return this._weeks[weekSelector.selectedIndex]; - }, - - _renderPingList: function(id = null) { - let pingSelector = document.getElementById("choose-ping-id"); - removeAllChildNodes(pingSelector); - - let weekRange = this._getSelectedWeek(); - let pings = this._archivedPings.filter( - (p) => p.timestampCreated >= weekRange.startDate.getTime() && - p.timestampCreated < weekRange.endDate.getTime()); - - for (let p of pings) { - let date = new Date(p.timestampCreated); - let text = shortDateString(date) - + " " + shortTimeString(date) - + " - " + p.type; - - let option = document.createElement("option"); - let content = document.createTextNode(text); - option.appendChild(content); - option.setAttribute("value", p.id); - if (id && p.id == id) { - option.selected = true; - } - pingSelector.appendChild(option); - } - }, - - _getSelectedPingId: function() { - let pingSelector = document.getElementById("choose-ping-id"); - let selected = pingSelector.selectedOptions.item(0); - return selected.getAttribute("value"); - }, - - _movePingIndex: function(offset) { - const id = this._getSelectedPingId(); - const index = this._archivedPings.findIndex((p) => p.id == id); - const newIndex = Math.min(Math.max(index + offset, 0), this._archivedPings.length - 1); - const ping = this._archivedPings[newIndex]; - - const weekIndex = this._weeks.findIndex( - (week) => ping.timestampCreated >= week.startDate.getTime() && - ping.timestampCreated < week.endDate.getTime()); - const options = document.getElementById("choose-ping-week").options; - options.item(weekIndex).selected = true; - - this._renderPingList(ping.id); - this._updateArchivedPingData(); - }, - - _showRawPingData: function() { - document.getElementById("raw-ping-data-section").classList.remove("hidden"); - document.getElementById("structured-ping-data-section").classList.add("hidden"); - }, - - _showStructuredPingData: function() { - document.getElementById("raw-ping-data-section").classList.add("hidden"); - document.getElementById("structured-ping-data-section").classList.remove("hidden"); - }, -}; - -var GeneralData = { - /** - * Renders the general data - */ - render: function(aPing) { - setHasData("general-data-section", true); - let table = document.createElement("table"); - - let caption = document.createElement("caption"); - let captionString = bundle.GetStringFromName("generalDataTitle"); - caption.appendChild(document.createTextNode(captionString + "\n")); - table.appendChild(caption); - - let headings = document.createElement("tr"); - this.appendColumn(headings, "th", bundle.GetStringFromName("generalDataHeadingName") + "\t"); - this.appendColumn(headings, "th", bundle.GetStringFromName("generalDataHeadingValue") + "\t"); - table.appendChild(headings); - - // The payload & environment parts are handled by other renderers. - let ignoreSections = ["payload", "environment"]; - let data = explodeObject(filterObject(aPing, ignoreSections)); - - for (let [path, value] of data) { - let row = document.createElement("tr"); - this.appendColumn(row, "td", path + "\t"); - this.appendColumn(row, "td", value + "\t"); - table.appendChild(row); - } - - let dataDiv = document.getElementById("general-data"); - removeAllChildNodes(dataDiv); - dataDiv.appendChild(table); - }, - - /** - * Helper function for appending a column to the data table. - * - * @param aRowElement Parent row element - * @param aColType Column's tag name - * @param aColText Column contents - */ - appendColumn: function(aRowElement, aColType, aColText) { - let colElement = document.createElement(aColType); - let colTextElement = document.createTextNode(aColText); - colElement.appendChild(colTextElement); - aRowElement.appendChild(colElement); - }, -}; - -var EnvironmentData = { - /** - * Renders the environment data - */ - render: function(ping) { - let dataDiv = document.getElementById("environment-data"); - removeAllChildNodes(dataDiv); - const hasData = !!ping.environment; - setHasData("environment-data-section", hasData); - if (!hasData) { - return; - } - - let data = sectionalizeObject(ping.environment); - - for (let [section, sectionData] of data) { - if (section == "addons") { - break; - } - - let table = document.createElement("table"); - this.appendHeading(table); - - for (let [path, value] of sectionData) { - let row = document.createElement("tr"); - this.appendColumn(row, "td", path); - this.appendColumn(row, "td", value); - table.appendChild(row); - } - - let hasData = sectionData.size > 0; - this.createSubsection(section, hasData, table, dataDiv); - } - - // We use specialized rendering here to make the addon and plugin listings - // more readable. - this.createAddonSection(dataDiv, ping); - }, - - createSubsection: function(title, hasSubdata, subSectionData, dataDiv) { - let dataSection = document.createElement("section"); - dataSection.classList.add("data-subsection"); - - if (hasSubdata) { - dataSection.classList.add("has-subdata"); - } - - // Create section heading - let sectionName = document.createElement("h2"); - sectionName.setAttribute("class", "section-name"); - sectionName.appendChild(document.createTextNode(title)); - sectionName.addEventListener("click", toggleSection, false); - - // Create caption for toggling the subsection visibility. - let toggleCaption = document.createElement("span"); - toggleCaption.setAttribute("class", "toggle-caption"); - let toggleText = bundle.GetStringFromName("environmentDataSubsectionToggle"); - toggleCaption.appendChild(document.createTextNode(" " + toggleText)); - toggleCaption.addEventListener("click", toggleSection, false); - - // Create caption for empty subsections. - let emptyCaption = document.createElement("span"); - emptyCaption.setAttribute("class", "empty-caption"); - let emptyText = bundle.GetStringFromName("environmentDataSubsectionEmpty"); - emptyCaption.appendChild(document.createTextNode(" " + emptyText)); - - // Create data container - let data = document.createElement("div"); - data.setAttribute("class", "subsection-data subdata"); - data.appendChild(subSectionData); - - // Append elements - dataSection.appendChild(sectionName); - dataSection.appendChild(toggleCaption); - dataSection.appendChild(emptyCaption); - dataSection.appendChild(data); - - dataDiv.appendChild(dataSection); - }, - - renderPersona: function(addonObj, addonSection, sectionTitle) { - let table = document.createElement("table"); - table.setAttribute("id", sectionTitle); - this.appendAddonSubsectionTitle(sectionTitle, table); - this.appendRow(table, "persona", addonObj.persona); - addonSection.appendChild(table); - }, - - renderActivePlugins: function(addonObj, addonSection, sectionTitle) { - let data = explodeObject(addonObj); - let table = document.createElement("table"); - table.setAttribute("id", sectionTitle); - this.appendAddonSubsectionTitle(sectionTitle, table); - - for (let plugin of addonObj) { - let data = explodeObject(plugin); - this.appendHeadingName(table, data.get("name")); - - for (let [key, value] of data) { - this.appendRow(table, key, value); - } - } - - addonSection.appendChild(table); - }, - - renderAddonsObject: function(addonObj, addonSection, sectionTitle) { - let table = document.createElement("table"); - table.setAttribute("id", sectionTitle); - this.appendAddonSubsectionTitle(sectionTitle, table); - - for (let id of Object.keys(addonObj)) { - let addon = addonObj[id]; - this.appendHeadingName(table, addon.name || id); - this.appendAddonID(table, id); - let data = explodeObject(addon); - - for (let [key, value] of data) { - this.appendRow(table, key, value); - } - } - - addonSection.appendChild(table); - }, - - renderKeyValueObject: function(addonObj, addonSection, sectionTitle) { - let data = explodeObject(addonObj); - let table = document.createElement("table"); - table.setAttribute("class", sectionTitle); - this.appendAddonSubsectionTitle(sectionTitle, table); - this.appendHeading(table); - - for (let [key, value] of data) { - this.appendRow(table, key, value); - } - - addonSection.appendChild(table); - }, - - appendAddonID: function(table, addonID) { - this.appendRow(table, "id", addonID); - }, - - appendHeading: function(table) { - let headings = document.createElement("tr"); - this.appendColumn(headings, "th", bundle.GetStringFromName("environmentDataHeadingName")); - this.appendColumn(headings, "th", bundle.GetStringFromName("environmentDataHeadingValue")); - table.appendChild(headings); - }, - - appendHeadingName: function(table, name) { - let headings = document.createElement("tr"); - this.appendColumn(headings, "th", name); - headings.cells[0].colSpan = 2; - table.appendChild(headings); - }, - - appendAddonSubsectionTitle: function(section, table) { - let caption = document.createElement("caption"); - caption.setAttribute("class", "addon-caption"); - caption.appendChild(document.createTextNode(section)); - table.appendChild(caption); - }, - - createAddonSection: function(dataDiv, ping) { - let addonSection = document.createElement("div"); - let addons = ping.environment.addons; - this.renderAddonsObject(addons.activeAddons, addonSection, "activeAddons"); - this.renderActivePlugins(addons.activePlugins, addonSection, "activePlugins"); - this.renderKeyValueObject(addons.theme, addonSection, "theme"); - this.renderKeyValueObject(addons.activeExperiment, addonSection, "activeExperiment"); - this.renderAddonsObject(addons.activeGMPlugins, addonSection, "activeGMPlugins"); - this.renderPersona(addons, addonSection, "persona"); - - let hasAddonData = Object.keys(ping.environment.addons).length > 0; - this.createSubsection("addons", hasAddonData, addonSection, dataDiv); - }, - - appendRow: function(table, id, value) { - let row = document.createElement("tr"); - this.appendColumn(row, "td", id); - this.appendColumn(row, "td", value); - table.appendChild(row); - }, - /** - * Helper function for appending a column to the data table. - * - * @param aRowElement Parent row element - * @param aColType Column's tag name - * @param aColText Column contents - */ - appendColumn: function(aRowElement, aColType, aColText) { - let colElement = document.createElement(aColType); - let colTextElement = document.createTextNode(aColText); - colElement.appendChild(colTextElement); - aRowElement.appendChild(colElement); - }, -}; - -var TelLog = { - /** - * Renders the telemetry log - */ - render: function(aPing) { - let entries = aPing.payload.log; - const hasData = entries && entries.length > 0; - setHasData("telemetry-log-section", hasData); - if (!hasData) { - return; - } - - let table = document.createElement("table"); - - let caption = document.createElement("caption"); - let captionString = bundle.GetStringFromName("telemetryLogTitle"); - caption.appendChild(document.createTextNode(captionString + "\n")); - table.appendChild(caption); - - let headings = document.createElement("tr"); - this.appendColumn(headings, "th", bundle.GetStringFromName("telemetryLogHeadingId") + "\t"); - this.appendColumn(headings, "th", bundle.GetStringFromName("telemetryLogHeadingTimestamp") + "\t"); - this.appendColumn(headings, "th", bundle.GetStringFromName("telemetryLogHeadingData") + "\t"); - table.appendChild(headings); - - for (let entry of entries) { - let row = document.createElement("tr"); - for (let elem of entry) { - this.appendColumn(row, "td", elem + "\t"); - } - table.appendChild(row); - } - - let dataDiv = document.getElementById("telemetry-log"); - removeAllChildNodes(dataDiv); - dataDiv.appendChild(table); - }, - - /** - * Helper function for appending a column to the data table. - * - * @param aRowElement Parent row element - * @param aColType Column's tag name - * @param aColText Column contents - */ - appendColumn: function(aRowElement, aColType, aColText) { - let colElement = document.createElement(aColType); - let colTextElement = document.createTextNode(aColText); - colElement.appendChild(colTextElement); - aRowElement.appendChild(colElement); - }, -}; - -var SlowSQL = { - - slowSqlHits: bundle.GetStringFromName("slowSqlHits"), - - slowSqlAverage: bundle.GetStringFromName("slowSqlAverage"), - - slowSqlStatement: bundle.GetStringFromName("slowSqlStatement"), - - mainThreadTitle: bundle.GetStringFromName("slowSqlMain"), - - otherThreadTitle: bundle.GetStringFromName("slowSqlOther"), - - /** - * Render slow SQL statistics - */ - render: function SlowSQL_render(aPing) { - // We can add the debug SQL data to the current ping later. - // However, we need to be careful to never send that debug data - // out due to privacy concerns. - // We want to show the actual ping data for archived pings, - // so skip this there. - let debugSlowSql = PingPicker.viewCurrentPingData && Preferences.get(PREF_DEBUG_SLOW_SQL, false); - let slowSql = debugSlowSql ? Telemetry.debugSlowSQL : aPing.payload.slowSQL; - if (!slowSql) { - setHasData("slow-sql-section", false); - return; - } - - let {mainThread, otherThreads} = - debugSlowSql ? Telemetry.debugSlowSQL : aPing.payload.slowSQL; - - let mainThreadCount = Object.keys(mainThread).length; - let otherThreadCount = Object.keys(otherThreads).length; - if (mainThreadCount == 0 && otherThreadCount == 0) { - setHasData("slow-sql-section", false); - return; - } - - setHasData("slow-sql-section", true); - if (debugSlowSql) { - document.getElementById("sql-warning").classList.remove("hidden"); - } - - let slowSqlDiv = document.getElementById("slow-sql-tables"); - removeAllChildNodes(slowSqlDiv); - - // Main thread - if (mainThreadCount > 0) { - let table = document.createElement("table"); - this.renderTableHeader(table, this.mainThreadTitle); - this.renderTable(table, mainThread); - - slowSqlDiv.appendChild(table); - slowSqlDiv.appendChild(document.createElement("hr")); - } - - // Other threads - if (otherThreadCount > 0) { - let table = document.createElement("table"); - this.renderTableHeader(table, this.otherThreadTitle); - this.renderTable(table, otherThreads); - - slowSqlDiv.appendChild(table); - slowSqlDiv.appendChild(document.createElement("hr")); - } - }, - - /** - * Creates a header row for a Slow SQL table - * Tabs & newlines added to cells to make it easier to copy-paste. - * - * @param aTable Parent table element - * @param aTitle Table's title - */ - renderTableHeader: function SlowSQL_renderTableHeader(aTable, aTitle) { - let caption = document.createElement("caption"); - caption.appendChild(document.createTextNode(aTitle + "\n")); - aTable.appendChild(caption); - - let headings = document.createElement("tr"); - this.appendColumn(headings, "th", this.slowSqlHits + "\t"); - this.appendColumn(headings, "th", this.slowSqlAverage + "\t"); - this.appendColumn(headings, "th", this.slowSqlStatement + "\n"); - aTable.appendChild(headings); - }, - - /** - * Fills out the table body - * Tabs & newlines added to cells to make it easier to copy-paste. - * - * @param aTable Parent table element - * @param aSql SQL stats object - */ - renderTable: function SlowSQL_renderTable(aTable, aSql) { - for (let [sql, [hitCount, totalTime]] of Object.entries(aSql)) { - let averageTime = totalTime / hitCount; - - let sqlRow = document.createElement("tr"); - - this.appendColumn(sqlRow, "td", hitCount + "\t"); - this.appendColumn(sqlRow, "td", averageTime.toFixed(0) + "\t"); - this.appendColumn(sqlRow, "td", sql + "\n"); - - aTable.appendChild(sqlRow); - } - }, - - /** - * Helper function for appending a column to a Slow SQL table. - * - * @param aRowElement Parent row element - * @param aColType Column's tag name - * @param aColText Column contents - */ - appendColumn: function SlowSQL_appendColumn(aRowElement, aColType, aColText) { - let colElement = document.createElement(aColType); - let colTextElement = document.createTextNode(aColText); - colElement.appendChild(colTextElement); - aRowElement.appendChild(colElement); - } -}; - -var StackRenderer = { - - stackTitle: bundle.GetStringFromName("stackTitle"), - - memoryMapTitle: bundle.GetStringFromName("memoryMapTitle"), - - /** - * Outputs the memory map associated with this hang report - * - * @param aDiv Output div - */ - renderMemoryMap: function StackRenderer_renderMemoryMap(aDiv, memoryMap) { - aDiv.appendChild(document.createTextNode(this.memoryMapTitle)); - aDiv.appendChild(document.createElement("br")); - - for (let currentModule of memoryMap) { - aDiv.appendChild(document.createTextNode(currentModule.join(" "))); - aDiv.appendChild(document.createElement("br")); - } - - aDiv.appendChild(document.createElement("br")); - }, - - /** - * Outputs the raw PCs from the hang's stack - * - * @param aDiv Output div - * @param aStack Array of PCs from the hang stack - */ - renderStack: function StackRenderer_renderStack(aDiv, aStack) { - aDiv.appendChild(document.createTextNode(this.stackTitle)); - let stackText = " " + aStack.join(" "); - aDiv.appendChild(document.createTextNode(stackText)); - - aDiv.appendChild(document.createElement("br")); - aDiv.appendChild(document.createElement("br")); - }, - renderStacks: function StackRenderer_renderStacks(aPrefix, aStacks, - aMemoryMap, aRenderHeader) { - let div = document.getElementById(aPrefix + '-data'); - removeAllChildNodes(div); - - let fetchE = document.getElementById(aPrefix + '-fetch-symbols'); - if (fetchE) { - fetchE.classList.remove("hidden"); - } - let hideE = document.getElementById(aPrefix + '-hide-symbols'); - if (hideE) { - hideE.classList.add("hidden"); - } - - if (aStacks.length == 0) { - return; - } - - setHasData(aPrefix + '-section', true); - - this.renderMemoryMap(div, aMemoryMap); - - for (let i = 0; i < aStacks.length; ++i) { - let stack = aStacks[i]; - aRenderHeader(i); - this.renderStack(div, stack) - } - }, - - /** - * Renders the title of the stack: e.g. "Late Write #1" or - * "Hang Report #1 (6 seconds)". - * - * @param aFormatArgs formating args to be passed to formatStringFromName. - */ - renderHeader: function StackRenderer_renderHeader(aPrefix, aFormatArgs) { - let div = document.getElementById(aPrefix + "-data"); - - let titleElement = document.createElement("span"); - titleElement.className = "stack-title"; - - let titleText = bundle.formatStringFromName( - aPrefix + "-title", aFormatArgs, aFormatArgs.length); - titleElement.appendChild(document.createTextNode(titleText)); - - div.appendChild(titleElement); - div.appendChild(document.createElement("br")); - } -}; - -var RawPayload = { - /** - * Renders the raw payload - */ - render: function(aPing) { - setHasData("raw-payload-section", true); - let pre = document.getElementById("raw-payload-data-pre"); - pre.textContent = JSON.stringify(aPing.payload, null, 2); - } -}; - -function SymbolicationRequest(aPrefix, aRenderHeader, - aMemoryMap, aStacks, aDurations = null) { - this.prefix = aPrefix; - this.renderHeader = aRenderHeader; - this.memoryMap = aMemoryMap; - this.stacks = aStacks; - this.durations = aDurations; -} -/** - * A callback for onreadystatechange. It replaces the numeric stack with - * the symbolicated one returned by the symbolication server. - */ -SymbolicationRequest.prototype.handleSymbolResponse = -function SymbolicationRequest_handleSymbolResponse() { - if (this.symbolRequest.readyState != 4) - return; - - let fetchElement = document.getElementById(this.prefix + "-fetch-symbols"); - fetchElement.classList.add("hidden"); - let hideElement = document.getElementById(this.prefix + "-hide-symbols"); - hideElement.classList.remove("hidden"); - let div = document.getElementById(this.prefix + "-data"); - removeAllChildNodes(div); - let errorMessage = bundle.GetStringFromName("errorFetchingSymbols"); - - if (this.symbolRequest.status != 200) { - div.appendChild(document.createTextNode(errorMessage)); - return; - } - - let jsonResponse = {}; - try { - jsonResponse = JSON.parse(this.symbolRequest.responseText); - } catch (e) { - div.appendChild(document.createTextNode(errorMessage)); - return; - } - - for (let i = 0; i < jsonResponse.length; ++i) { - let stack = jsonResponse[i]; - this.renderHeader(i, this.durations); - - for (let symbol of stack) { - div.appendChild(document.createTextNode(symbol)); - div.appendChild(document.createElement("br")); - } - div.appendChild(document.createElement("br")); - } -}; -/** - * Send a request to the symbolication server to symbolicate this stack. - */ -SymbolicationRequest.prototype.fetchSymbols = -function SymbolicationRequest_fetchSymbols() { - let symbolServerURI = - Preferences.get(PREF_SYMBOL_SERVER_URI, DEFAULT_SYMBOL_SERVER_URI); - let request = {"memoryMap" : this.memoryMap, "stacks" : this.stacks, - "version" : 3}; - let requestJSON = JSON.stringify(request); - - this.symbolRequest = new XMLHttpRequest(); - this.symbolRequest.open("POST", symbolServerURI, true); - this.symbolRequest.setRequestHeader("Content-type", "application/json"); - this.symbolRequest.setRequestHeader("Content-length", - requestJSON.length); - this.symbolRequest.setRequestHeader("Connection", "close"); - this.symbolRequest.onreadystatechange = this.handleSymbolResponse.bind(this); - this.symbolRequest.send(requestJSON); -} - -var ChromeHangs = { - - symbolRequest: null, - - /** - * Renders raw chrome hang data - */ - render: function ChromeHangs_render(aPing) { - let hangs = aPing.payload.chromeHangs; - setHasData("chrome-hangs-section", !!hangs); - if (!hangs) { - return; - } - - let stacks = hangs.stacks; - let memoryMap = hangs.memoryMap; - let durations = hangs.durations; - - StackRenderer.renderStacks("chrome-hangs", stacks, memoryMap, - (index) => this.renderHangHeader(index, durations)); - }, - - renderHangHeader: function ChromeHangs_renderHangHeader(aIndex, aDurations) { - StackRenderer.renderHeader("chrome-hangs", [aIndex + 1, aDurations[aIndex]]); - } -}; - -var ThreadHangStats = { - - /** - * Renders raw thread hang stats data - */ - render: function(aPayload) { - let div = document.getElementById("thread-hang-stats"); - removeAllChildNodes(div); - - let stats = aPayload.threadHangStats; - setHasData("thread-hang-stats-section", stats && (stats.length > 0)); - if (!stats) { - return; - } - - stats.forEach((thread) => { - div.appendChild(this.renderThread(thread)); - }); - }, - - /** - * Creates and fills data corresponding to a thread - */ - renderThread: function(aThread) { - let div = document.createElement("div"); - - let title = document.createElement("h2"); - title.textContent = aThread.name; - div.appendChild(title); - - // Don't localize the histogram name, because the - // name is also used as the div element's ID - Histogram.render(div, aThread.name + "-Activity", - aThread.activity, {exponential: true}, true); - aThread.hangs.forEach((hang, index) => { - let hangName = aThread.name + "-Hang-" + (index + 1); - let hangDiv = Histogram.render( - div, hangName, hang.histogram, {exponential: true}, true); - let stackDiv = document.createElement("div"); - let stack = hang.nativeStack || hang.stack; - stack.forEach((frame) => { - stackDiv.appendChild(document.createTextNode(frame)); - // Leave an extra <br> at the end of the stack listing - stackDiv.appendChild(document.createElement("br")); - }); - // Insert stack after the histogram title - hangDiv.insertBefore(stackDiv, hangDiv.childNodes[1]); - }); - return div; - }, -}; - -var Histogram = { - - hgramSamplesCaption: bundle.GetStringFromName("histogramSamples"), - - hgramAverageCaption: bundle.GetStringFromName("histogramAverage"), - - hgramSumCaption: bundle.GetStringFromName("histogramSum"), - - hgramCopyCaption: bundle.GetStringFromName("histogramCopy"), - - /** - * Renders a single Telemetry histogram - * - * @param aParent Parent element - * @param aName Histogram name - * @param aHgram Histogram information - * @param aOptions Object with render options - * * exponential: bars follow logarithmic scale - * @param aIsBHR whether or not requires fixing the labels for TimeHistogram - */ - render: function Histogram_render(aParent, aName, aHgram, aOptions, aIsBHR) { - let options = aOptions || {}; - let hgram = this.processHistogram(aHgram, aName, aIsBHR); - - let outerDiv = document.createElement("div"); - outerDiv.className = "histogram"; - outerDiv.id = aName; - - let divTitle = document.createElement("div"); - divTitle.className = "histogram-title"; - divTitle.appendChild(document.createTextNode(aName)); - outerDiv.appendChild(divTitle); - - let stats = hgram.sample_count + " " + this.hgramSamplesCaption + ", " + - this.hgramAverageCaption + " = " + hgram.pretty_average + ", " + - this.hgramSumCaption + " = " + hgram.sum; - - let divStats = document.createElement("div"); - divStats.appendChild(document.createTextNode(stats)); - outerDiv.appendChild(divStats); - - if (isRTL()) { - hgram.buckets.reverse(); - hgram.values.reverse(); - } - - let textData = this.renderValues(outerDiv, hgram, options); - - // The 'Copy' button contains the textual data, copied to clipboard on click - let copyButton = document.createElement("button"); - copyButton.className = "copy-node"; - copyButton.appendChild(document.createTextNode(this.hgramCopyCaption)); - copyButton.histogramText = aName + EOL + stats + EOL + EOL + textData; - copyButton.addEventListener("click", function() { - Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper) - .copyString(this.histogramText); - }); - outerDiv.appendChild(copyButton); - - aParent.appendChild(outerDiv); - return outerDiv; - }, - - processHistogram: function(aHgram, aName, aIsBHR) { - const values = Object.keys(aHgram.values).map(k => aHgram.values[k]); - if (!values.length) { - // If we have no values collected for this histogram, just return - // zero values so we still render it. - return { - values: [], - pretty_average: 0, - max: 0, - sample_count: 0, - sum: 0 - }; - } - - const sample_count = values.reduceRight((a, b) => a + b); - const average = Math.round(aHgram.sum * 10 / sample_count) / 10; - const max_value = Math.max(...values); - - function labelFunc(k) { - // - BHR histograms are TimeHistograms: Exactly power-of-two buckets (from 0) - // (buckets: [0..1], [2..3], [4..7], [8..15], ... note the 0..1 anomaly - same bucket) - // - TimeHistogram's JS representation adds a dummy (empty) "0" bucket, and - // the rest of the buckets have the label as the upper value of the - // bucket (non TimeHistograms have the lower value of the bucket as label). - // So JS TimeHistograms bucket labels are: 0 (dummy), 1, 3, 7, 15, ... - // - see toolkit/components/telemetry/Telemetry.cpp - // (CreateJSTimeHistogram, CreateJSThreadHangStats, CreateJSHangHistogram) - // - see toolkit/components/telemetry/ThreadHangStats.h - // Fix BHR labels to the "standard" format for about:telemetry as follows: - // - The dummy 0 label+bucket will be filtered before arriving here - // - If it's 1 -> manually correct it to 0 (the 0..1 anomaly) - // - For the rest, set the label as the bottom value instead of the upper. - // --> so we'll end with the following (non dummy) labels: 0, 2, 4, 8, 16, ... - if (!aIsBHR) { - return k; - } - return k == 1 ? 0 : (k + 1) / 2; - } - - const labelledValues = Object.keys(aHgram.values) - .filter(label => !aIsBHR || Number(label) != 0) // remove dummy 0 label for BHR - .map(k => [labelFunc(Number(k)), aHgram.values[k]]); - - let result = { - values: labelledValues, - pretty_average: average, - max: max_value, - sample_count: sample_count, - sum: aHgram.sum - }; - - return result; - }, - - /** - * Return a non-negative, logarithmic representation of a non-negative number. - * e.g. 0 => 0, 1 => 1, 10 => 2, 100 => 3 - * - * @param aNumber Non-negative number - */ - getLogValue: function(aNumber) { - return Math.max(0, Math.log10(aNumber) + 1); - }, - - /** - * Create histogram HTML bars, also returns a textual representation - * Both aMaxValue and aSumValues must be positive. - * Values are assumed to use 0 as baseline. - * - * @param aDiv Outer parent div - * @param aHgram The histogram data - * @param aOptions Object with render options (@see #render) - */ - renderValues: function Histogram_renderValues(aDiv, aHgram, aOptions) { - let text = ""; - // If the last label is not the longest string, alignment will break a little - let labelPadTo = 0; - if (aHgram.values.length) { - labelPadTo = String(aHgram.values[aHgram.values.length - 1][0]).length; - } - let maxBarValue = aOptions.exponential ? this.getLogValue(aHgram.max) : aHgram.max; - - for (let [label, value] of aHgram.values) { - let barValue = aOptions.exponential ? this.getLogValue(value) : value; - - // Create a text representation: <right-aligned-label> |<bar-of-#><value> <percentage> - text += EOL - + " ".repeat(Math.max(0, labelPadTo - String(label).length)) + label // Right-aligned label - + " |" + "#".repeat(Math.round(MAX_BAR_CHARS * barValue / maxBarValue)) // Bar - + " " + value // Value - + " " + Math.round(100 * value / aHgram.sample_count) + "%"; // Percentage - - // Construct the HTML labels + bars - let belowEm = Math.round(MAX_BAR_HEIGHT * (barValue / maxBarValue) * 10) / 10; - let aboveEm = MAX_BAR_HEIGHT - belowEm; - - let barDiv = document.createElement("div"); - barDiv.className = "bar"; - barDiv.style.paddingTop = aboveEm + "em"; - - // Add value label or an nbsp if no value - barDiv.appendChild(document.createTextNode(value ? value : '\u00A0')); - - // Create the blue bar - let bar = document.createElement("div"); - bar.className = "bar-inner"; - bar.style.height = belowEm + "em"; - barDiv.appendChild(bar); - - // Add bucket label - barDiv.appendChild(document.createTextNode(label)); - - aDiv.appendChild(barDiv); - } - - return text.substr(EOL.length); // Trim the EOL before the first line - }, - - /** - * Helper function for filtering histogram elements by their id - * Adds the "filter-blocked" class to histogram nodes whose IDs don't match the filter. - * - * @param aContainerNode Container node containing the histogram class nodes to filter - * @param aFilterText either text or /RegEx/. If text, case-insensitive and AND words - */ - filterHistograms: function _filterHistograms(aContainerNode, aFilterText) { - let filter = aFilterText.toString(); - - // Pass if: all non-empty array items match (case-sensitive) - function isPassText(subject, filter) { - for (let item of filter) { - if (item.length && subject.indexOf(item) < 0) { - return false; // mismatch and not a spurious space - } - } - return true; - } - - function isPassRegex(subject, filter) { - return filter.test(subject); - } - - // Setup normalized filter string (trimmed, lower cased and split on spaces if not RegEx) - let isPassFunc; // filter function, set once, then applied to all elements - filter = filter.trim(); - if (filter[0] != "/") { // Plain text: case insensitive, AND if multi-string - isPassFunc = isPassText; - filter = filter.toLowerCase().split(" "); - } else { - isPassFunc = isPassRegex; - var r = filter.match(/^\/(.*)\/(i?)$/); - try { - filter = RegExp(r[1], r[2]); - } - catch (e) { // Incomplete or bad RegExp - always no match - isPassFunc = function() { - return false; - }; - } - } - - let needLower = (isPassFunc === isPassText); - - let histograms = aContainerNode.getElementsByClassName("histogram"); - for (let hist of histograms) { - hist.classList[isPassFunc((needLower ? hist.id.toLowerCase() : hist.id), filter) ? "remove" : "add"]("filter-blocked"); - } - }, - - /** - * Event handler for change at histograms filter input - * - * When invoked, 'this' is expected to be the filter HTML node. - */ - histogramFilterChanged: function _histogramFilterChanged() { - if (this.idleTimeout) { - clearTimeout(this.idleTimeout); - } - - this.idleTimeout = setTimeout( () => { - Histogram.filterHistograms(document.getElementById(this.getAttribute("target_id")), this.value); - }, FILTER_IDLE_TIMEOUT); - } -}; - -/* - * Helper function to render JS objects with white space between top level elements - * so that they look better in the browser - * @param aObject JavaScript object or array to render - * @return String - */ -function RenderObject(aObject) { - let output = ""; - if (Array.isArray(aObject)) { - if (aObject.length == 0) { - return "[]"; - } - output = "[" + JSON.stringify(aObject[0]); - for (let i = 1; i < aObject.length; i++) { - output += ", " + JSON.stringify(aObject[i]); - } - return output + "]"; - } - let keys = Object.keys(aObject); - if (keys.length == 0) { - return "{}"; - } - output = "{\"" + keys[0] + "\":\u00A0" + JSON.stringify(aObject[keys[0]]); - for (let i = 1; i < keys.length; i++) { - output += ", \"" + keys[i] + "\":\u00A0" + JSON.stringify(aObject[keys[i]]); - } - return output + "}"; -} - -var KeyValueTable = { - /** - * Returns a 2-column table with keys and values - * @param aMeasurements Each key in this JS object is rendered as a row in - * the table with its corresponding value - * @param aKeysLabel Column header for the keys column - * @param aValuesLabel Column header for the values column - */ - render: function KeyValueTable_render(aMeasurements, aKeysLabel, aValuesLabel) { - let table = document.createElement("table"); - this.renderHeader(table, aKeysLabel, aValuesLabel); - this.renderBody(table, aMeasurements); - return table; - }, - - /** - * Create the table header - * Tabs & newlines added to cells to make it easier to copy-paste. - * - * @param aTable Table element - * @param aKeysLabel Column header for the keys column - * @param aValuesLabel Column header for the values column - */ - renderHeader: function KeyValueTable_renderHeader(aTable, aKeysLabel, aValuesLabel) { - let headerRow = document.createElement("tr"); - aTable.appendChild(headerRow); - - let keysColumn = document.createElement("th"); - keysColumn.appendChild(document.createTextNode(aKeysLabel + "\t")); - let valuesColumn = document.createElement("th"); - valuesColumn.appendChild(document.createTextNode(aValuesLabel + "\n")); - - headerRow.appendChild(keysColumn); - headerRow.appendChild(valuesColumn); - }, - - /** - * Create the table body - * Tabs & newlines added to cells to make it easier to copy-paste. - * - * @param aTable Table element - * @param aMeasurements Key/value map - */ - renderBody: function KeyValueTable_renderBody(aTable, aMeasurements) { - for (let [key, value] of Object.entries(aMeasurements)) { - // use .valueOf() to unbox Number, String, etc. objects - if (value && - (typeof value == "object") && - (typeof value.valueOf() == "object")) { - value = RenderObject(value); - } - - let newRow = document.createElement("tr"); - aTable.appendChild(newRow); - - let keyField = document.createElement("td"); - keyField.appendChild(document.createTextNode(key + "\t")); - newRow.appendChild(keyField); - - let valueField = document.createElement("td"); - valueField.appendChild(document.createTextNode(value + "\n")); - newRow.appendChild(valueField); - } - } -}; - -var GenericTable = { - /** - * Returns a n-column table. - * @param rows An array of arrays, each containing data to render - * for one row. - * @param headings The column header strings. - */ - render: function(rows, headings) { - let table = document.createElement("table"); - this.renderHeader(table, headings); - this.renderBody(table, rows); - return table; - }, - - /** - * Create the table header. - * Tabs & newlines added to cells to make it easier to copy-paste. - * - * @param table Table element - * @param headings Array of column header strings. - */ - renderHeader: function(table, headings) { - let headerRow = document.createElement("tr"); - table.appendChild(headerRow); - - for (let i = 0; i < headings.length; ++i) { - let suffix = (i == (headings.length - 1)) ? "\n" : "\t"; - let column = document.createElement("th"); - column.appendChild(document.createTextNode(headings[i] + suffix)); - headerRow.appendChild(column); - } - }, - - /** - * Create the table body - * Tabs & newlines added to cells to make it easier to copy-paste. - * - * @param table Table element - * @param rows An array of arrays, each containing data to render - * for one row. - */ - renderBody: function(table, rows) { - for (let row of rows) { - row = row.map(value => { - // use .valueOf() to unbox Number, String, etc. objects - if (value && - (typeof value == "object") && - (typeof value.valueOf() == "object")) { - return RenderObject(value); - } - return value; - }); - - let newRow = document.createElement("tr"); - table.appendChild(newRow); - - for (let i = 0; i < row.length; ++i) { - let suffix = (i == (row.length - 1)) ? "\n" : "\t"; - let field = document.createElement("td"); - field.appendChild(document.createTextNode(row[i] + suffix)); - newRow.appendChild(field); - } - } - } -}; - -var KeyedHistogram = { - render: function(parent, id, keyedHistogram) { - let outerDiv = document.createElement("div"); - outerDiv.className = "keyed-histogram"; - outerDiv.id = id; - - let divTitle = document.createElement("div"); - divTitle.className = "keyed-histogram-title"; - divTitle.appendChild(document.createTextNode(id)); - outerDiv.appendChild(divTitle); - - for (let [name, hgram] of Object.entries(keyedHistogram)) { - Histogram.render(outerDiv, name, hgram); - } - - parent.appendChild(outerDiv); - return outerDiv; - }, -}; - -var AddonDetails = { - tableIDTitle: bundle.GetStringFromName("addonTableID"), - tableDetailsTitle: bundle.GetStringFromName("addonTableDetails"), - - /** - * Render the addon details section as a series of headers followed by key/value tables - * @param aPing A ping object to render the data from. - */ - render: function AddonDetails_render(aPing) { - let addonSection = document.getElementById("addon-details"); - removeAllChildNodes(addonSection); - let addonDetails = aPing.payload.addonDetails; - const hasData = addonDetails && Object.keys(addonDetails).length > 0; - setHasData("addon-details-section", hasData); - if (!hasData) { - return; - } - - for (let provider in addonDetails) { - let providerSection = document.createElement("h2"); - let titleText = bundle.formatStringFromName("addonProvider", [provider], 1); - providerSection.appendChild(document.createTextNode(titleText)); - addonSection.appendChild(providerSection); - addonSection.appendChild( - KeyValueTable.render(addonDetails[provider], - this.tableIDTitle, this.tableDetailsTitle)); - } - } -}; - -var Scalars = { - /** - * Render the scalar data - if present - from the payload in a simple key-value table. - * @param aPayload A payload object to render the data from. - */ - render: function(aPayload) { - let scalarsSection = document.getElementById("scalars"); - removeAllChildNodes(scalarsSection); - - if (!aPayload.processes || !aPayload.processes.parent) { - return; - } - - let scalars = aPayload.processes.parent.scalars; - const hasData = scalars && Object.keys(scalars).length > 0; - setHasData("scalars-section", hasData); - if (!hasData) { - return; - } - - const headingName = bundle.GetStringFromName("namesHeader"); - const headingValue = bundle.GetStringFromName("valuesHeader"); - const table = KeyValueTable.render(scalars, headingName, headingValue); - scalarsSection.appendChild(table); - } -}; - -var KeyedScalars = { - /** - * Render the keyed scalar data - if present - from the payload in a simple key-value table. - * @param aPayload A payload object to render the data from. - */ - render: function(aPayload) { - let scalarsSection = document.getElementById("keyed-scalars"); - removeAllChildNodes(scalarsSection); - - if (!aPayload.processes || !aPayload.processes.parent) { - return; - } - - let keyedScalars = aPayload.processes.parent.keyedScalars; - const hasData = keyedScalars && Object.keys(keyedScalars).length > 0; - setHasData("keyed-scalars-section", hasData); - if (!hasData) { - return; - } - - const headingName = bundle.GetStringFromName("namesHeader"); - const headingValue = bundle.GetStringFromName("valuesHeader"); - for (let scalar in keyedScalars) { - // Add the name of the scalar. - let scalarNameSection = document.createElement("h2"); - scalarNameSection.appendChild(document.createTextNode(scalar)); - scalarsSection.appendChild(scalarNameSection); - // Populate the section with the key-value pairs from the scalar. - const table = KeyValueTable.render(keyedScalars[scalar], headingName, headingValue); - scalarsSection.appendChild(table); - } - } -}; - -var Events = { - /** - * Render the event data - if present - from the payload in a simple table. - * @param aPayload A payload object to render the data from. - */ - render: function(aPayload) { - let eventsSection = document.getElementById("events"); - removeAllChildNodes(eventsSection); - - if (!aPayload.processes || !aPayload.processes.parent) { - return; - } - - const events = aPayload.processes.parent.events; - const hasData = events && Object.keys(events).length > 0; - setHasData("events-section", hasData); - if (!hasData) { - return; - } - - const headings = [ - "timestamp", - "category", - "method", - "object", - "value", - "extra", - ]; - - const table = GenericTable.render(events, headings); - eventsSection.appendChild(table); - } -}; - -/** - * Helper function for showing either the toggle element or "No data collected" message for a section - * - * @param aSectionID ID of the section element that needs to be changed - * @param aHasData true (default) indicates that toggle should be displayed - */ -function setHasData(aSectionID, aHasData) { - let sectionElement = document.getElementById(aSectionID); - sectionElement.classList[aHasData ? "add" : "remove"]("has-data"); -} - -/** - * Helper function that expands and collapses sections + - * changes caption on the toggle text - */ -function toggleSection(aEvent) { - let parentElement = aEvent.target.parentElement; - if (!parentElement.classList.contains("has-data") && - !parentElement.classList.contains("has-subdata")) { - return; // nothing to toggle - } - - parentElement.classList.toggle("expanded"); - - // Store section opened/closed state in a hidden checkbox (which is then used on reload) - let statebox = parentElement.getElementsByClassName("statebox")[0]; - if (statebox) { - statebox.checked = parentElement.classList.contains("expanded"); - } -} - -/** - * Sets the text of the page header based on a config pref + bundle strings - */ -function setupPageHeader() -{ - let serverOwner = Preferences.get(PREF_TELEMETRY_SERVER_OWNER, "Mozilla"); - let brandName = brandBundle.GetStringFromName("brandFullName"); - let subtitleText = bundle.formatStringFromName( - "pageSubtitle", [serverOwner, brandName], 2); - - let subtitleElement = document.getElementById("page-subtitle"); - subtitleElement.appendChild(document.createTextNode(subtitleText)); -} - -/** - * Initializes load/unload, pref change and mouse-click listeners - */ -function setupListeners() { - Settings.attachObservers(); - PingPicker.attachObservers(); - - // Clean up observers when page is closed - window.addEventListener("unload", - function unloadHandler(aEvent) { - window.removeEventListener("unload", unloadHandler); - Settings.detachObservers(); - }, false); - - document.getElementById("chrome-hangs-fetch-symbols").addEventListener("click", - function () { - if (!gPingData) { - return; - } - - let hangs = gPingData.payload.chromeHangs; - let req = new SymbolicationRequest("chrome-hangs", - ChromeHangs.renderHangHeader, - hangs.memoryMap, - hangs.stacks, - hangs.durations); - req.fetchSymbols(); - }, false); - - document.getElementById("chrome-hangs-hide-symbols").addEventListener("click", - function () { - if (!gPingData) { - return; - } - - ChromeHangs.render(gPingData); - }, false); - - document.getElementById("late-writes-fetch-symbols").addEventListener("click", - function () { - if (!gPingData) { - return; - } - - let lateWrites = gPingData.payload.lateWrites; - let req = new SymbolicationRequest("late-writes", - LateWritesSingleton.renderHeader, - lateWrites.memoryMap, - lateWrites.stacks); - req.fetchSymbols(); - }, false); - - document.getElementById("late-writes-hide-symbols").addEventListener("click", - function () { - if (!gPingData) { - return; - } - - LateWritesSingleton.renderLateWrites(gPingData.payload.lateWrites); - }, false); - - // Clicking on the section name will toggle its state - let sectionHeaders = document.getElementsByClassName("section-name"); - for (let sectionHeader of sectionHeaders) { - sectionHeader.addEventListener("click", toggleSection, false); - } - - // Clicking on the "toggle" text will also toggle section's state - let toggleLinks = document.getElementsByClassName("toggle-caption"); - for (let toggleLink of toggleLinks) { - toggleLink.addEventListener("click", toggleSection, false); - } -} - -function onLoad() { - window.removeEventListener("load", onLoad); - - // Set the text in the page header - setupPageHeader(); - - // Set up event listeners - setupListeners(); - - // Render settings. - Settings.render(); - - // Restore sections states - let stateboxes = document.getElementsByClassName("statebox"); - for (let box of stateboxes) { - if (box.checked) { // Was open. Will still display as empty if not has-data - box.parentElement.classList.add("expanded"); - } - } - - // Update ping data when async Telemetry init is finished. - Telemetry.asyncFetchTelemetryData(() => PingPicker.update()); -} - -var LateWritesSingleton = { - renderHeader: function LateWritesSingleton_renderHeader(aIndex) { - StackRenderer.renderHeader("late-writes", [aIndex + 1]); - }, - - renderLateWrites: function LateWritesSingleton_renderLateWrites(lateWrites) { - setHasData("late-writes-section", !!lateWrites); - if (!lateWrites) { - return; - } - - let stacks = lateWrites.stacks; - let memoryMap = lateWrites.memoryMap; - StackRenderer.renderStacks('late-writes', stacks, memoryMap, - LateWritesSingleton.renderHeader); - } -}; - -/** - * Helper function for sorting the startup milestones in the Simple Measurements - * section into temporal order. - * - * @param aSimpleMeasurements Telemetry ping's "Simple Measurements" data - * @return Sorted measurements - */ -function sortStartupMilestones(aSimpleMeasurements) { - const telemetryTimestamps = TelemetryTimestamps.get(); - let startupEvents = Services.startup.getStartupInfo(); - delete startupEvents['process']; - - function keyIsMilestone(k) { - return (k in startupEvents) || (k in telemetryTimestamps); - } - - let sortedKeys = Object.keys(aSimpleMeasurements); - - // Sort the measurements, with startup milestones at the front + ordered by time - sortedKeys.sort(function keyCompare(keyA, keyB) { - let isKeyAMilestone = keyIsMilestone(keyA); - let isKeyBMilestone = keyIsMilestone(keyB); - - // First order by startup vs non-startup measurement - if (isKeyAMilestone && !isKeyBMilestone) - return -1; - if (!isKeyAMilestone && isKeyBMilestone) - return 1; - // Don't change order of non-startup measurements - if (!isKeyAMilestone && !isKeyBMilestone) - return 0; - - // If both keys are startup measurements, order them by value - return aSimpleMeasurements[keyA] - aSimpleMeasurements[keyB]; - }); - - // Insert measurements into a result object in sort-order - let result = {}; - for (let key of sortedKeys) { - result[key] = aSimpleMeasurements[key]; - } - - return result; -} - -function renderProcessList(ping, selectEl) { - removeAllChildNodes(selectEl); - let option = document.createElement("option"); - option.appendChild(document.createTextNode("parent")); - option.setAttribute("value", ""); - option.selected = true; - selectEl.appendChild(option); - - if (!("processes" in ping.payload)) { - selectEl.disabled = true; - return; - } - selectEl.disabled = false; - - for (let process of Object.keys(ping.payload.processes)) { - // TODO: parent hgrams are on root payload, not in payload.processes.parent - // When/If that gets moved, you'll need to remove this: - if (process === "parent") { - continue; - } - option = document.createElement("option"); - option.appendChild(document.createTextNode(process)); - option.setAttribute("value", process); - selectEl.appendChild(option); - } -} - -function renderPayloadList(ping) { - // Rebuild the payload select with options: - // Parent Payload (selected) - // Child Payload 1..ping.payload.childPayloads.length - let listEl = document.getElementById("choose-payload"); - removeAllChildNodes(listEl); - - let option = document.createElement("option"); - let text = bundle.GetStringFromName("parentPayload"); - let content = document.createTextNode(text); - let payloadIndex = 0; - option.appendChild(content); - option.setAttribute("value", payloadIndex++); - option.selected = true; - listEl.appendChild(option); - - if (!ping.payload.childPayloads) { - listEl.disabled = true; - return - } - listEl.disabled = false; - - for (; payloadIndex <= ping.payload.childPayloads.length; ++payloadIndex) { - option = document.createElement("option"); - text = bundle.formatStringFromName("childPayloadN", [payloadIndex], 1); - content = document.createTextNode(text); - option.appendChild(content); - option.setAttribute("value", payloadIndex); - listEl.appendChild(option); - } -} - -function toggleElementHidden(element, isHidden) { - if (isHidden) { - element.classList.add("hidden"); - } else { - element.classList.remove("hidden"); - } -} - -function togglePingSections(isMainPing) { - // We always show the sections that are "common" to all pings. - // The raw payload section is only used for pings other than "main" and "saved-session". - let commonSections = new Set(["general-data-section", "environment-data-section"]); - let otherPingSections = new Set(["raw-payload-section"]); - - let elements = document.getElementById("structured-ping-data-section").children; - for (let section of elements) { - if (commonSections.has(section.id)) { - continue; - } - - let showElement = isMainPing != otherPingSections.has(section.id); - toggleElementHidden(section, !showElement); - } -} - -function displayPingData(ping, updatePayloadList = false) { - gPingData = ping; - - // Render raw ping data. - let pre = document.getElementById("raw-ping-data"); - pre.textContent = JSON.stringify(gPingData, null, 2); - - // Update the structured data rendering. - const keysHeader = bundle.GetStringFromName("keysHeader"); - const valuesHeader = bundle.GetStringFromName("valuesHeader"); - - // Update the payload list and process lists - if (updatePayloadList) { - renderPayloadList(ping); - renderProcessList(ping, document.getElementById("histograms-processes")); - renderProcessList(ping, document.getElementById("keyed-histograms-processes")); - } - - // Show general data. - GeneralData.render(ping); - - // Show environment data. - EnvironmentData.render(ping); - - // We only have special rendering code for the payloads from "main" pings. - // For any other pings we just render the raw JSON payload. - let isMainPing = (ping.type == "main" || ping.type == "saved-session"); - togglePingSections(isMainPing); - - if (!isMainPing) { - RawPayload.render(ping); - return; - } - - // Show telemetry log. - TelLog.render(ping); - - // Show slow SQL stats - SlowSQL.render(ping); - - // Show chrome hang stacks - ChromeHangs.render(ping); - - // Render Addon details. - AddonDetails.render(ping); - - // Select payload to render - let payloadSelect = document.getElementById("choose-payload"); - let payloadOption = payloadSelect.selectedOptions.item(0); - let payloadIndex = payloadOption.getAttribute("value"); - - let payload = ping.payload; - if (payloadIndex > 0) { - payload = ping.payload.childPayloads[payloadIndex - 1]; - } - - // Show thread hang stats - ThreadHangStats.render(payload); - - // Show simple measurements - let simpleMeasurements = sortStartupMilestones(payload.simpleMeasurements); - let hasData = Object.keys(simpleMeasurements).length > 0; - setHasData("simple-measurements-section", hasData); - let simpleSection = document.getElementById("simple-measurements"); - removeAllChildNodes(simpleSection); - - if (hasData) { - simpleSection.appendChild(KeyValueTable.render(simpleMeasurements, - keysHeader, valuesHeader)); - } - - LateWritesSingleton.renderLateWrites(payload.lateWrites); - - // Show basic session info gathered - hasData = Object.keys(ping.payload.info).length > 0; - setHasData("session-info-section", hasData); - let infoSection = document.getElementById("session-info"); - removeAllChildNodes(infoSection); - - if (hasData) { - infoSection.appendChild(KeyValueTable.render(ping.payload.info, - keysHeader, valuesHeader)); - } - - // Show scalar data. - Scalars.render(payload); - KeyedScalars.render(payload); - - // Show histogram data - let hgramDiv = document.getElementById("histograms"); - removeAllChildNodes(hgramDiv); - - let histograms = payload.histograms; - - let hgramsSelect = document.getElementById("histograms-processes"); - let hgramsOption = hgramsSelect.selectedOptions.item(0); - let hgramsProcess = hgramsOption.getAttribute("value"); - if (hgramsProcess && - "processes" in ping.payload && - hgramsProcess in ping.payload.processes) { - histograms = ping.payload.processes[hgramsProcess].histograms; - } - - hasData = Object.keys(histograms).length > 0; - setHasData("histograms-section", hasData || hgramsSelect.options.length); - - if (hasData) { - for (let [name, hgram] of Object.entries(histograms)) { - Histogram.render(hgramDiv, name, hgram, {unpacked: true}); - } - - let filterBox = document.getElementById("histograms-filter"); - filterBox.addEventListener("input", Histogram.histogramFilterChanged, false); - if (filterBox.value.trim() != "") { // on load, no need to filter if empty - Histogram.filterHistograms(hgramDiv, filterBox.value); - } - - setHasData("histograms-section", true); - } - - // Show keyed histogram data - let keyedDiv = document.getElementById("keyed-histograms"); - removeAllChildNodes(keyedDiv); - - let keyedHistograms = payload.keyedHistograms; - - let keyedHgramsSelect = document.getElementById("keyed-histograms-processes"); - let keyedHgramsOption = keyedHgramsSelect.selectedOptions.item(0); - let keyedHgramsProcess = keyedHgramsOption.getAttribute("value"); - if (keyedHgramsProcess && - "processes" in ping.payload && - keyedHgramsProcess in ping.payload.processes) { - keyedHistograms = ping.payload.processes[keyedHgramsProcess].keyedHistograms; - } - - setHasData("keyed-histograms-section", keyedHgramsSelect.options.length); - if (keyedHistograms) { - let hasData = false; - for (let [id, keyed] of Object.entries(keyedHistograms)) { - if (Object.keys(keyed).length > 0) { - hasData = true; - KeyedHistogram.render(keyedDiv, id, keyed, {unpacked: true}); - } - } - setHasData("keyed-histograms-section", hasData || keyedHgramsSelect.options.length); - } - - // Show event data. - Events.render(payload); - - // Show addon histogram data - let addonDiv = document.getElementById("addon-histograms"); - removeAllChildNodes(addonDiv); - - let addonHistogramsRendered = false; - let addonData = payload.addonHistograms; - if (addonData) { - for (let [addon, histograms] of Object.entries(addonData)) { - for (let [name, hgram] of Object.entries(histograms)) { - addonHistogramsRendered = true; - Histogram.render(addonDiv, addon + ": " + name, hgram, {unpacked: true}); - } - } - } - - setHasData("addon-histograms-section", addonHistogramsRendered); -} - -window.addEventListener("load", onLoad, false); diff --git a/toolkit/content/aboutTelemetry.xhtml b/toolkit/content/aboutTelemetry.xhtml deleted file mode 100644 index 24b78b9933..0000000000 --- a/toolkit/content/aboutTelemetry.xhtml +++ /dev/null @@ -1,290 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD; - <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD; - <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD; - <!ENTITY % aboutTelemetryDTD SYSTEM "chrome://global/locale/aboutTelemetry.dtd"> %aboutTelemetryDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <title>&aboutTelemetry.pageTitle;</title> - - <link rel="stylesheet" href="chrome://global/content/aboutTelemetry.css" - type="text/css"/> - - <script type="application/javascript;version=1.7" - src="chrome://global/content/aboutTelemetry.js"/> - </head> - - <body dir="&locale.dir;"> - - <header id="page-description"> - <h1>&aboutTelemetry.pageTitle;</h1> - - <h2 id="page-subtitle"></h2> - - <table id="settings"> - <tr> - <td> - <p id="description-upload-enabled" class="description-enabled">&aboutTelemetry.uploadEnabled;</p> - <p id="description-upload-disabled" class="description-disabled">&aboutTelemetry.uploadDisabled;</p> - </td> - <td> - <a href="" class="change-data-choices-link">&aboutTelemetry.changeDataChoices;</a> - </td> - </tr> - <tr> - <td> - <p id="description-extended-recording-enabled" class="description-enabled">&aboutTelemetry.extendedRecordingEnabled;</p> - <p id="description-extended-recording-disabled" class="description-disabled">&aboutTelemetry.extendedRecordingDisabled;</p> - </td> - <td> - <a href="" class="change-data-choices-link">&aboutTelemetry.changeDataChoices;</a> - </td> - </tr> - </table> - - <div id="ping-picker"> - <div id="ping-source-picker"> - &aboutTelemetry.pingDataSource;<br/> - <input type="radio" id="ping-source-current" name="choose-ping-source" value="current" checked="checked" /> - &aboutTelemetry.showCurrentPingData;<br /> - <input type="radio" id="ping-source-archive" name="choose-ping-source" value="archive" /> - &aboutTelemetry.showArchivedPingData;<br /> - </div> - <div id="ping-source-picker"> - &aboutTelemetry.pingDataDisplay;<br/> - <input type="radio" id="ping-source-structured" name="choose-ping-display" value="structured" checked="checked" /> - &aboutTelemetry.structured;<br /> - <input type="radio" id="ping-source-raw" name="choose-ping-display" value="raw" /> - &aboutTelemetry.raw;<br /> - </div> - <div id="current-ping-picker"> - <input id="show-subsession-data" type="checkbox" checked="checked" />&aboutTelemetry.showSubsessionData; - </div> - <div id="archived-ping-picker" class="hidden"> - &aboutTelemetry.choosePing;<br /> - <button id="newer-ping" type="button">&aboutTelemetry.showNewerPing;</button> - <button id="older-ping" type="button">&aboutTelemetry.showOlderPing;</button><br /> - <table> - <tr> - <th>&aboutTelemetry.archiveWeekHeader;</th> - <th>&aboutTelemetry.archivePingHeader;</th> - </tr> - <tr> - <td> - <select id="choose-ping-week"> - </select> - </td> - <td> - <select id="choose-ping-id"> - </select> - </td> - </tr> - </table> - </div> - <table> - <tr> - <th>&aboutTelemetry.payloadChoiceHeader;</th> - </tr> - <tr> - <td> - <select id="choose-payload"> - </select> - </td> - </tr> - </table> - </div> - </header> - - <div id="raw-ping-data-section" class="hidden"> - <pre id="raw-ping-data"></pre> - </div> - - <div id="structured-ping-data-section"> - <section id="general-data-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.generalDataSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="general-data" class="data"> - </div> - </section> - - <section id="environment-data-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.environmentDataSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="environment-data" class="data"> - </div> - </section> - - <section id="session-info-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.sessionInfoSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="session-info" class="data"> - </div> - </section> - - <section id="scalars-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.scalarsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="scalars" class="data"> - </div> - </section> - - <section id="keyed-scalars-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.keyedScalarsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="keyed-scalars" class="data"> - </div> - </section> - - <section id="histograms-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.histogramsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <span class="filter-ui"> - &aboutTelemetry.filterText; <input type="text" class="filter" id="histograms-filter" target_id="histograms"/> - </span> - <div class="processes-ui"> - <select id="histograms-processes" class="process-picker"></select> - </div> - <div id="histograms" class="data"> - </div> - </section> - - <section id="keyed-histograms-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.keyedHistogramsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div class="processes-ui"> - <select id="keyed-histograms-processes" class="process-picker"></select> - </div> - <div id="keyed-histograms" class="data"> - </div> - </section> - - <section id="events-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">Events</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="events" class="data"> - </div> - </section> - - <section id="simple-measurements-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.simpleMeasurementsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="simple-measurements" class="data"> - </div> - </section> - - <section id="telemetry-log-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.telemetryLogSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="telemetry-log" class="data"> - </div> - </section> - - <section id="slow-sql-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.slowSqlSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="slow-sql-tables" class="data"> - <p id="sql-warning" class="hidden">&aboutTelemetry.fullSqlWarning;</p> - </div> - </section> - - <section id="chrome-hangs-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.chromeHangsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="chrome-hangs" class="data"> - <a id="chrome-hangs-fetch-symbols" href="#">&aboutTelemetry.fetchSymbols;</a> - <a id="chrome-hangs-hide-symbols" class="hidden" href="#">&aboutTelemetry.hideSymbols;</a> - <br/> - <br/> - <div id="chrome-hangs-data"> - </div> - </div> - </section> - - <section id="thread-hang-stats-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.threadHangStatsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="thread-hang-stats" class="data"> - </div> - </section> - - <section id="late-writes-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.lateWritesSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="late-writes" class="data"> - <a id="late-writes-fetch-symbols" href="#">&aboutTelemetry.fetchSymbols;</a> - <a id="late-writes-hide-symbols" class="hidden" href="#">&aboutTelemetry.hideSymbols;</a> - <br/> - <br/> - <div id="late-writes-data"> - </div> - </div> - </section> - - <section id="addon-details-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.addonDetailsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="addon-details" class="data"> - </div> - </section> - - <section id="addon-histograms-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.addonHistogramsSection;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="addon-histograms" class="data"> - </div> - </section> - - <section id="raw-payload-section" class="data-section"> - <input type="checkbox" class="statebox"/> - <h1 class="section-name">&aboutTelemetry.rawPayload;</h1> - <span class="toggle-caption">&aboutTelemetry.toggle;</span> - <span class="empty-caption">&aboutTelemetry.emptySection;</span> - <div id="raw-payload-data" class="data"> - <pre id="raw-payload-data-pre"></pre> - </div> - </section> - </div> - - </body> - -</html> diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index 7a1ce80b9a..1f1c880397 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -30,9 +30,6 @@ toolkit.jar: #endif * content/global/aboutSupport.js * content/global/aboutSupport.xhtml - content/global/aboutTelemetry.js - content/global/aboutTelemetry.xhtml - content/global/aboutTelemetry.css content/global/directionDetector.html content/global/plugins.html content/global/plugins.css diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm index f69daa0eb9..aef5c6acba 100644 --- a/toolkit/mozapps/extensions/AddonManager.jsm +++ b/toolkit/mozapps/extensions/AddonManager.jsm @@ -168,7 +168,6 @@ function safeCall(aCallback, ...aArgs) { */ function reportProviderError(aProvider, aMethod, aError) { let method = `provider ${providerName(aProvider)}.${aMethod}`; - AddonManagerPrivate.recordException("AMI", method, aError); logger.error("Exception calling " + method, aError); } @@ -631,12 +630,6 @@ var AddonManagerInternal = { providerShutdowns: new Map(), types: {}, startupChanges: {}, - // Store telemetry details per addon provider - telemetryDetails: {}, - - recordTimestamp: function(name, value) { - this.TelemetryTimestamps.add(name, value); - }, validateBlocklist: function() { let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]); @@ -748,7 +741,6 @@ var AddonManagerInternal = { }) .catch(err => { logger.warn("Failure during shutdown of " + name, err); - AddonManagerPrivate.recordException("AMI", "Async shutdown of " + name, err); }); }; logger.debug("Registering shutdown blocker for " + name); @@ -770,12 +762,6 @@ var AddonManagerInternal = { if (gStarted) return; - this.recordTimestamp("AMI_startup_begin"); - - // clear this for xpcshell test restarts - for (let provider in this.telemetryDetails) - delete this.telemetryDetails[provider]; - let appChanged = undefined; let oldAppVersion = null; @@ -822,7 +808,6 @@ var AddonManagerInternal = { Services.prefs.addObserver(PREF_EM_AUTOUPDATE_DEFAULT, this, false); let defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED, true); - AddonManagerPrivate.recordSimpleMeasure("default_providers", defaultProvidersEnabled); // Ensure all default providers have had a chance to register themselves if (defaultProvidersEnabled) { @@ -836,12 +821,10 @@ var AddonManagerInternal = { if ((syms.length < 1) || (typeof scope[syms[0]].startup != "function")) { logger.warn("Provider " + url + " has no startup()"); - AddonManagerPrivate.recordException("AMI", "provider " + url, "no startup()"); } logger.debug("Loaded provider scope for " + url + ": " + Object.keys(scope).toSource()); } catch (e) { - AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); logger.error("Exception loading default provider \"" + url + "\"", e); } }; @@ -860,7 +843,6 @@ var AddonManagerInternal = { logger.debug(`Loaded provider scope for ${url}`); } catch (e) { - AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); logger.error("Exception loading provider " + entry + " from category \"" + url + "\"", e); } @@ -886,11 +868,9 @@ var AddonManagerInternal = { } gStartupComplete = true; - this.recordTimestamp("AMI_startup_end"); } catch (e) { logger.error("startup failed", e); - AddonManagerPrivate.recordException("AMI", "startup failed", e); } logger.debug("Completed startup sequence"); @@ -1105,7 +1085,6 @@ var AddonManagerInternal = { catch(err) { savedError = err; logger.error("Failure during wait for shutdown barrier", err); - AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonManager providers", err); } } @@ -1118,7 +1097,6 @@ var AddonManagerInternal = { catch(err) { savedError = err; logger.error("Failure during AddonRepository shutdown", err); - AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonRepository", err); } logger.debug("Async provider shutdown done"); @@ -2518,56 +2496,6 @@ this.AddonManagerPrivate = { AddonType: AddonType, - recordTimestamp: function(name, value) { - AddonManagerInternal.recordTimestamp(name, value); - }, - - _simpleMeasures: {}, - recordSimpleMeasure: function(name, value) { - this._simpleMeasures[name] = value; - }, - - recordException: function(aModule, aContext, aException) { - let report = { - module: aModule, - context: aContext - }; - - if (typeof aException == "number") { - report.message = Components.Exception("", aException).name; - } - else { - report.message = aException.toString(); - if (aException.fileName) { - report.file = aException.fileName; - report.line = aException.lineNumber; - } - } - - this._simpleMeasures.exception = report; - }, - - getSimpleMeasures: function() { - return this._simpleMeasures; - }, - - getTelemetryDetails: function() { - return AddonManagerInternal.telemetryDetails; - }, - - setTelemetryDetails: function(aProvider, aDetails) { - AddonManagerInternal.telemetryDetails[aProvider] = aDetails; - }, - - // Start a timer, record a simple measure of the time interval when - // timer.done() is called - simpleTimer: function(aName) { - let startTime = Cu.now(); - return { - done: () => this.recordSimpleMeasure(aName, Math.round(Cu.now() - startTime)) - }; - }, - /** * Helper to call update listeners when no update is available. * @@ -2969,7 +2897,6 @@ this.AddonManager = { }; // load the timestamps module into AddonManagerInternal -Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", AddonManagerInternal); Object.freeze(AddonManagerInternal); Object.freeze(AddonManagerPrivate); Object.freeze(AddonManager); diff --git a/toolkit/mozapps/extensions/content/update.js b/toolkit/mozapps/extensions/content/update.js index afc74dca8e..98495b4266 100644 --- a/toolkit/mozapps/extensions/content/update.js +++ b/toolkit/mozapps/extensions/content/update.js @@ -243,17 +243,6 @@ var gVersionInfoPage = { onAllUpdatesFinished: function gVersionInfoPage_onAllUpdatesFinished() { AddonManager.removeAddonListener(listener); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_disabled", - gUpdateWizard.disabled); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_metadata_enabled", - gUpdateWizard.metadataEnabled); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_metadata_disabled", - gUpdateWizard.metadataDisabled); - // Record 0 for these here in case we exit early; values will be replaced - // later if we actually upgrade any. - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgraded", 0); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeFailed", 0); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeDeclined", 0); // Filter out any add-ons that are now enabled. // Tycho: // logger.debug("VersionInfo updates finished: found " + @@ -563,12 +552,6 @@ var gInstallingPage = { if (this._installs.length == this._currentInstall) { Services.obs.notifyObservers(null, "TEST:all-updates-done", null); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgraded", - gUpdateWizard.upgraded); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeFailed", - gUpdateWizard.upgradeFailed); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeDeclined", - gUpdateWizard.upgradeDeclined); this._installing = false; if (gUpdateWizard.shuttingDown) { return; diff --git a/toolkit/mozapps/extensions/internal/GMPProvider.jsm b/toolkit/mozapps/extensions/internal/GMPProvider.jsm index 2ebde08bb1..c894271018 100644 --- a/toolkit/mozapps/extensions/internal/GMPProvider.jsm +++ b/toolkit/mozapps/extensions/internal/GMPProvider.jsm @@ -454,7 +454,6 @@ var GMPProvider = { configureLogging(); this._log = Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP", "GMPProvider."); - let telemetry = {}; this.buildPluginList(); this.ensureProperCDMInstallState(); @@ -476,14 +475,6 @@ var GMPProvider = { e.name + " - sandboxing not available?", e); } } - - if (this.isEnabled) { - telemetry[id] = { - userDisabled: wrapper.userDisabled, - version: wrapper.version, - applyBackgroundUpdates: wrapper.applyBackgroundUpdates, - }; - } } if (Preferences.get(GMPPrefs.KEY_EME_ENABLED, false)) { @@ -500,8 +491,6 @@ var GMPProvider = { this._log.warn("startup - adding clearkey CDM failed", e); } } - - AddonManagerPrivate.setTelemetryDetails("GMP", telemetry); }, shutdown: function() { diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 02275b8c49..eb4e54720a 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -201,7 +201,7 @@ const RESTARTLESS_TYPES = new Set([ "locale", ]); -// Keep track of where we are in startup for telemetry +// Keep track of where we are in startup. // event happened during XPIDatabase.startup() const XPI_STARTING = "XPIStarting"; // event happened after startup() but before the final-ui-startup event @@ -1828,13 +1828,11 @@ this.XPIProvider = { allAppGlobal: true, // A string listing the enabled add-ons for annotating crash reports enabledAddons: null, - // Keep track of startup phases for telemetry + // Keep track of startup phases. runPhase: XPI_STARTING, // Keep track of the newest file in each add-on, in case we want to - // report it to telemetry. + // report it. _mostRecentlyModifiedFile: {}, - // Per-addon telemetry information - _telemetryDetails: {}, // Experiments are disabled by default. Track ones that are locally enabled. _enabledExperiments: null, // A Map from an add-on install to its ID @@ -2004,8 +2002,6 @@ this.XPIProvider = { } try { - AddonManagerPrivate.recordTimestamp("XPI_startup_begin"); - logger.debug("startup"); this.runPhase = XPI_STARTING; this.installs = []; @@ -2013,8 +2009,6 @@ this.XPIProvider = { this.installLocationsByName = {}; // Hook for tests to detect when saving database at shutdown time fails this._shutdownError = null; - // Clear this at startup for xpcshell test restarts - this._telemetryDetails = {}; // Clear the set of enabled experiments (experiments disabled by default). this._enabledExperiments = new Set(); @@ -2139,21 +2133,7 @@ this.XPIProvider = { this.enabledAddons = Preferences.get(PREF_EM_ENABLED_ADDONS, ""); - if ("nsICrashReporter" in Ci && - Services.appinfo instanceof Ci.nsICrashReporter) { - // Annotate the crash report with relevant add-on information. - try { - Services.appinfo.annotateCrashReport("Theme", this.currentSkin); - } catch (e) { } - try { - Services.appinfo.annotateCrashReport("EMCheckCompatibility", - AddonManager.checkCompatibility); - } catch (e) { } - this.addAddonsToCrashReporter(); - } - try { - AddonManagerPrivate.recordTimestamp("XPI_bootstrap_addons_begin"); for (let id in this.bootstrappedAddons) { try { let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); @@ -2172,11 +2152,9 @@ this.XPIProvider = { this.bootstrappedAddons[id].descriptor, e); } } - AddonManagerPrivate.recordTimestamp("XPI_bootstrap_addons_end"); } catch (e) { logger.error("bootstrap startup failed", e); - AddonManagerPrivate.recordException("XPI-BOOTSTRAP", "startup failed", e); } // Let these shutdown a little earlier when they still have access to most @@ -2195,23 +2173,11 @@ this.XPIProvider = { } }, "quit-application-granted", false); - // Detect final-ui-startup for telemetry reporting - Services.obs.addObserver({ - observe: function uiStartupObserver(aSubject, aTopic, aData) { - AddonManagerPrivate.recordTimestamp("XPI_finalUIStartup"); - XPIProvider.runPhase = XPI_AFTER_UI_STARTUP; - Services.obs.removeObserver(this, "final-ui-startup"); - } - }, "final-ui-startup", false); - - AddonManagerPrivate.recordTimestamp("XPI_startup_end"); - this.extensionsActive = true; this.runPhase = XPI_BEFORE_UI_STARTUP; } catch (e) { logger.error("startup failed", e); - AddonManagerPrivate.recordException("XPI", "startup failed", e); } }, @@ -2235,7 +2201,6 @@ this.XPIProvider = { // If there are pending operations then we must update the list of active // add-ons if (Preferences.get(PREF_PENDING_OPERATIONS, false)) { - AddonManagerPrivate.recordSimpleMeasure("XPIDB_pending_ops", 1); XPIDatabase.updateActiveAddons(); Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, !XPIDatabase.writeAddonsList()); @@ -2302,11 +2267,8 @@ this.XPIProvider = { * to be updated, but the metadata check needs to be performed. */ shouldForceUpdateCheck: function XPI_shouldForceUpdateCheck(aAppChanged) { - AddonManagerPrivate.recordSimpleMeasure("XPIDB_metadata_age", AddonRepository.metadataAge()); - let startupChanges = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED); logger.debug("shouldForceUpdateCheck startupChanges: " + startupChanges.toSource()); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_disabled", startupChanges.length); let forceUpdate = []; if (startupChanges.length > 0) { @@ -2400,10 +2362,6 @@ this.XPIProvider = { Services.appinfo.annotateCrashReport("Add-ons", data); } catch (e) { } - - let TelemetrySession = - Cu.import("resource://gre/modules/TelemetrySession.jsm", {}).TelemetrySession; - TelemetrySession.setAddOns(data); }, /** @@ -3549,11 +3507,7 @@ this.XPIProvider = { } } - // Telemetry probe added around getInstallState() to check perf - let telemetryCaptureTime = Cu.now(); let installChanged = XPIStates.getInstallState(); - let telemetry = Services.telemetry; - telemetry.getHistogramById("CHECK_ADDONS_MODIFIED_MS").add(Math.round(Cu.now() - telemetryCaptureTime)); if (installChanged) { updateReasons.push("directoryState"); } @@ -3605,7 +3559,6 @@ this.XPIProvider = { // If the database needs to be updated then open it and then update it // from the filesystem if (updateReasons.length > 0) { - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_load_reasons", updateReasons); XPIDatabase.syncLoadDB(false); try { extensionListChanged = this.processFileChanges(manifests, @@ -6421,7 +6374,6 @@ AddonInternal.prototype = { let message = "Problem with addon " + this.id + " targetPlatforms " + JSON.stringify(this.targetPlatforms); logger.error(message, e); - AddonManagerPrivate.recordException("XPI", message, e); // don't trust this add-on return false; } diff --git a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js index 02c7fa29a8..9f3273b1a5 100644 --- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js +++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js @@ -428,7 +428,6 @@ this.XPIDatabase = { // use an Error here so we get a stack trace. let err = new Error("XPI database modified after shutdown began"); logger.warn(err); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_late_stack", Log.stackTrace(err)); } if (!this._deferredSave) { @@ -536,7 +535,6 @@ this.XPIDatabase = { let fstream = null; let data = ""; try { - let readTimer = AddonManagerPrivate.simpleTimer("XPIDB_syncRead_MS"); logger.debug("Opening XPI database " + this.jsonFile.path); fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]. createInstance(Components.interfaces.nsIFileInputStream); @@ -554,14 +552,11 @@ this.XPIDatabase = { data += str.value; } while (read != 0); - readTimer.done(); this.parseDB(data, aRebuildOnError); } catch(e) { logger.error("Failed to load XPI JSON data from profile", e); - let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildReadFailed_MS"); this.rebuildDatabase(aRebuildOnError); - rebuildTimer.done(); } finally { if (cstream) @@ -583,7 +578,6 @@ this.XPIDatabase = { // If an async load was also in progress, resolve that promise with our DB; // otherwise create a resolved promise if (this._dbPromise) { - AddonManagerPrivate.recordSimpleMeasure("XPIDB_overlapped_load", 1); this._dbPromise.resolve(this.addonDB); } else @@ -596,27 +590,20 @@ this.XPIDatabase = { * If true, synchronously reconstruct the database from installed add-ons */ parseDB: function(aData, aRebuildOnError) { - let parseTimer = AddonManagerPrivate.simpleTimer("XPIDB_parseDB_MS"); try { // dump("Loaded JSON:\n" + aData + "\n"); let inputAddons = JSON.parse(aData); // Now do some sanity checks on our JSON db if (!("schemaVersion" in inputAddons) || !("addons" in inputAddons)) { - parseTimer.done(); // Content of JSON file is bad, need to rebuild from scratch logger.error("bad JSON file contents"); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "badJSON"); - let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildBadJSON_MS"); this.rebuildDatabase(aRebuildOnError); - rebuildTimer.done(); return; } if (inputAddons.schemaVersion != DB_SCHEMA) { // Handle mismatched JSON schema version. For now, we assume // compatibility for JSON data, though we throw away any fields we // don't know about (bug 902956) - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", - "schemaMismatch-" + inputAddons.schemaVersion); logger.debug("JSON schema mismatch: expected " + DB_SCHEMA + ", actual " + inputAddons.schemaVersion); // When we rev the schema of the JSON database, we need to make sure we @@ -630,7 +617,6 @@ this.XPIDatabase = { let newAddon = new DBAddonInternal(loadedAddon); addonDB.set(newAddon._key, newAddon); }; - parseTimer.done(); this.addonDB = addonDB; logger.debug("Successfully read XPI database"); this.initialized = true; @@ -638,18 +624,13 @@ this.XPIDatabase = { catch(e) { // If we catch and log a SyntaxError from the JSON // parser, the xpcshell test harness fails the test for us: bug 870828 - parseTimer.done(); if (e.name == "SyntaxError") { logger.error("Syntax error parsing saved XPI JSON data"); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "syntax"); } else { logger.error("Failed to load XPI JSON data from profile", e); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "other"); } - let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildReadFailed_MS"); this.rebuildDatabase(aRebuildOnError); - rebuildTimer.done(); } }, @@ -657,7 +638,6 @@ this.XPIDatabase = { * Upgrade database from earlier (sqlite or RDF) version if available */ upgradeDB: function(aRebuildOnError) { - let upgradeTimer = AddonManagerPrivate.simpleTimer("XPIDB_upgradeDB_MS"); try { let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA); if (schemaVersion <= LAST_SQLITE_DB_SCHEMA) { @@ -668,7 +648,6 @@ this.XPIDatabase = { else { // we've upgraded before but the JSON file is gone, fall through // and rebuild from scratch - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "dbMissing"); } } catch(e) { @@ -678,7 +657,6 @@ this.XPIDatabase = { } this.rebuildDatabase(aRebuildOnError); - upgradeTimer.done(); }, /** @@ -686,15 +664,12 @@ this.XPIDatabase = { * (for example because read permission is denied) */ rebuildUnreadableDB: function(aError, aRebuildOnError) { - let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildUnreadableDB_MS"); logger.warn("Extensions database " + this.jsonFile.path + " exists but is not readable; rebuilding", aError); // Remember the error message until we try and write at least once, so // we know at shutdown time that there was a problem this._loadError = aError; - AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "unreadable"); this.rebuildDatabase(aRebuildOnError); - rebuildTimer.done(); }, /** @@ -712,24 +687,19 @@ this.XPIDatabase = { } logger.debug("Starting async load of XPI database " + this.jsonFile.path); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_async_load", XPIProvider.runPhase); let readOptions = { outExecutionDuration: 0 }; return this._dbPromise = OS.File.read(this.jsonFile.path, null, readOptions).then( byteArray => { logger.debug("Async JSON file read took " + readOptions.outExecutionDuration + " MS"); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_asyncRead_MS", - readOptions.outExecutionDuration); if (this._addonDB) { logger.debug("Synchronous load completed while waiting for async load"); return this.addonDB; } logger.debug("Finished async read of XPI database, parsing..."); - let decodeTimer = AddonManagerPrivate.simpleTimer("XPIDB_decode_MS"); let decoder = new TextDecoder(); let data = decoder.decode(byteArray); - decodeTimer.done(); this.parseDB(data, true); return this.addonDB; }) @@ -1006,21 +976,11 @@ this.XPIDatabase = { this.initialized = false; - if (this._deferredSave) { - AddonManagerPrivate.recordSimpleMeasure( - "XPIDB_saves_total", this._deferredSave.totalSaves); - AddonManagerPrivate.recordSimpleMeasure( - "XPIDB_saves_overlapped", this._deferredSave.overlappedSaves); - AddonManagerPrivate.recordSimpleMeasure( - "XPIDB_saves_late", this._deferredSave.dirty ? 1 : 0); - } - // Return a promise that any pending writes of the DB are complete and we // are finished cleaning up let flushPromise = this.flush(); flushPromise.then(null, error => { logger.error("Flush of XPI database failed", error); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_shutdownFlush_failed", 1); // If our last attempt to read or write the DB failed, force a new // extensions.ini to be written to disk on the next startup Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true); @@ -1139,7 +1099,6 @@ this.XPIDatabase = { // an XPI theme to a lightweight theme before the DB has loaded, // because we're called from sync XPIProvider.addonChanged logger.warn("Synchronous load of XPI database due to getAddonsByType(" + aType + ")"); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_byType", XPIProvider.runPhase); this.syncLoadDB(true); } return _filterDB(this.addonDB, aAddon => (aAddon.type == aType)); @@ -1156,8 +1115,6 @@ this.XPIDatabase = { if (!this.addonDB) { // This may be called when the DB hasn't otherwise been loaded logger.warn("Synchronous load of XPI database due to getVisibleAddonForInternalName"); - AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_forInternalName", - XPIProvider.runPhase); this.syncLoadDB(true); } @@ -1228,8 +1185,6 @@ this.XPIDatabase = { */ addAddonMetadata: function XPIDB_addAddonMetadata(aAddon, aDescriptor) { if (!this.addonDB) { - AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata", - XPIProvider.runPhase); this.syncLoadDB(false); } @@ -1358,8 +1313,6 @@ this.XPIDatabase = { if (!this.addonDB) { logger.warn("updateActiveAddons called when DB isn't loaded"); // force the DB to load - AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_updateActive", - XPIProvider.runPhase); this.syncLoadDB(true); } logger.debug("Updating add-on states"); @@ -1379,8 +1332,6 @@ this.XPIDatabase = { writeAddonsList: function XPIDB_writeAddonsList() { if (!this.addonDB) { // force the DB to load - AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_writeList", - XPIProvider.runPhase); this.syncLoadDB(true); } Services.appinfo.invalidateCachesOnRestart(); |