Skip to content

Commit f4beced

Browse files
authored
Merge pull request #1835 from rosahbruno/page-loads
Bug 1867126 - automatic page load instrumentation
2 parents 498a54a + 057b212 commit f4beced

File tree

8 files changed

+146
-5
lines changed

8 files changed

+146
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
[#1808](https://github.com/mozilla/glean.js/pull/1808): **BREAKING CHANGE**: Make glean.js fully synchronous.
1616

17+
* [#1835](https://github.com/mozilla/glean.js/pull/1835): Automatic instrumentation of page load events for simple web properties.
18+
1719
# v3.0.0 (2023-11-16)
1820

1921
[Full changelog](https://github.com/mozilla/glean.js/compare/v3.0.0-pre.1...v3.0.0)

automation/compat/index.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import { benchmark } from "./generated/pings.js";
99
import * as metrics from "./generated/sample.js";
1010

1111
Glean.setSourceTags(["automation"]);
12-
Glean.initialize("glean-compat-benchmark", true);
12+
Glean.initialize("glean-compat-benchmark", true, {
13+
enableAutoPageLoadEvents: true
14+
});
1315

1416
metrics.pageLoaded.set();
1517
benchmark.submit();
@@ -18,6 +20,7 @@ benchmark.submit();
1820
//
1921
// Overwrite the console.info function in order to know when (and if) the benchmark ping was sent.
2022
// If a success ping message is logged we show that in the document.
23+
let pingSubmissionCount = 0;
2124
console.info = function () {
2225
var message = "";
2326
for (var i = 0; i < arguments.length; i++) {
@@ -29,7 +32,14 @@ console.info = function () {
2932
}
3033
console.log(message);
3134
if (/successfully sent 200.$/.test(message)) {
32-
var elem = document.getElementById("msg");
33-
elem.innerHTML = "Ping submitted successfully.";
35+
pingSubmissionCount++;
36+
37+
// Two pings should be submitted when run successfully
38+
// 1. The built-in page_load event, which submits an events ping.
39+
// 2. The benchmark ping.
40+
if (pingSubmissionCount == 2) {
41+
var elem = document.getElementById("msg");
42+
elem.innerHTML = "Pings submitted successfully.";
43+
}
3444
}
3545
}

automation/compat/tests/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export async function runWebTest(driver) {
101101
await driver.wait(
102102
until.elementTextIs(
103103
successTextContainer,
104-
"Ping submitted successfully."
104+
"Pings submitted successfully."
105105
), 11_000); // 1s more than the default upload timeout in Glean.
106106

107107
console.log("Test passed.");

glean/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"./private/ping": "./dist/core/pings/ping_type.js",
1212
"./uploader": "./dist/core/upload/uploader.js",
1313
"./testing": "./dist/core/testing/index.js",
14-
"./web": "./dist/entry/web.js"
14+
"./web": "./dist/entry/web.js",
15+
"./metrics": "./dist/core/glean_metrics.js"
1516
},
1617
"typesVersions": {
1718
"*": {
@@ -32,6 +33,9 @@
3233
],
3334
"error": [
3435
"./dist/types/core/error/error_type.d.ts"
36+
],
37+
"metrics": [
38+
"./dist/types/core/glean_metrics.d.ts"
3539
]
3640
}
3741
},

glean/src/core/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export interface ConfigurationInterface {
4747
// Migrate from legacy storage (IndexedDB) to the new one (LocalStorage).
4848
// This should only be true for older projects that have existing data in IndexedDB.
4949
readonly migrateFromLegacyStorage?: boolean,
50+
// Allow the client to explicitly specify whether they want page load events to be
51+
// collected automatically.
52+
readonly enableAutoPageLoadEvents?: boolean,
5053
}
5154

5255
// Important: the `Configuration` should only be used internally by the Glean singleton.
@@ -58,6 +61,7 @@ export class Configuration implements ConfigurationInterface {
5861
readonly buildDate?: Date;
5962
readonly maxEvents: number;
6063
readonly migrateFromLegacyStorage?: boolean;
64+
readonly enableAutoPageLoadEvents?: boolean;
6165

6266
// Debug configuration.
6367
debug: DebugOptions;
@@ -71,6 +75,7 @@ export class Configuration implements ConfigurationInterface {
7175
this.buildDate = config?.buildDate;
7276
this.maxEvents = config?.maxEvents || DEFAULT_MAX_EVENTS;
7377
this.migrateFromLegacyStorage = config?.migrateFromLegacyStorage;
78+
this.enableAutoPageLoadEvents = config?.enableAutoPageLoadEvents;
7479

7580
this.debug = {};
7681

glean/src/core/glean.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import MetricsDatabase from "./metrics/database.js";
1919
import EventsDatabase from "./metrics/events_database/index.js";
2020
import PingsDatabase from "./pings/database.js";
2121
import ErrorManager from "./error/index.js";
22+
import GleanMetrics from "./glean_metrics.js";
2223

2324
const LOG_TAG = "core.Glean";
2425

@@ -317,6 +318,12 @@ namespace Glean {
317318
onUploadEnabled();
318319
initializeCoreMetrics(config?.migrateFromLegacyStorage);
319320

321+
// Record a page load event if the client has auto page-load events enabled.
322+
if (config?.enableAutoPageLoadEvents) {
323+
// This function call has no parameters because auto-instrumentation
324+
// means there are no overrides.
325+
GleanMetrics.pageLoad();
326+
}
320327
} else {
321328
// If upload is disabled, and we've never run before, only set the
322329
// client_id to KNOWN_CLIENT_ID, but do not send a deletion request

glean/src/core/glean_metrics.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { Context } from "./context.js";
6+
import EventMetricType from "./metrics/types/event.js";
7+
import { EVENTS_PING_NAME } from "./constants.js";
8+
import { Lifetime } from "./metrics/lifetime.js";
9+
import log, { LoggingLevel } from "./log.js";
10+
11+
const LOG_TAG = "core.glean_metrics";
12+
13+
interface PageLoadParams {
14+
url?: string;
15+
referrer?: string;
16+
title?: string;
17+
}
18+
19+
/**
20+
* This namespace contains functions to support Glean's auto-instrumentation
21+
* capability. These functions are either running automatically if enabled
22+
* via the Glean config or they are called manually by the client.
23+
*/
24+
namespace GleanMetrics {
25+
// Object to hold all automatic instrumentation metrics.
26+
const metrics = {
27+
pageLoad: new EventMetricType(
28+
{
29+
category: "glean",
30+
name: "page_load",
31+
sendInPings: [EVENTS_PING_NAME],
32+
lifetime: Lifetime.Ping,
33+
disabled: false,
34+
},
35+
// Page load extras defined in `src/metrics.yaml`.
36+
["url", "referrer", "title"]
37+
)
38+
};
39+
40+
/**
41+
* For a standard web project `initialize` is called every time a page
42+
* loads. For every page load if the client has auto page loads enabled,
43+
* we will record a page load event.
44+
*
45+
* @param overrides Overrides for each page_load extra key.
46+
*/
47+
export function pageLoad(overrides?: PageLoadParams) {
48+
// Cannot record an event if Glean has not been initialized.
49+
if (!Context.initialized) {
50+
log(
51+
LOG_TAG,
52+
"Attempted to record a page load event before Glean was initialized. This is a no-op.",
53+
LoggingLevel.Warn
54+
);
55+
return;
56+
}
57+
58+
// Each key defaults to the override. If no override is provided, we fall
59+
// back to the default value IF the `window` or the `document` objects
60+
// are available.
61+
//
62+
// If neither of those are available, then we default to a value that shows
63+
// that no value is available.
64+
metrics.pageLoad.record({
65+
url:
66+
overrides?.url ?? (typeof window !== "undefined"
67+
? window.location.href
68+
: "URL_NOT_PROVIDED_OR_AVAILABLE"
69+
),
70+
referrer:
71+
overrides?.referrer ?? (typeof document !== "undefined"
72+
? document.referrer
73+
: "REFERRER_NOT_PROVIDED_OR_AVAILABLE"
74+
),
75+
title:
76+
overrides?.title ?? (typeof document !== "undefined"
77+
? document.title
78+
: "TITLE_NOT_PROVIDED_OR_AVAILABLE"
79+
),
80+
});
81+
}
82+
}
83+
84+
export default GleanMetrics;

glean/src/metrics.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,32 @@ glean:
413413
notification_emails:
414414
- glean-team@mozilla.com
415415
expires: never
416+
page_load:
417+
type: event
418+
description: |
419+
A event triggered whenever a page is loaded.
420+
421+
**This event by default is not collected automatically. This can be
422+
turned on by the client in the Glean configuration object
423+
(`enableAutoPageLoadEvents`). Glean provides a separate API for
424+
collecting the same page load data if the client wants to collect
425+
page loads manually.**
426+
bugs:
427+
- https://bugzilla.mozilla.org/show_bug.cgi?id=1867126
428+
data_reviews:
429+
- https://bugzilla.mozilla.org/show_bug.cgi?id=1867126#c8
430+
data_sensitivity:
431+
- interaction
432+
notification_emails:
433+
- glean-team@mozilla.com
434+
expires: never
435+
extra_keys:
436+
url:
437+
description: The page URL.
438+
type: string
439+
referrer:
440+
description: The page referrer.
441+
type: string
442+
title:
443+
description: The page title.
444+
type: string

0 commit comments

Comments
 (0)