Skip to content

Commit

Permalink
Bug 1820158 - Port WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT and WEBEXT_BROW…
Browse files Browse the repository at this point in the history
…SERACTION_POPUP_PRELOAD_RESULT_COUNT to Glean labeled_counter metrics. r=zombie

Differential Revision: https://phabricator.services.mozilla.com/D191756
  • Loading branch information
rpl committed Nov 10, 2023
1 parent 29007f8 commit c038ce2
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ const EXTENSION_ID2 = "@test-extension2";
// Keep this in sync with the order in Histograms.json for
// WEBEXT_BROWSERACTION_POPUP_PRELOAD_RESULT_COUNT
const CATEGORIES = ["popupShown", "clearAfterHover", "clearAfterMousedown"];
const GLEAN_RESULT_LABELS = [...CATEGORIES, "__other__"];

function assertGleanPreloadResultLabelCounter(expectedLabelsValue) {
for (const label of GLEAN_RESULT_LABELS) {
const expectedLabelValue = expectedLabelsValue[label];
Assert.deepEqual(
Glean.extensionsCounters.browserActionPreloadResult[label].testGetValue(),
expectedLabelValue,
`Expect Glean browserActionPreloadResult metric label ${label} to be ${
expectedLabelValue > 0 ? expectedLabelValue : "empty"
}`
);
}
}

function assertGleanPreloadResultLabelCounterEmpty() {
// All empty labels passed to the other helpers to make it
// assert that all labels are empty.
assertGleanPreloadResultLabelCounter({});
}

/**
* Takes a Telemetry histogram snapshot and makes sure
Expand Down Expand Up @@ -273,6 +293,7 @@ add_task(async function testBrowserActionTelemetryResults() {

histogram.clear();
histogramKeyed.clear();
Services.fog.testResetFOG();

is(
histogram.snapshot().sum,
Expand All @@ -284,6 +305,7 @@ add_task(async function testBrowserActionTelemetryResults() {
0,
`No data recorded for histogram: ${RESULT_HISTOGRAM_KEYED}.`
);
assertGleanPreloadResultLabelCounterEmpty();

await extension.startup();

Expand Down Expand Up @@ -314,6 +336,7 @@ add_task(async function testBrowserActionTelemetryResults() {
);

assertOnlyOneTypeSet(histogram.snapshot(), "clearAfterHover");
assertGleanPreloadResultLabelCounter({ clearAfterHover: 1 });

let keyedSnapshot = histogramKeyed.snapshot();
Assert.deepEqual(
Expand All @@ -325,6 +348,7 @@ add_task(async function testBrowserActionTelemetryResults() {

histogram.clear();
histogramKeyed.clear();
Services.fog.testResetFOG();

// TODO: Create a test for cancel after mousedown.
// This is tricky because calling mouseout after mousedown causes a
Expand All @@ -334,6 +358,7 @@ add_task(async function testBrowserActionTelemetryResults() {
await awaitExtensionPanel(extension);

assertOnlyOneTypeSet(histogram.snapshot(), "popupShown");
assertGleanPreloadResultLabelCounter({ popupShown: 1 });

keyedSnapshot = histogramKeyed.snapshot();
Assert.deepEqual(
Expand Down
46 changes: 33 additions & 13 deletions toolkit/components/extensions/ExtensionTelemetry.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ const HISTOGRAMS_IDS = {
const GLEAN_METRICS_TYPES = {
backgroundPageLoad: "timing_distribution",
browserActionPopupOpen: "timing_distribution",
browserActionPreloadResult: null,
browserActionPreloadResult: "labeled_counter",
contentScriptInjection: "timing_distribution",
eventPageRunningTime: "custom_distribution",
eventPageIdleResult: null,
eventPageIdleResult: "labeled_counter",
extensionStartup: "timing_distribution",
pageActionPopupOpen: "timing_distribution",
storageLocalGetJson: "timing_distribution",
Expand Down Expand Up @@ -251,12 +251,14 @@ class ExtensionTelemetryMetric {
*/
_histogramAdd(metric, { category, extension, value }) {
if (!extension) {
throw new Error(`Mandatory extension parameter is undefined`);
Cu.reportError(`Mandatory extension parameter is undefined`);
return;
}

const baseId = HISTOGRAMS_IDS[metric];
if (!baseId) {
throw new Error(`Unknown metric ${metric}`);
Cu.reportError(`Unknown metric ${metric}`);
return;
}

const histogram = Services.telemetry.getHistogramById(baseId);
Expand All @@ -277,16 +279,34 @@ class ExtensionTelemetryMetric {
keyedHistogram.add(extensionId, value);
}

if (GLEAN_METRICS_TYPES[metric] === "custom_distribution") {
if (typeof category === "string") {
throw new Error(
`Unexpected unsupported category on Glean metric ${metric}`
);
switch (GLEAN_METRICS_TYPES[metric]) {
case "custom_distribution": {
if (typeof category === "string") {
Cu.reportError(
`Unexpected unsupported category parameter set on Glean metric ${metric}`
);
return;
}
// NOTE: extensionsTiming may become a property of the GLEAN_METRICS_TYPES
// map once we may introduce new histograms that are not part of the
// extensionsTiming Glean metrics category.
Glean.extensionsTiming[metric].accumulateSamples([value]);
break;
}
// NOTE: extensionsTiming may become a property of the GLEAN_METRICS_TYPES
// map once we may introduce new metrics that are not part of the
// extensionsTiming Glean metrics category.
Glean.extensionsTiming[metric].accumulateSamples([value]);
case "labeled_counter": {
if (typeof category !== "string") {
Cu.reportError(
`Missing mandatory category on adding data to labeled Glean metric ${metric}`
);
return;
}
Glean.extensionsCounters[metric][category].add(value ?? 1);
break;
}
default:
Cu.reportError(
`Unexpected unsupported Glean metric type "${GLEAN_METRICS_TYPES[metric]}" for metric ${metric}`
);
}
}
}
Expand Down
60 changes: 60 additions & 0 deletions toolkit/components/extensions/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,66 @@ extensions.quarantined_domains:
- technical
telemetry_mirror: EXTENSIONS_QUARANTINEDDOMAINS_REMOTEHASH

extensions.counters:

browser_action_preload_result:
type: labeled_counter
expires: never
description: |
Number of times an event page hit the idle timeout and results in one of the labels.
# Keep these labels in sync with the ones in WEBEXT_BROWSERACTION_POPUP_PRELOAD_RESULT_COUNT
# as defined in Histograms.json
labels:
- popupShown
- clearAfterHover
- clearAfterMousedown
lifetime: application
notification_emails:
- [email protected]
bugs:
- https://bugzilla.mozilla.org/1297167
- https://bugzilla.mozilla.org/1513556
- https://bugzilla.mozilla.org/1578225
- https://bugzilla.mozilla.org/1623315
- https://bugzilla.mozilla.org/1666980
- https://bugzilla.mozilla.org/1706839
- https://bugzilla.mozilla.org/1745271
- https://bugzilla.mozilla.org/1777402
- https://bugzilla.mozilla.org/1811155
- https://bugzilla.mozilla.org/1861303
- https://bugzilla.mozilla.org/1820158
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1820158#c8
data_sensitivity:
- technical

event_page_idle_result:
type: labeled_counter
expires: never
description: |
Number of times an event page hit the idle timeout and results in one of the labels.
# Keep these labels in sync with the ones in WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT
# as defined in Histograms.json
labels:
- suspend
- reset_other
- reset_event
- reset_listeners
- reset_nativeapp
- reset_streamfilter
lifetime: application
notification_emails:
- [email protected]
bugs:
- https://bugzilla.mozilla.org/1787940
- https://bugzilla.mozilla.org/1817103
- https://bugzilla.mozilla.org/1861303
- https://bugzilla.mozilla.org/1820158
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1820158#c8
data_sensitivity:
- technical

extensions.timing:

background_page_load:
Expand Down
91 changes: 91 additions & 0 deletions toolkit/components/extensions/test/xpcshell/head_telemetry.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ const HISTOGRAM_EVENTPAGE_IDLE_RESULT_CATEGORIES = [
"reset_streamfilter",
];

const GLEAN_EVENTPAGE_IDLE_RESULT_CATEGORIES = [
...HISTOGRAM_EVENTPAGE_IDLE_RESULT_CATEGORIES,
"__other__",
];

function valueSum(arr) {
return Object.values(arr).reduce((a, b) => a + b, 0);
}
Expand Down Expand Up @@ -272,6 +277,92 @@ function assertGleanMetricsSamplesCount({
);
}

function assertGleanLabeledCounter({
metricId,
gleanMetric,
gleanMetricLabels,
expectedLabelsValue,
ignoreNonExpectedLabels,
message,
}) {
const { GleanLabeled } = globalThis;
const msg = message ? `(${message})` : "";
if (!Array.isArray(gleanMetricLabels) || !gleanMetricLabels.length) {
throw new Error(
`Missing mandatory gleanMetricLabels property ${msg}: ${gleanMetricLabels}`
);
}

if (!(gleanMetric instanceof GleanLabeled)) {
throw new Error(
`Glean metric "${metricId}" should be an instance of GleanLabeled: ${gleanMetric} ${msg}`
);
}

for (const label of gleanMetricLabels) {
const expectedLabelValue = expectedLabelsValue[label];
if (ignoreNonExpectedLabels && !(label in expectedLabelsValue)) {
continue;
}
Assert.deepEqual(
gleanMetric[label].testGetValue(),
expectedLabelValue,
`Expect Glean "${metricId}" metric label "${label}" to be ${
expectedLabelValue > 0 ? expectedLabelValue : "empty"
}`
);
}
}

function assertGleanLabeledCounterEmpty({
metricId,
gleanMetric,
gleanMetricLabels,
message,
}) {
// All empty labels passed to the other helpers to make it
// assert that all labels are empty.
assertGleanLabeledCounter({
metricId,
gleanMetric,
gleanMetricLabels,
expectedLabelsValue: {},
message,
});
}

function assertGleanLabeledCounterNotEmpty({
metricId,
gleanMetric,
expectedNotEmptyLabels,
message,
}) {
const { GleanLabeled } = globalThis;
const msg = message ? `(${message})` : "";
if (
!Array.isArray(expectedNotEmptyLabels) ||
!expectedNotEmptyLabels.length
) {
throw new Error(
`Missing mandatory expectedNotEmptyLabels property ${msg}: ${expectedNotEmptyLabels}`
);
}

if (!(gleanMetric instanceof GleanLabeled)) {
throw new Error(
`Glean metric "${metricId}" should be an instance of GleanLabeled: ${gleanMetric} ${msg}`
);
}

for (const label of expectedNotEmptyLabels) {
Assert.notEqual(
gleanMetric[label].testGetValue(),
undefined,
`Expect Glean "${metricId}" metric label "${label}" to not be empty`
);
}
}

function assertDNRTelemetryMetricsDefined(metrics) {
const metricsNotFound = metrics.filter(metricDetails => {
const { metric, label } = metricDetails;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ add_task(async function test_eventpage_idle() {
gleanMetric: Glean.extensionsTiming.eventPageRunningTime,
gleanMetricConstructor: GleanCustomDistribution,
});
assertGleanLabeledCounterEmpty({
metricId: "eventPageIdleResult",
gleanMetric: Glean.extensionsCounters.eventPageIdleResult,
gleanMetricLabels: GLEAN_EVENTPAGE_IDLE_RESULT_CATEGORIES,
});

let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
Expand Down Expand Up @@ -143,6 +148,11 @@ add_task(async function test_eventpage_idle() {
category: "suspend",
categories: HISTOGRAM_EVENTPAGE_IDLE_RESULT_CATEGORIES,
});
assertGleanLabeledCounterNotEmpty({
metricId: "eventPageIdleResult",
gleanMetric: Glean.extensionsCounters.eventPageIdleResult,
expectedNotEmptyLabels: ["suspend"],
});

assertHistogramCategoryNotEmpty(
WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT_BY_ADDONID,
Expand Down Expand Up @@ -207,10 +217,15 @@ add_task(
add_task(
{ pref_set: [["extensions.webextensions.runtime.timeout", 1000]] },
async function test_eventpage_runtime_onSuspend_canceled() {
clearHistograms();
resetTelemetryData();

assertHistogramEmpty(WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT);
assertKeyedHistogramEmpty(WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT_BY_ADDONID);
assertGleanLabeledCounterEmpty({
metricId: "eventPageIdleResult",
gleanMetric: Glean.extensionsCounters.eventPageIdleResult,
gleanMetricLabels: GLEAN_EVENTPAGE_IDLE_RESULT_CATEGORIES,
});

let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
Expand Down Expand Up @@ -256,6 +271,11 @@ add_task(
category: "reset_event",
categories: HISTOGRAM_EVENTPAGE_IDLE_RESULT_CATEGORIES,
});
assertGleanLabeledCounterNotEmpty({
metricId: "eventPageIdleResult",
gleanMetric: Glean.extensionsCounters.eventPageIdleResult,
expectedNotEmptyLabels: ["reset_event"],
});

assertHistogramCategoryNotEmpty(
WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT_BY_ADDONID,
Expand Down Expand Up @@ -426,10 +446,15 @@ function createPendingListenerTestExtension() {
add_task(
{ pref_set: [["extensions.background.idle.timeout", 500]] },
async function test_eventpage_idle_reset_on_async_listener_unresolved() {
clearHistograms();
resetTelemetryData();

assertHistogramEmpty(WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT);
assertKeyedHistogramEmpty(WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT_BY_ADDONID);
assertGleanLabeledCounterEmpty({
metricId: "eventPageIdleResult",
gleanMetric: Glean.extensionsCounters.eventPageIdleResult,
gleanMetricLabels: GLEAN_EVENTPAGE_IDLE_RESULT_CATEGORIES,
});

let extension = createPendingListenerTestExtension();
await extension.startup();
Expand Down Expand Up @@ -473,6 +498,16 @@ add_task(
categories: HISTOGRAM_EVENTPAGE_IDLE_RESULT_CATEGORIES,
});

assertGleanLabeledCounter({
metricId: "eventPageIdleResult",
gleanMetric: Glean.extensionsCounters.eventPageIdleResult,
gleanMetricLabels: GLEAN_EVENTPAGE_IDLE_RESULT_CATEGORIES,
ignoreNonExpectedLabels: true, // Only check values on the labels listed below.
expectedLabelsValue: {
reset_listeners: 1,
},
});

assertHistogramCategoryNotEmpty(
WEBEXT_EVENTPAGE_IDLE_RESULT_COUNT_BY_ADDONID,
{
Expand Down

0 comments on commit c038ce2

Please sign in to comment.