From 920545b0be48e40fc105fb723d0de6b7329aafe6 Mon Sep 17 00:00:00 2001 From: Mathieu Leplatre Date: Thu, 5 Nov 2026 12:16:46 +0100 Subject: [PATCH] chore(remote-settings): RMST-586: Use glean-sym --- Cargo.lock | 2 + components/remote_settings/Cargo.toml | 5 +++ components/remote_settings/build.rs | 11 ++++++ components/remote_settings/metrics.yaml | 11 +++--- components/remote_settings/src/lib.rs | 5 +++ components/remote_settings/src/service.rs | 1 + components/remote_settings/src/telemetry.rs | 41 +++++++++++++++++++-- 7 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 components/remote_settings/build.rs diff --git a/Cargo.lock b/Cargo.lock index 9069eedbc5b..2ebe4ff54dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3943,6 +3943,8 @@ dependencies = [ "error-support", "expect-test", "firefox-versioning", + "glean-build", + "glean-sym", "jexl-eval", "mockall", "mockito", diff --git a/components/remote_settings/Cargo.toml b/components/remote_settings/Cargo.toml index 12cb09646b6..437ce7c31d7 100644 --- a/components/remote_settings/Cargo.toml +++ b/components/remote_settings/Cargo.toml @@ -13,6 +13,9 @@ default = [] signatures = ["dep:canonical_json", "dep:rc_crypto"] # submitting glean telemetry is tricky on desktop for now. telemetry-submission = [] +# Record metrics directly from Rust via glean-sym, instead of through the +# `RemoteSettingsTelemetry` foreign callback. +glean-sym = ["dep:glean-sym", "glean-sym/active"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -35,9 +38,11 @@ firefox-versioning = { path = "../support/firefox-versioning" } sha2 = "^0.10" canonical_json = { version = "0.5", optional = true } rc_crypto = { path = "../support/rc_crypto", optional = true } +glean-sym = { version = "71", optional = true } [build-dependencies] uniffi = { version = "0.32", features = ["build"] } +glean-build = { git = "https://github.com/mozilla/glean", tag = "v71.0.0" } [dev-dependencies] expect-test = "1.4" diff --git a/components/remote_settings/build.rs b/components/remote_settings/build.rs new file mode 100644 index 00000000000..faad658f00b --- /dev/null +++ b/components/remote_settings/build.rs @@ -0,0 +1,11 @@ +/* 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/. */ + +fn main() { + glean_build::Builder::default() + .file("metrics.yaml") + .format("rust_sym") + .generate() + .expect("Error generating Glean Rust bindings"); +} diff --git a/components/remote_settings/metrics.yaml b/components/remote_settings/metrics.yaml index 35e2644c011..0f958c8d9e5 100644 --- a/components/remote_settings/metrics.yaml +++ b/components/remote_settings/metrics.yaml @@ -5,11 +5,12 @@ # This file defines the metrics that will be gathered for the Remote Settings # component. Changes to these metrics require data review. # -# We can't record metrics from Rust directly. To work around that we: -# - Define the metrics in application-services -# - Define API calls in application-services that return the metrics -# alongside the normal results. -# - Record the metrics with Glean in the consumer code +# Metrics are recorded in one of two ways: +# - With the `glean-sym` feature, they are recorded directly from Rust. +# `build.rs` generates the Rust bindings from this file, and `glean-sym` +# does the magic at runtime. +# - Otherwise, the consumer (Android, iOS) implements the `RemoteSettingsTelemetry` +# trait and records the metrics with its own Glean-generated bindings. --- $schema: moz://mozilla.org/schemas/glean/metrics/2-0-0 diff --git a/components/remote_settings/src/lib.rs b/components/remote_settings/src/lib.rs index 9c5f80b194a..d8cc0f516c3 100644 --- a/components/remote_settings/src/lib.rs +++ b/components/remote_settings/src/lib.rs @@ -20,6 +20,11 @@ pub mod telemetry; pub(crate) mod jexl_filter; mod macros; +#[cfg(feature = "glean-sym")] +mod glean_metrics { + include!(concat!(env!("OUT_DIR"), "/glean_metrics.rs")); +} + pub use client::{Attachment, RemoteSettingsRecord, RsJsonObject}; pub use config::{BaseUrl, RemoteSettingsConfig, RemoteSettingsServer}; pub use context::RemoteSettingsContext; diff --git a/components/remote_settings/src/service.rs b/components/remote_settings/src/service.rs index 4c955913905..80ea6691d95 100644 --- a/components/remote_settings/src/service.rs +++ b/components/remote_settings/src/service.rs @@ -91,6 +91,7 @@ impl RemoteSettingsService { client: Client::new(ClientSettings::default()), remote_state: RemoteState::default(), }), + // TODO: elegant plug and play here? telemetry: Mutex::new(RemoteSettingsTelemetryWrapper::noop()), } } diff --git a/components/remote_settings/src/telemetry.rs b/components/remote_settings/src/telemetry.rs index 1a94f137487..4f66898d4b8 100644 --- a/components/remote_settings/src/telemetry.rs +++ b/components/remote_settings/src/telemetry.rs @@ -94,6 +94,8 @@ impl RemoteSettingsTelemetry for NoopRemoteSettingsTelemetry { /// Wrapper around [RemoteSettingsTelemetry] used internally. #[derive(Clone)] pub struct RemoteSettingsTelemetryWrapper { + // Unused with `glean-sym`: metrics are recorded directly from Rust. + #[cfg_attr(feature = "glean-sym", allow(dead_code))] inner: Arc, } @@ -108,8 +110,40 @@ impl RemoteSettingsTelemetryWrapper { } } + #[cfg(feature = "glean-sym")] + fn report_uptake(&self, event: UptakeEventExtras) { + // With glean-sym, telemetry is sent directly from the + // Glean SDK. The wrapped inner implementation is not + // called. + // This allows us to transition to glean-sym without + // breaking changes. + // Once this ships and gets enabled in builds, we can + // remove the telemetry wrapper code in iOS and Android. + use crate::glean_metrics::remote_settings::{ + uptake_remotesettings, UptakeRemotesettingsExtra, + }; + uptake_remotesettings.record(UptakeRemotesettingsExtra { + value: event.value, + source: event.source, + age: event.age, + trigger: event.trigger, + timestamp: event.timestamp, + duration: event.duration, + errorname: event.error_name, + }); + } + + #[cfg(not(feature = "glean-sym"))] + fn report_uptake(&self, event: UptakeEventExtras) { + // Call the native implementation of Glean. + // Note: feature is disabled on desktop. + // When `glean-sym` is enabled, the wrapper isn't called at all + // and events are sent directly by the Glean SDK. + self.inner.report_uptake(event) + } + pub fn report_uptake_success(&self, source: &str, duration: Option) { - self.inner.report_uptake(UptakeEventExtras { + self.report_uptake(UptakeEventExtras { value: Some(SyncStatus::Success.to_string()), source: Some(source.to_string()), age: None, @@ -121,7 +155,7 @@ impl RemoteSettingsTelemetryWrapper { } pub fn report_uptake_up_to_date(&self, source: &str, duration: Option) { - self.inner.report_uptake(UptakeEventExtras { + self.report_uptake(UptakeEventExtras { value: Some(SyncStatus::UpToDate.to_string()), source: Some(source.to_string()), age: None, @@ -143,7 +177,8 @@ impl RemoteSettingsTelemetryWrapper { .unwrap_or("") .trim() .to_string(); - self.inner.report_uptake(UptakeEventExtras { + + self.report_uptake(UptakeEventExtras { value: Some(error_to_status(error).to_string()), source: Some(source.to_string()), age: None,