Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

[Full changelog](https://github.com/mozilla/glean.js/compare/v3.0.0...main)

* [#1835](https://github.com/mozilla/glean.js/pull/1835): Automatic instrumentation of page load events for simple web properties.

# v3.0.0 (2023-11-16)

[Full changelog](https://github.com/mozilla/glean.js/compare/v3.0.0-pre.1...v3.0.0)
Expand Down
16 changes: 13 additions & 3 deletions automation/compat/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { benchmark } from "./generated/pings.js";
import * as metrics from "./generated/sample.js";

Glean.setSourceTags(["automation"]);
Glean.initialize("glean-compat-benchmark", true);
Glean.initialize("glean-compat-benchmark", true, {
enableAutoPageLoadEvents: true
});

metrics.pageLoaded.set();
benchmark.submit();
Expand All @@ -18,6 +20,7 @@ benchmark.submit();
//
// Overwrite the console.info function in order to know when (and if) the benchmark ping was sent.
// If a success ping message is logged we show that in the document.
let pingSubmissionCount = 0;
console.info = function () {
var message = "";
for (var i = 0; i < arguments.length; i++) {
Expand All @@ -29,7 +32,14 @@ console.info = function () {
}
console.log(message);
if (/successfully sent 200.$/.test(message)) {
var elem = document.getElementById("msg");
elem.innerHTML = "Ping submitted successfully.";
pingSubmissionCount++;

// Two pings should be submitted when run successfully
// 1. The built-in page_load event, which submits an events ping.
// 2. The benchmark ping.
if (pingSubmissionCount == 2) {
var elem = document.getElementById("msg");
elem.innerHTML = "Pings submitted successfully.";
}
}
}
2 changes: 1 addition & 1 deletion automation/compat/tests/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export async function runWebTest(driver) {
await driver.wait(
until.elementTextIs(
successTextContainer,
"Ping submitted successfully."
"Pings submitted successfully."
), 11_000); // 1s more than the default upload timeout in Glean.

console.log("Test passed.");
Expand Down
6 changes: 5 additions & 1 deletion glean/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"./private/ping": "./dist/core/pings/ping_type.js",
"./uploader": "./dist/core/upload/uploader.js",
"./testing": "./dist/core/testing/index.js",
"./web": "./dist/entry/web.js"
"./web": "./dist/entry/web.js",
"./metrics": "./dist/core/glean_metrics.js"
},
"typesVersions": {
"*": {
Expand All @@ -32,6 +33,9 @@
],
"error": [
"./dist/types/core/error/error_type.d.ts"
],
"metrics": [
"./dist/types/core/glean_metrics.d.ts"
]
}
},
Expand Down
5 changes: 5 additions & 0 deletions glean/src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export interface ConfigurationInterface {
// Migrate from legacy storage (IndexedDB) to the new one (LocalStorage).
// This should only be true for older projects that have existing data in IndexedDB.
readonly migrateFromLegacyStorage?: boolean,
// Allow the client to explicitly specify whether they want page load events to be
// collected automatically.
readonly enableAutoPageLoadEvents?: boolean,
}

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

// Debug configuration.
debug: DebugOptions;
Expand All @@ -71,6 +75,7 @@ export class Configuration implements ConfigurationInterface {
this.buildDate = config?.buildDate;
this.maxEvents = config?.maxEvents || DEFAULT_MAX_EVENTS;
this.migrateFromLegacyStorage = config?.migrateFromLegacyStorage;
this.enableAutoPageLoadEvents = config?.enableAutoPageLoadEvents;

this.debug = {};

Expand Down
7 changes: 7 additions & 0 deletions glean/src/core/glean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import MetricsDatabase from "./metrics/database.js";
import EventsDatabase from "./metrics/events_database/index.js";
import PingsDatabase from "./pings/database.js";
import ErrorManager from "./error/index.js";
import GleanMetrics from "./glean_metrics.js";

const LOG_TAG = "core.Glean";

Expand Down Expand Up @@ -318,6 +319,12 @@ namespace Glean {
onUploadEnabled();
initializeCoreMetrics(config?.migrateFromLegacyStorage);

// Record a page load event if the client has auto page-load events enabled.
if (config?.enableAutoPageLoadEvents) {
// This function call has no parameters because auto-instrumentation
// means there are no overrides.
GleanMetrics.pageLoad();
}
} else {
// If upload is disabled, and we've never run before, only set the
// client_id to KNOWN_CLIENT_ID, but do not send a deletion request
Expand Down
84 changes: 84 additions & 0 deletions glean/src/core/glean_metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* 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/. */

import { Context } from "./context.js";
import EventMetricType from "./metrics/types/event.js";
import { EVENTS_PING_NAME } from "./constants.js";
import { Lifetime } from "./metrics/lifetime.js";
import log, { LoggingLevel } from "./log.js";

const LOG_TAG = "core.glean_metrics";

interface PageLoadParams {
url?: string;
referrer?: string;
title?: string;
}

/**
* This namespace contains functions to support Glean's auto-instrumentation
* capability. These functions are either running automatically if enabled
* via the Glean config or they are called manually by the client.
*/
namespace GleanMetrics {
// Object to hold all automatic instrumentation metrics.
const metrics = {
pageLoad: new EventMetricType(
{
category: "glean",
name: "page_load",
sendInPings: [EVENTS_PING_NAME],
lifetime: Lifetime.Ping,
disabled: false,
},
// Page load extras defined in `src/metrics.yaml`.
["url", "referrer", "title"]
)
};

/**
* For a standard web project `initialize` is called every time a page
* loads. For every page load if the client has auto page loads enabled,
* we will record a page load event.
*
* @param overrides Overrides for each page_load extra key.
*/
export function pageLoad(overrides?: PageLoadParams) {
// Cannot record an event if Glean has not been initialized.
if (!Context.initialized) {
log(
LOG_TAG,
"Attempted to record a page load event before Glean was initialized. This is a no-op.",
LoggingLevel.Warn
);
return;
}

// Each key defaults to the override. If no override is provided, we fall
// back to the default value IF the `window` or the `document` objects
// are available.
//
// If neither of those are available, then we default to a value that shows
// that no value is available.
metrics.pageLoad.record({
url:
overrides?.url ?? (typeof window !== "undefined"
? window.location.href
: "URL_NOT_PROVIDED_OR_AVAILABLE"
),
referrer:
overrides?.referrer ?? (typeof document !== "undefined"
? document.referrer
: "REFERRER_NOT_PROVIDED_OR_AVAILABLE"
),
title:
overrides?.title ?? (typeof document !== "undefined"
? document.title
: "TITLE_NOT_PROVIDED_OR_AVAILABLE"
),
});
}
}

export default GleanMetrics;
29 changes: 29 additions & 0 deletions glean/src/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,32 @@ glean:
notification_emails:
- glean-team@mozilla.com
expires: never
page_load:
type: event
description: |
A event triggered whenever a page is loaded.

**This event by default is not collected automatically. This can be
turned on by the client in the Glean configuration object
(`enableAutoPageLoadEvents`). Glean provides a separate API for
collecting the same page load data if the client wants to collect
page loads manually.**
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1867126
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1867126#c8
data_sensitivity:
- interaction
notification_emails:
- glean-team@mozilla.com
expires: never
extra_keys:
url:
description: The page URL.
type: string
referrer:
description: The page referrer.
type: string
title:
description: The page title.
type: string