☠☠ backed out by c096376198df ☠ ☠ | |
author | Robert Helmer <rhelmer@mozilla.com> |
Thu, 04 Oct 2018 14:15:11 +0000 | |
changeset 497756 | b969cbe46b14814c397199ef84db2ed18d252107 |
parent 497755 | 74ce6fcac2111570473f580669c536d93f816133 |
child 497757 | d0d593bf9772b1eb99547d114c9c6533e87bcd56 |
push id | 10002 |
push user | archaeopteryx@coole-files.de |
push date | Fri, 19 Oct 2018 23:09:29 +0000 |
treeherder | mozilla-beta@01378c910610 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | janerik |
bugs | 1492656 |
milestone | 64.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1779,8 +1779,11 @@ pref("prio.publicKeyB", "26E6674E65425B8 #if defined(NIGHTLY_BUILD) && defined(MOZ_LIBPRIO) pref("prio.enabled", true); #endif #ifdef NIGHTLY_BUILD pref("browser.fastblock.enabled", true); #endif +// Telemetry Coverage is disabled by default. +pref("toolkit.telemetry.coverage.enabled", false); +pref("toolkit.telemetry.coverage.endpoint.base", "https://telemetry-coverage.mozilla.org");
--- a/testing/profiles/common/user.js +++ b/testing/profiles/common/user.js @@ -44,8 +44,9 @@ user_pref("xpinstall.signatures.required // Prevent Remote Settings to issue non local connections. user_pref("services.settings.server", "http://localhost/remote-settings-dummy/v1"); // Ensure autoplay is enabled for all platforms. user_pref("media.autoplay.default", 0); // 0=Allowed, 1=Blocked, 2=Prompt user_pref("media.autoplay.enabled.user-gestures-needed", true); user_pref("media.autoplay.ask-permission", false); user_pref("media.autoplay.block-webaudio", false); user_pref("media.allowed-to-play.enabled", true); +user_pref("toolkit.telemetry.coverage.endpoint.base", "http://localhost");
--- a/toolkit/components/telemetry/app/TelemetryController.jsm +++ b/toolkit/components/telemetry/app/TelemetryController.jsm @@ -47,16 +47,17 @@ const REASON_GATHER_PAYLOAD = "gather-pa const REASON_GATHER_SUBSESSION_PAYLOAD = "gather-subsession-payload"; XPCOMUtils.defineLazyServiceGetter(this, "Telemetry", "@mozilla.org/base/telemetry;1", "nsITelemetry"); XPCOMUtils.defineLazyModuleGetters(this, { ClientID: "resource://gre/modules/ClientID.jsm", + CoveragePing: "resource://gre/modules/CoveragePing.jsm", AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm", TelemetryStorage: "resource://gre/modules/TelemetryStorage.jsm", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", TelemetryArchive: "resource://gre/modules/TelemetryArchive.jsm", TelemetrySession: "resource://gre/modules/TelemetrySession.jsm", MemoryTelemetry: "resource://gre/modules/MemoryTelemetry.jsm", TelemetrySend: "resource://gre/modules/TelemetrySend.jsm", TelemetryReportingPolicy: "resource://gre/modules/TelemetryReportingPolicy.jsm", @@ -692,16 +693,19 @@ var Impl = { // in the future. TelemetryStorage.removeFHRDatabase(); // The init sequence is forced to run on shutdown for short sessions and // we don't want to start TelemetryModules as the timer registration will fail. if (!this._shuttingDown) { // Report the modules loaded in the Firefox process. TelemetryModules.start(); + + // Send telemetry coverage ping. + await CoveragePing.startup(); } TelemetryEventPing.startup(); this._delayedInitTaskDeferred.resolve(); } catch (e) { this._delayedInitTaskDeferred.reject(e); } finally {
new file mode 100644 --- /dev/null +++ b/toolkit/components/telemetry/docs/data/coverage-ping.rst @@ -0,0 +1,40 @@ + +"coverage" ping +============= + +This ping is not enabled by default. When enabled, a ping is generated a total of once per profile, as a diagnostic tool +to determine whether Telemetry is working for users. + +This ping contains no client id and no environment data. + +You can find more background information in `this blog post <https://blog.mozilla.org/data/2018/08/20/effectively-measuring-search-in-firefox/>`_. + +Structure: + +.. code-block:: js + + { + "appVersion": "63.0a1", + "appUpdateChannel": "nightly", + "osName": "Darwin", + "osVersion": "17.7.0", + "telemetryEnabled": 1 + } + +Expected behaviours +------------------- +The following is a list of expected behaviours for the ``coverage`` ping: + +- The ping will only be sent once per ping version, per profile. +- If sending the ping fails, it will be retried on startup. +- A totally arbitrary UUID is generated on first run on a new profile, to use for filtering duplicates. +- The ping is sent to a different endpoint not using existing Telemetry. +- The ping does not honor the Telemetry enabled preference, but provides its own opt-out preference: `toolkit.telemetry.coverage.opt-out`. +- The ping is disabled by default. It is intended to be enabled for users on an experimental basis using the preference `toolkit.telemetry.coverage.enabled`. + +Version History +--------------- + +- Firefox 64: + + - "coverage" ping shipped (`bug 1492656 <https://bugzilla.mozilla.org/show_bug.cgi?id=1492656>`_).
--- a/toolkit/components/telemetry/moz.build +++ b/toolkit/components/telemetry/moz.build @@ -95,16 +95,17 @@ EXTRA_JS_MODULES += [ 'app/TelemetrySend.jsm', 'app/TelemetryStopwatch.jsm', 'app/TelemetryStorage.jsm', 'app/TelemetryTimestamps.jsm', 'app/TelemetryUtils.jsm', 'other/GCTelemetry.jsm', 'other/MemoryTelemetry.jsm', 'other/UITelemetry.jsm', + 'pings/CoveragePing.jsm', 'pings/EventPing.jsm', 'pings/HealthPing.jsm', 'pings/ModulesPing.jsm', 'pings/TelemetrySession.jsm', 'pings/UpdatePing.jsm', ] TESTING_JS_MODULES += [
new file mode 100644 --- /dev/null +++ b/toolkit/components/telemetry/pings/CoveragePing.jsm @@ -0,0 +1,154 @@ +/* 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"; + +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +ChromeUtils.defineModuleGetter(this, + "CommonUtils", "resource://services-common/utils.js"); +ChromeUtils.defineModuleGetter(this, + "Log", "resource://gre/modules/Log.jsm"); +ChromeUtils.defineModuleGetter(this, + "PromiseUtils", "resource://gre/modules/PromiseUtils.jsm"); +ChromeUtils.defineModuleGetter(this, + "ServiceRequest", "resource://gre/modules/ServiceRequest.jsm"); +ChromeUtils.defineModuleGetter(this, + "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"); + +var EXPORTED_SYMBOLS = ["CoveragePing"]; + +const COVERAGE_VERSION = "2"; + +const COVERAGE_ENABLED_PREF = "toolkit.telemetry.coverage.enabled"; +const LOG_LEVEL_PREF = "toolkit.telemetry.coverage.log-level"; +const OPT_OUT_PREF = "toolkit.telemetry.coverage.opt-out"; +const ALREADY_RUN_PREF = `toolkit.telemetry.coverage.already-run.v${COVERAGE_VERSION}`; +const COVERAGE_UUID_PREF = `toolkit.telemetry.coverage.uuid.v${COVERAGE_VERSION}`; +const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled"; +const REPORTING_ENDPOINT_BASE_PREF = `toolkit.telemetry.coverage.endpoint.base`; +const REPORTING_ENDPOINT = "submit/coverage/coverage"; +const PING_SUBMISSION_TIMEOUT = 30 * 1000; // 30 seconds + +const log = Log.repository.getLogger("Telemetry::CoveragePing"); +log.level = Services.prefs.getIntPref(LOG_LEVEL_PREF, Log.Level.Error); +log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); + +var CoveragePing = Object.freeze({ + async startup() { + if (!Services.prefs.getCharPref(REPORTING_ENDPOINT_BASE_PREF, null)) { + log.error("no endpoint base set"); + return; + } + + if (!Services.prefs.getBoolPref(COVERAGE_ENABLED_PREF)) { + log.debug("coverage not enabled"); + return; + } + + if (Services.prefs.getBoolPref(OPT_OUT_PREF, false)) { + log.debug("user has set opt-out pref"); + return; + } + + if (Services.prefs.getBoolPref(ALREADY_RUN_PREF, false)) { + log.debug("already run on this profile"); + return; + } + + try { + await this.reportTelemetrySetting(); + } catch (e) { + log.error("unable to upload payload", e); + } + }, + + // NOTE - this does not use existing Telemetry code or honor Telemetry opt-out prefs, + // by design. It also sends no identifying data like the client ID. See the "coverage ping" + // documentation for details. + reportTelemetrySetting() { + const enabled = Services.prefs.getBoolPref(TELEMETRY_ENABLED_PREF, false); + + const payload = { + "appVersion": Services.appinfo.version, + "appUpdateChannel": UpdateUtils.getUpdateChannel(false), + "osName": Services.sysinfo.getProperty("name"), + "osVersion": Services.sysinfo.getProperty("version"), + "telemetryEnabled": enabled, + }; + + let cachedUuid = Services.prefs.getCharPref(COVERAGE_UUID_PREF, null); + if (!cachedUuid) { + // Totally random UUID, just for detecting duplicates. + cachedUuid = CommonUtils.generateUUID(); + Services.prefs.setCharPref(COVERAGE_UUID_PREF, cachedUuid); + } + + let reportingEndpointBase = Services.prefs.getCharPref(REPORTING_ENDPOINT_BASE_PREF, null); + + let endpoint = `${reportingEndpointBase}/${REPORTING_ENDPOINT}/${COVERAGE_VERSION}/${cachedUuid}`; + + log.debug(`putting to endpoint ${endpoint} with payload:`, payload); + + let deferred = PromiseUtils.defer(); + + let request = new ServiceRequest({mozAnon: true}); + request.mozBackgroundRequest = true; + request.timeout = PING_SUBMISSION_TIMEOUT; + + request.open("PUT", endpoint, true); + request.overrideMimeType("text/plain"); + request.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); + request.setRequestHeader("Date", new Date().toUTCString()); + + // Prevent the request channel from running though URLClassifier (bug 1296802) + request.channel.loadFlags &= ~Ci.nsIChannel.LOAD_CLASSIFY_URI; + + let errorhandler = (event) => { + let failure = event.type; + log.error(`error making request to ${endpoint}: ${failure}`); + deferred.reject(event); + }; + + request.onerror = errorhandler; + request.ontimeout = errorhandler; + request.onabort = errorhandler; + + request.onloadend = (event) => { + let status = request.status; + let statusClass = status - (status % 100); + let success = false; + + if (statusClass === 200) { + // We can treat all 2XX as success. + log.info(`successfully submitted, status: ${status}`); + success = true; + } else if (statusClass === 400) { + // 4XX means that something with the request was broken. + + // TODO: we should handle this better, but for now we should avoid resubmitting + // broken requests by pretending success. + success = true; + log.error(`error submitting to ${endpoint}, status: ${status} - ping request broken?`); + } else if (statusClass === 500) { + // 5XX means there was a server-side error and we should try again later. + log.error(`error submitting to ${endpoint}, status: ${status} - server error, should retry later`); + } else { + // We received an unexpected status code. + log.error(`error submitting to ${endpoint}, status: ${status}, type: ${event.type}`); + } + + if (success) { + Services.prefs.setBoolPref(ALREADY_RUN_PREF, true); + log.debug(`result from PUT: ${request.responseText}`); + deferred.resolve(); + } else { + deferred.reject(event); + } + }; + + request.send(JSON.stringify(payload)); + + return deferred.promise; + }, +});
new file mode 100644 --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_CoveragePing.js @@ -0,0 +1,104 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +ChromeUtils.import("resource://gre/modules/CoveragePing.jsm"); +ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +ChromeUtils.import("resource://testing-common/httpd.js"); + + +const COVERAGE_VERSION = "2"; + +const COVERAGE_ENABLED_PREF = "toolkit.telemetry.coverage.enabled"; +const OPT_OUT_PREF = "toolkit.telemetry.coverage.opt-out"; +const ALREADY_RUN_PREF = `toolkit.telemetry.coverage.already-run.v${COVERAGE_VERSION}`; +const COVERAGE_UUID_PREF = `toolkit.telemetry.coverage.uuid.v${COVERAGE_VERSION}`; +const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled"; +const REPORTING_ENDPOINT_BASE_PREF = "toolkit.telemetry.coverage.endpoint.base"; +const REPORTING_ENDPOINT = "submit/coverage/coverage"; + +Services.prefs.setIntPref("toolkit.telemetry.coverage.log-level", 20); + +add_task(async function setup() { + let uuid = "test123"; + Services.prefs.setCharPref(COVERAGE_UUID_PREF, uuid); + + const server = new HttpServer(); + server.start(-1); + const serverPort = server.identity.primaryPort; + + Services.prefs.setCharPref(REPORTING_ENDPOINT_BASE_PREF, `http://localhost:${serverPort}`); + + server.registerPathHandler(`/${REPORTING_ENDPOINT}/${COVERAGE_VERSION}/${uuid}`, (request, response) => { + equal(request.method, "PUT"); + let telemetryEnabled = Services.prefs.getBoolPref(TELEMETRY_ENABLED_PREF, false); + + let requestBody = NetUtil.readInputStreamToString(request.bodyInputStream, + request.bodyInputStream.available()); + + let resultObj = JSON.parse(requestBody); + + deepEqual(Object.keys(resultObj), [ + "appUpdateChannel", "osName", "osVersion", "telemetryEnabled", + ]); + + if (telemetryEnabled) { + ok(resultObj.telemetryEnabled); + } else { + ok(!resultObj.telemetryEnabled); + } + + const response_body = "OK"; + response.bodyOutputStream.write(response_body, response_body.length); + server.stop(); + }); + + // Trigger a proper telemetry init. + do_get_profile(true); + // Make sure we don't generate unexpected pings due to pref changes. + await setEmptyPrefWatchlist(); + + await TelemetryController.testSetup(); +}); + +add_task(async function test_prefs() { + // Telemetry reporting setting does not control this ping, but it + // reported by this ping. + Services.prefs.setBoolPref(TELEMETRY_ENABLED_PREF, false); + + // should not run if enabled pref is false + Services.prefs.setBoolPref(COVERAGE_ENABLED_PREF, false); + Services.prefs.setBoolPref(ALREADY_RUN_PREF, false); + Services.prefs.setBoolPref(OPT_OUT_PREF, false); + + await TelemetryController.testReset(); + + let alreadyRun = Services.prefs.getBoolPref(ALREADY_RUN_PREF, false); + ok(!alreadyRun, "should not have run with enabled pref false"); + + // should not run if opt-out pref is true + Services.prefs.setBoolPref(COVERAGE_ENABLED_PREF, true); + Services.prefs.setBoolPref(ALREADY_RUN_PREF, false); + Services.prefs.setBoolPref(OPT_OUT_PREF, true); + + await TelemetryController.testReset(); + + // should run if opt-out pref is false and coverage is enabled + Services.prefs.setBoolPref(COVERAGE_ENABLED_PREF, true); + Services.prefs.setBoolPref(ALREADY_RUN_PREF, false); + Services.prefs.setBoolPref(OPT_OUT_PREF, false); + + await TelemetryController.testReset(); + + // the telemetry setting should be set correctly + Services.prefs.setBoolPref(TELEMETRY_ENABLED_PREF, true); + + await TelemetryController.testReset(); + + alreadyRun = Services.prefs.getBoolPref(ALREADY_RUN_PREF, false); + + ok(alreadyRun, "should run if no opt-out and enabled"); +}); +
--- a/toolkit/components/telemetry/tests/unit/xpcshell.ini +++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini @@ -86,8 +86,10 @@ skip-if = os == "android" # Disabled due [test_ModulesPing.js] [test_PingSender.js] skip-if = (os == "android") || (os == "linux" && bits == 32) [test_TelemetryGC.js] [test_TelemetryAndroidEnvironment.js] [test_TelemetryUtils.js] [test_EventPing.js] [test_EventPing_disabled.js] +tags = coverage +[test_CoveragePing.js]