Skip to content

Commit

Permalink
Add extensionTelemetry (#10057)
Browse files Browse the repository at this point in the history
* Add extension metrics to extension session ping

- Added extension_metrics.yaml file to the telemetry directory.
- Defined new metrics for extension usage, including onboarding completion, feature usage, and website exclusions.
- Added extension_metrics.yaml to the list of metrics sent in the extensionsession ping.
- Updated pings.yaml to include extensionsession as a new ping type.
- Included client ID in extensionsession ping.
- Updated bugs, data reviews, and notification emails for the new metrics.
- Added reasons for sending extensionsession ping on session start and end.
- Updated comments to reflect changes.

* Add support for WebExtension Telemetry

- Added a new `WebExtensionTelemetry` class to handle WebExtension telemetry events.
- Implemented `fromJson` function to parse JSON telemetry data into `TelemetryInfo` objects.
- Added `recordTelemetry` function to record telemetry events to Glean.
- Implemented `startSession` and `stopSession` functions to track session start and end events.
- Added new handlers for various telemetry events and flags in `handlers.cpp`.
- Updated `webextensionadapter.cpp` to handle telemetry requests.
- Updated `pings.yaml` to include new telemetry pings.
- Updated `webextensiontelemetry.h` to define new telemetry functions and structures.

* Allow filtering on a per-ping basis

* Use glean lifetimes instead of homebrewed stuff

* Address feedback in metrics_yaml

* Address feedback in pings.yaml

* fix typos in c++

* Update upload enablement in MZGlean

- Update MZGlean::upadateUploadEnabled() to MZGlean::updateUploadEnabled() for consistency in naming.
- Ensure that the static function updateUploadEnabled() is called correctly in the MZGlean class.
- Update the documentation comments for clarity and consistency.

* Update flag handling in webextensiontelemetry.cpp

- Changed the function declaration of `flag` from `consteval` to `constexpr` to ensure that it is a compile-time constant expression.
- This change ensures that the function is not evaluated at runtime, improving performance and avoiding potential issues with runtime evaluation.
  • Loading branch information
strseb authored Dec 4, 2024
1 parent 554cf92 commit 2aa9528
Show file tree
Hide file tree
Showing 13 changed files with 542 additions and 19 deletions.
1 change: 1 addition & 0 deletions qtglean/glean_parser_ext/run_glean_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def create_dir(path):
]
metrics_files = [
os.path.join(telemetry_path, "metrics.yaml"),
os.path.join(telemetry_path, "extension_metrics.yaml"),
os.path.join(telemetry_path, "interaction_metrics.yaml"),
os.path.join(telemetry_path, "impression_metrics.yaml"),
os.path.join(telemetry_path, "outcome_metrics.yaml"),
Expand Down
19 changes: 18 additions & 1 deletion qtglean/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use glean::{ClientInfoMetrics, Configuration};

use ffi::helpers::FallibleToString;
use metrics::__generated_pings::register_pings;
use once_cell::sync::Lazy;
use std::sync::Mutex;
use std::sync::Arc;
use uploader::VPNPingUploader;
use logger::Logger;

Expand All @@ -23,6 +26,9 @@ mod logger;

const GLEAN_APPLICATION_ID: &str = "mozillavpn";

static GLOBAL_PING_FILTER_LIST : Lazy<Arc<Mutex<Vec<String>>>> = Lazy::new(|| Arc::new(Mutex::new(Vec::new())));


#[no_mangle]
pub extern "C" fn glean_register_log_handler(message_handler: extern fn(i32, *mut c_char)) {
Logger::init(message_handler);
Expand All @@ -44,7 +50,7 @@ pub extern "C" fn glean_initialize(is_telemetry_enabled: bool, data_path: FfiStr
// Default is "https://incoming.telemetry.mozilla.org"
server_endpoint: None,
// Use the Glean provided one once https://bugzilla.mozilla.org/show_bug.cgi?id=1675468 is resolved
uploader: Some(Box::new(VPNPingUploader::new())),
uploader: Some(Box::new(VPNPingUploader::new(GLOBAL_PING_FILTER_LIST.clone()))),
// Whether Glean should schedule “metrics” pings for you
use_core_mps: true,
trim_data_to_registered_pings: false,
Expand Down Expand Up @@ -130,3 +136,14 @@ pub extern "C" fn glean_test_reset_glean(is_telemetry_enabled: bool, data_path:

glean::test_reset_glean(cfg, client_info, true);
}

#[no_mangle]
pub extern "C" fn glean_push_ping_filter(ping_name: FfiStr) {
let mut list = GLOBAL_PING_FILTER_LIST.lock().unwrap();
list.push(ping_name.into_string());
}
#[no_mangle]
pub extern "C" fn glean_clear_ping_filter() {
let mut list = GLOBAL_PING_FILTER_LIST.lock().unwrap();
list.clear();
}
21 changes: 20 additions & 1 deletion qtglean/src/uploader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,41 @@
use glean::net::{PingUploader, UploadResult, PingUploadRequest};
use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use std::sync::Mutex;
use std::sync::Arc;

#[derive(Debug)]
pub struct VPNPingUploader {
client: Client,
forbidden_ping_list: Arc<Mutex<Vec<String>>>,
}

impl VPNPingUploader {
pub fn new() -> VPNPingUploader {
pub fn new(forbidden_pings :Arc<Mutex<Vec<String>>> ) -> VPNPingUploader {
VPNPingUploader {
client: Client::new(),
forbidden_ping_list: forbidden_pings
}
}

fn allowed_to_send(&self, req: &PingUploadRequest)->bool{
let data = self.forbidden_ping_list.lock().unwrap();
// Emtpy list -> allow everything
if data.is_empty(){
return true;
}
// Otherwise the ping_name MUST NOT be in the list.
return data.iter().all(|e| e != &req.ping_name);
}
}

impl PingUploader for VPNPingUploader {
fn upload(&self, upload_request: PingUploadRequest) -> UploadResult {
if !self.allowed_to_send(&upload_request){
// If we're not allowed to send, "fake" a 200 response,
// so the data is dropped and not retried later.
return UploadResult::http_status(200);
}
let mut parsed_headers = HeaderMap::new();
for (name, value) in upload_request.headers {
if let (Ok(parsed_name), Ok(parsed_value)) = (
Expand Down
2 changes: 2 additions & 0 deletions src/cmake/sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ if(NOT CMAKE_CROSSCOMPILING)
target_sources(mozillavpn-sources INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/webextensionadapter.h
${CMAKE_CURRENT_SOURCE_DIR}/webextensionadapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/webextensiontelemetry.h
${CMAKE_CURRENT_SOURCE_DIR}/webextensiontelemetry.cpp
)
target_compile_definitions(mozillavpn-sources INTERFACE MVPN_WEBEXTENSION)
endif()
Expand Down
70 changes: 58 additions & 12 deletions src/glean/mzglean.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ MZGlean::MZGlean(QObject* parent) : QObject(parent) {
connect(AndroidVPNActivity::instance(),
&AndroidVPNActivity::eventRequestGleanUploadEnabledState, this,
[&]() {
broadcastUploadEnabledChange(
broadcastClientUploadEnabledChange(
SettingsHolder::instance()->gleanEnabled());
});
#endif
Expand All @@ -79,8 +79,14 @@ void MZGlean::initialize(const QString& channel) {

connect(SettingsHolder::instance(), &SettingsHolder::gleanEnabledChanged,
s_instance, []() {
s_instance->setUploadEnabled(
SettingsHolder::instance()->gleanEnabled());
updatePingFilter();
updateUploadEnabled();
});
connect(SettingsHolder::instance(),
&SettingsHolder::extensionTelemetryEnabledChanged, s_instance,
[]() {
updatePingFilter();
updateUploadEnabled();
});
}

Expand Down Expand Up @@ -115,10 +121,16 @@ void MZGlean::initialize(const QString& channel) {
# else
SettingsHolder* settingsHolder = SettingsHolder::instance();
Q_ASSERT(settingsHolder);
auto const clientTelemetryEnabled = settingsHolder->gleanEnabled();
auto const extensionTelemetryEnabled =
settingsHolder->extensionTelemetryEnabled();

auto const shouldUpload =
extensionTelemetryEnabled | clientTelemetryEnabled;

glean_initialize(SettingsHolder::instance()->gleanEnabled(),
gleanDirectory.absolutePath().toUtf8(), channel.toUtf8(),
QLocale::system().name().toUtf8());
updatePingFilter();
glean_initialize(shouldUpload, gleanDirectory.absolutePath().toUtf8(),
channel.toUtf8(), QLocale::system().name().toUtf8());

setLogPings(settingsHolder->gleanLogPings());
if (settingsHolder->gleanDebugTagActive()) {
Expand All @@ -130,16 +142,21 @@ void MZGlean::initialize(const QString& channel) {
}

// static
void MZGlean::setUploadEnabled(bool isTelemetryEnabled) {
logger.debug() << "Changing MZGlean upload status to" << isTelemetryEnabled;
void MZGlean::updateUploadEnabled() {
auto const settings = SettingsHolder::instance();
auto const clientTelemetryEnabled = settings->gleanEnabled();
auto const extensionTelemetryEnabled = settings->extensionTelemetryEnabled();

auto const shouldUpload = extensionTelemetryEnabled | clientTelemetryEnabled;
logger.debug() << "Changing MZGlean upload status to" << shouldUpload;

#if not(defined(MZ_WASM))
glean_set_upload_enabled(isTelemetryEnabled);
glean_set_upload_enabled(shouldUpload);
#endif

broadcastUploadEnabledChange(isTelemetryEnabled);
broadcastClientUploadEnabledChange(clientTelemetryEnabled);

if (isTelemetryEnabled) {
if (clientTelemetryEnabled) {
#if defined(MZ_ANDROID) || defined(MZ_IOS)
// need to reset installation ID, as it would have been cleared
QString uuid = mozilla::glean::session::installation_id.generateAndSet();
Expand All @@ -162,7 +179,7 @@ void MZGlean::setUploadEnabled(bool isTelemetryEnabled) {
}

// static
void MZGlean::broadcastUploadEnabledChange(bool isTelemetryEnabled) {
void MZGlean::broadcastClientUploadEnabledChange(bool isTelemetryEnabled) {
#if defined(MZ_ANDROID)
logger.debug() << "Broadcasting MZGlean upload status to Android Daemon.";

Expand Down Expand Up @@ -221,3 +238,32 @@ void MZGlean::setLogPings(bool flag) {
glean_set_log_pings(flag);
#endif
}

void MZGlean::updatePingFilter() {
#if defined(MZ_WASM)
return;
#else
glean_clear_ping_filter();
auto settings = SettingsHolder::instance();
auto clientTelemetryEnabled = settings->gleanEnabled();
auto extensionTelemetryEnabled = settings->extensionTelemetryEnabled();

// Everything is allowed, only required to clear the filter.
if (clientTelemetryEnabled && extensionTelemetryEnabled) {
return;
}
// All extension telemetry is inside the extension session ping
// so filter that ping out.
if (clientTelemetryEnabled) {
glean_push_ping_filter("extensionsession");
}
// Otherwise, filter the vpn pings out.
else if (extensionTelemetryEnabled) {
glean_push_ping_filter("daemonsession");
glean_push_ping_filter("main");
glean_push_ping_filter("vpnsession");
}
// If neither are enabled, we won't send things anyway.

#endif
}
6 changes: 4 additions & 2 deletions src/glean/mzglean.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ class MZGlean final : public QObject {
private:
explicit MZGlean(QObject* parent);

static void setUploadEnabled(bool isTelemetryEnabled);
static void updateUploadEnabled();

/**
* @brief Broadcast to the mobile VPN daemon instances of Glean,
* that the telemetry uploadEnabled state has changed.
*
* @param isTelemetryEnabled The new upload enabled state.
*/
static void broadcastUploadEnabledChange(bool isTelemetryEnabled);
static void broadcastClientUploadEnabledChange(bool isTelemetryEnabled);

static void updatePingFilter();

public:
~MZGlean();
Expand Down
10 changes: 10 additions & 0 deletions src/settingslist.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,3 +783,13 @@ SETTING_BOOL(addonApiSetting, // getter
false // sensitive (do not log)
)
#endif

SETTING_BOOL(extensionTelemetryEnabled, // getter
setExtensionTelemetryEnabled, // setter
removeExtensionTelemetryEnabled, // remover
hasExtensionTelemetryEnabled, // has
"extensionTelemetryEnabled", // key
false, // default value
true, // remove when reset
false // sensitive (do not log)
)
Loading

0 comments on commit 2aa9528

Please sign in to comment.