Bug 1821189 - Associate provenance attribution with installation.first_seen event r=nalexander

We can't add the provenance data to the `installation.first_seen` extra data because it is already at its maximum number of keys. So instead we will add the `installation.first_seen_prov_ext` event which will be sent at the same time as `installation.first_seen` and will contain provenance attribution data in its extras object.

Differential Revision: https://phabricator.services.mozilla.com/D172520
This commit is contained in:
Robin Steuber
2023-03-14 18:08:16 +00:00
parent ceccf6b94b
commit c7f37da43c
5 changed files with 164 additions and 14 deletions

View File

@@ -441,6 +441,15 @@ export var ProvenanceData = {
/**
* Only submits telemetry once, no matter how many times it is called.
* Has no effect on OSs where provenance data is not supported.
*
* @returns An object indicating the values submitted. Keys may not match the
* Scalar names since the returned object is intended to be suitable
* for use as a Telemetry Event's `extra` object, which has shorter
* limits for extra key names than the limits for Scalar names.
* Values will be converted to strings since Telemetry Event's
* `extra` objects must have string values.
* On platforms that do not support provenance data, this will always
* return an empty object.
*/
async submitProvenanceTelemetry() {
if (gTelemetryPromise) {
@@ -448,21 +457,31 @@ export var ProvenanceData = {
}
gTelemetryPromise = (async () => {
const errorValue = "error";
let extra = {};
let provenance = await this.readZoneIdProvenanceFile();
if (!provenance) {
return;
return extra;
}
Services.telemetry.scalarSet(
let setTelemetry = (scalarName, extraKey, value) => {
Services.telemetry.scalarSet(scalarName, value);
extra[extraKey] = value.toString();
};
setTelemetry(
"attribution.provenance.data_exists",
"data_exists",
!provenance.readProvenanceError
);
if (provenance.readProvenanceError) {
return;
return extra;
}
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.file_system",
"file_system",
provenance.fileSystem ?? errorValue
);
@@ -475,42 +494,50 @@ export var ProvenanceData = {
provenance.readZoneIdError == "openFile" &&
provenance.readZoneIdErrorCode == ERROR_FILE_NOT_FOUND
);
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.ads_exists",
"ads_exists",
ads_exists
);
if (!ads_exists) {
return;
return extra;
}
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.security_zone",
"security_zone",
"zoneId" in provenance ? provenance.zoneId.toString() : errorValue
);
let haveReferrerUrl = URL.isInstance(provenance.referrerUrl);
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.referrer_url_exists",
"refer_url_exist",
haveReferrerUrl
);
if (haveReferrerUrl) {
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.referrer_url_is_mozilla",
"refer_url_moz",
provenance.referrerUrlIsMozilla
);
}
let haveHostUrl = URL.isInstance(provenance.hostUrl);
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.host_url_exists",
"host_url_exist",
haveHostUrl
);
if (haveHostUrl) {
Services.telemetry.scalarSet(
setTelemetry(
"attribution.provenance.host_url_is_mozilla",
"host_url_moz",
provenance.hostUrlIsMozilla
);
}
return extra;
})();
return gTelemetryPromise;
},

View File

@@ -27,6 +27,20 @@ add_setup(function setup() {
// If `iniFileContents` is passed as `null`, we will simulate an error reading
// the INI.
async function testProvenance(iniFileContents, testFn, telemetryTestFn) {
// The extra data returned by `ProvenanceData.submitProvenanceTelemetry` uses
// names that don't actually match the scalar names due to name length
// restrictions.
let scalarToExtraKeyMap = {
"attribution.provenance.data_exists": "data_exists",
"attribution.provenance.file_system": "file_system",
"attribution.provenance.ads_exists": "ads_exists",
"attribution.provenance.security_zone": "security_zone",
"attribution.provenance.referrer_url_exists": "refer_url_exist",
"attribution.provenance.referrer_url_is_mozilla": "refer_url_moz",
"attribution.provenance.host_url_exists": "host_url_exist",
"attribution.provenance.host_url_is_mozilla": "host_url_moz",
};
if (iniFileContents == null) {
AttributionIOUtils.readUTF8 = async path => {
throw new Error("test error: simulating provenance file read error");
@@ -40,13 +54,15 @@ async function testProvenance(iniFileContents, testFn, telemetryTestFn) {
}
if (telemetryTestFn) {
Services.telemetry.clearScalars();
await ProvenanceData.submitProvenanceTelemetry();
let extras = await ProvenanceData.submitProvenanceTelemetry();
let scalars = Services.telemetry.getSnapshotForScalars(
"new-profile",
false /* aClear */
).parent;
let checkScalar = (scalarName, expectedValue) => {
TelemetryTestUtils.assertScalar(scalars, scalarName, expectedValue);
let extraKey = scalarToExtraKeyMap[scalarName];
Assert.equal(extras[extraKey], expectedValue.toString());
};
telemetryTestFn(checkScalar);
}