Bug 1304647 - Measure the number of total URIs visited in a "session fragment", without any filtering. r=gijs, data-review=rweiss
authorAlessio Placitelli <alessio.placitelli@gmail.com>
Tue, 18 Oct 2016 01:58:00 +0200
changeset 319832 f2027674d0b299a4dba5d27911d22fdb333ab5f6
parent 319831 1bd14dd39440eeef1e29dfc4d4427ad176828a88
child 319833 1b8a23c25b1f43d626c978d9e3eb2ca6e3dafb66
push id20748
push userphilringnalda@gmail.com
push dateFri, 28 Oct 2016 03:39:55 +0000
treeherderfx-team@715360440695 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs1304647
milestone52.0a1
Bug 1304647 - Measure the number of total URIs visited in a "session fragment", without any filtering. r=gijs, data-review=rweiss MozReview-Commit-ID: 8L18SKeeM7F
browser/modules/BrowserUsageTelemetry.jsm
browser/modules/test/browser_UsageTelemetry.js
browser/modules/test/browser_UsageTelemetry_private_and_restore.js
toolkit/components/telemetry/Scalars.yaml
--- a/browser/modules/BrowserUsageTelemetry.jsm
+++ b/browser/modules/BrowserUsageTelemetry.jsm
@@ -26,16 +26,17 @@ const DOMWINDOW_OPENED_TOPIC = "domwindo
 
 // Probe names.
 const MAX_TAB_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_tab_count";
 const MAX_WINDOW_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_window_count";
 const TAB_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.tab_open_event_count";
 const WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.window_open_event_count";
 const UNIQUE_DOMAINS_COUNT_SCALAR_NAME = "browser.engagement.unique_domains_count";
 const TOTAL_URI_COUNT_SCALAR_NAME = "browser.engagement.total_uri_count";
+const UNFILTERED_URI_COUNT_SCALAR_NAME = "browser.engagement.unfiltered_uri_count";
 
 // A list of known search origins.
 const KNOWN_SEARCH_SOURCES = [
   "abouthome",
   "contextmenu",
   "newtab",
   "searchbar",
   "urlbar",
@@ -73,23 +74,23 @@ function getSearchEngineId(engine) {
 }
 
 let URICountListener = {
   // A set containing the visited domains, see bug 1271310.
   _domainSet: new Set(),
   // A map to keep track of the URIs loaded from the restored tabs.
   _restoredURIsMap: new WeakMap(),
 
-  isValidURI(uri) {
+  isHttpURI(uri) {
     // Only consider http(s) schemas.
     return uri.schemeIs("http") || uri.schemeIs("https");
   },
 
   addRestoredURI(browser, uri) {
-    if (!this.isValidURI(uri)) {
+    if (!this.isHttpURI(uri)) {
       return;
     }
 
     this._restoredURIsMap.set(browser, uri.spec);
   },
 
   onLocationChange(browser, webProgress, request, uri, flags) {
     // Don't count this URI if it's an error page.
@@ -97,38 +98,61 @@ let URICountListener = {
       return;
     }
 
     // We only care about top level loads.
     if (!webProgress.isTopLevel) {
       return;
     }
 
-    if (!this.isValidURI(uri)) {
-      return;
-    }
-
     // The SessionStore sets the URI of a tab first, firing onLocationChange the
     // first time, then manages content loading using its scheduler. Once content
     // loads, we will hit onLocationChange again.
     // We can catch the first case by checking for null requests: be advised that
     // this can also happen when navigating page fragments, so account for it.
     if (!request &&
         !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) {
       return;
     }
 
+    // Track URI loads, even if they're not http(s).
+    let uriSpec = null;
+    try {
+      uriSpec = uri.spec;
+    } catch (e) {
+      // If we have troubles parsing the spec, still count this as
+      // an unfiltered URI.
+      Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1);
+      return;
+    }
+
+
+    // Don't count about:blank and similar pages, as they would artificially
+    // inflate the counts.
+    if (browser.ownerDocument.defaultView.gInitialPages.includes(uriSpec)) {
+      return;
+    }
+
     // If the URI we're loading is in the _restoredURIsMap, then it comes from a
     // restored tab. If so, let's skip it and remove it from the map as we want to
     // count page refreshes.
-    if (this._restoredURIsMap.get(browser) === uri.spec) {
+    if (this._restoredURIsMap.get(browser) === uriSpec) {
       this._restoredURIsMap.delete(browser);
       return;
     }
 
+    // The URI wasn't from a restored tab. Count it among the unfiltered URIs.
+    // If this is an http(s) URI, this also gets counted by the "total_uri_count"
+    // probe.
+    Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1);
+
+    if (!this.isHttpURI(uri)) {
+      return;
+    }
+
     // Update the URI counts.
     Services.telemetry.scalarAdd(TOTAL_URI_COUNT_SCALAR_NAME, 1);
 
     // We only want to count the unique domains up to MAX_UNIQUE_VISITED_DOMAINS.
     if (this._domainSet.size == MAX_UNIQUE_VISITED_DOMAINS) {
       return;
     }
 
--- a/browser/modules/test/browser_UsageTelemetry.js
+++ b/browser/modules/test/browser_UsageTelemetry.js
@@ -1,16 +1,17 @@
 "use strict";
 
 const MAX_CONCURRENT_TABS = "browser.engagement.max_concurrent_tab_count";
 const TAB_EVENT_COUNT = "browser.engagement.tab_open_event_count";
 const MAX_CONCURRENT_WINDOWS = "browser.engagement.max_concurrent_window_count";
 const WINDOW_OPEN_COUNT = "browser.engagement.window_open_event_count";
 const TOTAL_URI_COUNT = "browser.engagement.total_uri_count";
 const UNIQUE_DOMAINS_COUNT = "browser.engagement.unique_domains_count";
+const UNFILTERED_URI_COUNT = "browser.engagement.unfiltered_uri_count";
 
 const TELEMETRY_SUBSESSION_TOPIC = "internal-telemetry-after-subsession-split";
 
 /**
  * Waits for the web progress listener associated with this tab to fire an
  * onLocationChange for a non-error page.
  *
  * @param {xul:browser} browser
@@ -54,191 +55,214 @@ let checkScalar = (scalars, scalarName, 
     return;
   }
   ok(!(scalarName in scalars), scalarName + " must not be reported.");
 };
 
 /**
  * Get a snapshot of the scalars and check them against the provided values.
  */
-let checkScalars = (maxTabs, tabOpenCount, maxWindows, windowsOpenCount, totalURIs, domainCount) => {
+let checkScalars = (countsObject) => {
   const scalars =
     Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
 
   // Check the expected values. Scalars that are never set must not be reported.
-  checkScalar(scalars, MAX_CONCURRENT_TABS, maxTabs,
+  checkScalar(scalars, MAX_CONCURRENT_TABS, countsObject.maxTabs,
               "The maximum tab count must match the expected value.");
-  checkScalar(scalars, TAB_EVENT_COUNT, tabOpenCount,
+  checkScalar(scalars, TAB_EVENT_COUNT, countsObject.tabOpenCount,
               "The number of open tab event count must match the expected value.");
-  checkScalar(scalars, MAX_CONCURRENT_WINDOWS, maxWindows,
+  checkScalar(scalars, MAX_CONCURRENT_WINDOWS, countsObject.maxWindows,
               "The maximum window count must match the expected value.");
-  checkScalar(scalars, WINDOW_OPEN_COUNT, windowsOpenCount,
+  checkScalar(scalars, WINDOW_OPEN_COUNT, countsObject.windowsOpenCount,
               "The number of window open event count must match the expected value.");
-  checkScalar(scalars, TOTAL_URI_COUNT, totalURIs,
+  checkScalar(scalars, TOTAL_URI_COUNT, countsObject.totalURIs,
               "The total URI count must match the expected value.");
-  checkScalar(scalars, UNIQUE_DOMAINS_COUNT, domainCount,
+  checkScalar(scalars, UNIQUE_DOMAINS_COUNT, countsObject.domainCount,
               "The unique domains count must match the expected value.");
+  checkScalar(scalars, UNFILTERED_URI_COUNT, countsObject.totalUnfilteredURIs,
+              "The unfiltered URI count must match the expected value.");
 };
 
 add_task(function* test_tabsAndWindows() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
 
   let openedTabs = [];
   let expectedTabOpenCount = 0;
   let expectedWinOpenCount = 0;
   let expectedMaxTabs = 0;
   let expectedMaxWins = 0;
 
   // Add a new tab and check that the count is right.
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
   expectedTabOpenCount = 1;
   expectedMaxTabs = 2;
-  checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount, 0, 0);
+  // This, and all the checks below, also check that initial pages (about:newtab, about:blank, ..)
+  // are not counted by the total_uri_count and the unfiltered_uri_count probes.
+  checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins,
+                windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0,
+                totalUnfilteredURIs: 0});
 
   // Add two new tabs in the same window.
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
   expectedTabOpenCount += 2;
   expectedMaxTabs += 2;
-  checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount, 0, 0);
+  checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins,
+                windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0,
+                totalUnfilteredURIs: 0});
 
   // Add a new window and then some tabs in it. An empty new windows counts as a tab.
   let win = yield BrowserTestUtils.openNewBrowserWindow();
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
   // The new window started with a new tab, so account for it.
   expectedTabOpenCount += 4;
   expectedWinOpenCount += 1;
   expectedMaxWins = 2;
   expectedMaxTabs += 4;
 
   // Remove a tab from the first window, the max shouldn't change.
   yield BrowserTestUtils.removeTab(openedTabs.pop());
-  checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount, 0, 0);
+  checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins,
+                windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0,
+                totalUnfilteredURIs: 0});
 
   // Remove all the extra windows and tabs.
   for (let tab of openedTabs) {
     yield BrowserTestUtils.removeTab(tab);
   }
   yield BrowserTestUtils.closeWindow(win);
 
   // Make sure all the scalars still have the expected values.
-  checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount, 0, 0);
+  checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins,
+                windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0,
+                totalUnfilteredURIs: 0});
 });
 
 add_task(function* test_subsessionSplit() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
 
   // Add a new window (that will have 4 tabs).
   let win = yield BrowserTestUtils.openNewBrowserWindow();
   let openedTabs = [];
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
-  openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
+  openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:mozilla"));
   openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://www.example.com"));
 
-  // Check that the scalars have the right values.
-  checkScalars(5 /*maxTabs*/, 4 /*tabOpen*/, 2 /*maxWins*/, 1 /*winOpen*/,
-               1 /* toalURIs */, 1 /* uniqueDomains */);
+  // Check that the scalars have the right values. We expect 2 unfiltered URI loads
+  // (about:mozilla and www.example.com, but no about:blank) and 1 URI totalURIs
+  // (only www.example.com).
+  checkScalars({maxTabs: 5, tabOpenCount: 4, maxWindows: 2, windowsOpenCount: 1,
+                totalURIs: 1, domainCount: 1, totalUnfilteredURIs: 2});
 
   // Remove a tab.
   yield BrowserTestUtils.removeTab(openedTabs.pop());
 
   // Simulate a subsession split by clearing the scalars (via |snapshotScalars|) and
   // notifying the subsession split topic.
   Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
                                      true /* clearScalars*/);
   Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC, "");
 
   // After a subsession split, only the MAX_CONCURRENT_* scalars must be available
-  // and have the correct value. No tabs or windows were opened so other scalars
+  // and have the correct value. No tabs, windows or URIs were opened so other scalars
   // must not be reported.
-  checkScalars(4 /*maxTabs*/, 0 /*tabOpen*/, 2 /*maxWins*/, 0 /*winOpen*/,
-               0 /* toalURIs */, 0 /* uniqueDomains */);
+  checkScalars({maxTabs: 4, tabOpenCount: 0, maxWindows: 2, windowsOpenCount: 0,
+                totalURIs: 0, domainCount: 0, totalUnfilteredURIs: 0});
 
   // Remove all the extra windows and tabs.
   for (let tab of openedTabs) {
     yield BrowserTestUtils.removeTab(tab);
   }
   yield BrowserTestUtils.closeWindow(win);
 });
 
 add_task(function* test_URIAndDomainCounts() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
 
-  let checkCounts = (URICount, domainCount) => {
+  let checkCounts = (countsObject) => {
     // Get a snapshot of the scalars and then clear them.
     const scalars =
       Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-    checkScalar(scalars, TOTAL_URI_COUNT, URICount,
+    checkScalar(scalars, TOTAL_URI_COUNT, countsObject.totalURIs,
                 "The URI scalar must contain the expected value.");
-    checkScalar(scalars, UNIQUE_DOMAINS_COUNT, domainCount,
+    checkScalar(scalars, UNIQUE_DOMAINS_COUNT, countsObject.domainCount,
                 "The unique domains scalar must contain the expected value.");
+    checkScalar(scalars, UNFILTERED_URI_COUNT, countsObject.totalUnfilteredURIs,
+                "The unfiltered URI scalar must contain the expected value.");
   };
 
   // Check that about:blank doesn't get counted in the URI total.
   let firstTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
-  checkCounts(0, 0);
+  checkCounts({totalURIs: 0, domainCount: 0, totalUnfilteredURIs: 0});
 
   // Open a different page and check the counts.
   yield BrowserTestUtils.loadURI(firstTab.linkedBrowser, "http://example.com/");
   yield BrowserTestUtils.browserLoaded(firstTab.linkedBrowser);
-  checkCounts(1, 1);
+  checkCounts({totalURIs: 1, domainCount: 1, totalUnfilteredURIs: 1});
 
   // Activating a different tab must not increase the URI count.
   let secondTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
   yield BrowserTestUtils.switchTab(gBrowser, firstTab);
-  checkCounts(1, 1);
+  checkCounts({totalURIs: 1, domainCount: 1, totalUnfilteredURIs: 1});
   yield BrowserTestUtils.removeTab(secondTab);
 
   // Open a new window and set the tab to a new address.
   let newWin = yield BrowserTestUtils.openNewBrowserWindow();
   yield BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, "http://example.com/");
   yield BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser);
-  checkCounts(2, 1);
+  checkCounts({totalURIs: 2, domainCount: 1, totalUnfilteredURIs: 2});
 
   // We should not count AJAX requests.
   const XHR_URL = "http://example.com/r";
   yield ContentTask.spawn(newWin.gBrowser.selectedBrowser, XHR_URL, function(url) {
     return new Promise(resolve => {
       var xhr = new content.window.XMLHttpRequest();
       xhr.open("GET", url);
       xhr.onload = () => resolve();
       xhr.send();
     });
   });
-  checkCounts(2, 1);
+  checkCounts({totalURIs: 2, domainCount: 1, totalUnfilteredURIs: 2});
 
   // Check that we're counting page fragments.
   let loadingStopped = browserLocationChanged(newWin.gBrowser.selectedBrowser);
   yield BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, "http://example.com/#2");
   yield loadingStopped;
-  checkCounts(3, 1);
+  checkCounts({totalURIs: 3, domainCount: 1, totalUnfilteredURIs: 3});
 
-  // Check test.domain.com and some.domain.com are only counted once unique.
+  // Check that a different URI from the example.com domain doesn't increment the unique count.
   yield BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, "http://test1.example.com/");
   yield BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser);
-  checkCounts(4, 1);
+  checkCounts({totalURIs: 4, domainCount: 1, totalUnfilteredURIs: 4});
 
   // Make sure that the unique domains counter is incrementing for a different domain.
   yield BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, "https://example.org/");
   yield BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser);
-  checkCounts(5, 2);
+  checkCounts({totalURIs: 5, domainCount: 2, totalUnfilteredURIs: 5});
 
   // Check that we only account for top level loads (e.g. we don't count URIs from
   // embedded iframes).
   yield ContentTask.spawn(newWin.gBrowser.selectedBrowser, null, function* () {
     let doc = content.document;
     let iframe = doc.createElement("iframe");
     let promiseIframeLoaded = ContentTaskUtils.waitForEvent(iframe, "load", false);
     iframe.src = "https://example.org/test";
     doc.body.insertBefore(iframe, doc.body.firstChild);
     yield promiseIframeLoaded;
   });
-  checkCounts(5, 2);
+  checkCounts({totalURIs: 5, domainCount: 2, totalUnfilteredURIs: 5});
+
+  // Check that uncommon protocols get counted in the unfiltered URI probe.
+  const TEST_PAGE =
+    "data:text/html,<a id='target' href='%23par1'>Click me</a><a name='par1'>The paragraph.</a>";
+  yield BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, TEST_PAGE);
+  yield BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser);
+  checkCounts({totalURIs: 5, domainCount: 2, totalUnfilteredURIs: 6});
 
   // Clean up.
   yield BrowserTestUtils.removeTab(firstTab);
   yield BrowserTestUtils.closeWindow(newWin);
 });
--- a/browser/modules/test/browser_UsageTelemetry_private_and_restore.js
+++ b/browser/modules/test/browser_UsageTelemetry_private_and_restore.js
@@ -1,15 +1,16 @@
 "use strict";
 
 const MAX_CONCURRENT_TABS = "browser.engagement.max_concurrent_tab_count";
 const TAB_EVENT_COUNT = "browser.engagement.tab_open_event_count";
 const MAX_CONCURRENT_WINDOWS = "browser.engagement.max_concurrent_window_count";
 const WINDOW_OPEN_COUNT = "browser.engagement.window_open_event_count";
 const TOTAL_URI_COUNT = "browser.engagement.total_uri_count";
+const UNFILTERED_URI_COUNT = "browser.engagement.unfiltered_uri_count";
 const UNIQUE_DOMAINS_COUNT = "browser.engagement.unique_domains_count";
 
 function promiseBrowserStateRestored() {
   return new Promise(resolve => {
      Services.obs.addObserver(function observer(aSubject, aTopic) {
        Services.obs.removeObserver(observer, "sessionstore-browser-state-restored");
        resolve();
      }, "sessionstore-browser-state-restored", false);
@@ -25,16 +26,17 @@ add_task(function* test_privateMode() {
   yield BrowserTestUtils.loadURI(privateWin.gBrowser.selectedBrowser, "http://example.com/");
   yield BrowserTestUtils.browserLoaded(privateWin.gBrowser.selectedBrowser);
 
   // Check that tab and window count is recorded.
   const scalars =
     Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
 
   ok(!(TOTAL_URI_COUNT in scalars), "We should not track URIs in private mode.");
+  ok(!(UNFILTERED_URI_COUNT in scalars), "We should not track URIs in private mode.");
   ok(!(UNIQUE_DOMAINS_COUNT in scalars), "We should not track unique domains in private mode.");
   is(scalars[TAB_EVENT_COUNT], 1, "The number of open tab event count must match the expected value.");
   is(scalars[MAX_CONCURRENT_TABS], 2, "The maximum tab count must match the expected value.");
   is(scalars[WINDOW_OPEN_COUNT], 1, "The number of window open event count must match the expected value.");
   is(scalars[MAX_CONCURRENT_WINDOWS], 2, "The maximum window count must match the expected value.");
 
   // Clean up.
   yield BrowserTestUtils.closeWindow(privateWin);
@@ -74,15 +76,16 @@ add_task(function* test_sessionRestore()
   SessionStore.setBrowserState(JSON.stringify(state));
   yield tabRestored;
 
   // Check that the URI is not recorded.
   const scalars =
     Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
 
   ok(!(TOTAL_URI_COUNT in scalars), "We should not track URIs from restored sessions.");
+  ok(!(UNFILTERED_URI_COUNT in scalars), "We should not track URIs from restored sessions.");
   ok(!(UNIQUE_DOMAINS_COUNT in scalars), "We should not track unique domains from restored sessions.");
 
   // Restore the original session and cleanup.
   let sessionRestored = promiseBrowserStateRestored();
   SessionStore.setBrowserState(JSON.stringify(state));
   yield sessionRestored;
 });
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -62,16 +62,30 @@ browser.engagement:
       page reloads, after the session has been restored. This does not include background
       page requests and URIs from embedded pages or private browsing.
     expires: "55"
     kind: uint
     notification_emails:
       - rweiss@mozilla.com
     release_channel_collection: opt-out
 
+  unfiltered_uri_count:
+    bug_numbers:
+      - 1304647
+    description: >
+      The count of the total non-unique URIs visited in a subsession, not restricted to
+      a specific protocol, including page reloads and about:* pages (other than initial
+      pages such as about:blank, ...), after the session has been restored. This does
+      not include background page requests and URIs from embedded pages or private browsing.
+    expires: "55"
+    kind: uint
+    notification_emails:
+      - bcolloran@mozilla.com
+    release_channel_collection: opt-out
+
   unique_domains_count:
     bug_numbers:
       - 1271310
     description: >
       The count of the unique domains visited in a subsession, after the session
       has been restored. Subdomains under eTLD are aggregated after the first level
       (i.e. test.example.com and other.example.com are only counted once).
       This does not include background page requests and domains from embedded pages