Backed out 15 changesets (bug 1662868) for causing xpcshell thread leaks.

CLOSED TREE

Backed out changeset fe1462617a8d (bug 1662868)
Backed out changeset 99df04f55be1 (bug 1662868)
Backed out changeset 21f7b675b3b9 (bug 1662868)
Backed out changeset 33a5ec2378cd (bug 1662868)
Backed out changeset be7a168ee182 (bug 1662868)
Backed out changeset 1803b5acd0f8 (bug 1662868)
Backed out changeset 98415dd8ee7e (bug 1662868)
Backed out changeset 6e38bfcb8587 (bug 1662868)
Backed out changeset 43245bce408a (bug 1662868)
Backed out changeset b727f5c658f5 (bug 1662868)
Backed out changeset f631a1d04d0a (bug 1662868)
Backed out changeset 6a5e0257086c (bug 1662868)
Backed out changeset 82c6c1b7a24a (bug 1662868)
Backed out changeset 6f4740140fe1 (bug 1662868)
Backed out changeset 2f342eaea13e (bug 1662868)
This commit is contained in:
Mihai Alexandru Michis 2020-12-02 18:24:59 +02:00
Родитель ec37b8925b
Коммит d2849190f6
124 изменённых файлов: 19551 добавлений и 20035 удалений

10
Cargo.lock сгенерированный
Просмотреть файл

@ -1545,7 +1545,6 @@ dependencies = [
"ffi-support",
"glean",
"glean-core",
"inherent",
"log",
"nsstring",
"once_cell",
@ -2079,9 +2078,9 @@ dependencies = [
[[package]]
name = "glean"
version = "33.5.0"
version = "33.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d5556ec294a763121f57384cf09be9b7f8eebbfc075040f9120b84f6a1160b"
checksum = "8f52254ae2baf857eec45b424a0d2dfe6ac63f353b594cfa4bee033f8386b25c"
dependencies = [
"crossbeam-channel",
"glean-core",
@ -2091,14 +2090,13 @@ dependencies = [
"serde",
"serde_json",
"thiserror",
"uuid",
]
[[package]]
name = "glean-core"
version = "33.5.0"
version = "33.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "657786648aaf8df52b059cb5cedff3be250df149bd8f6364919166e9d02a398d"
checksum = "82e3c82289c1ce270c1accc086f9cac083c15ddc01d167e9c6e0b8ed32a4b47c"
dependencies = [
"bincode",
"chrono",

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

22
third_party/rust/glean-core/Cargo.lock сгенерированный поставляемый
Просмотреть файл

@ -53,9 +53,9 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "cc"
version = "1.0.65"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
[[package]]
name = "cfg-if"
@ -180,7 +180,7 @@ dependencies = [
[[package]]
name = "glean-core"
version = "33.5.0"
version = "33.4.0"
dependencies = [
"bincode",
"chrono",
@ -543,9 +543,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.53"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8833e20724c24de12bbaba5ad230ea61c3eafb05b881c7c9d3cfe8638b187e68"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
dependencies = [
"proc-macro2",
"quote",
@ -580,9 +580,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.1.2"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
@ -600,9 +600,9 @@ dependencies = [
[[package]]
name = "tinyvec"
version = "1.1.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f"
checksum = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575"
dependencies = [
"tinyvec_macros",
]
@ -624,9 +624,9 @@ dependencies = [
[[package]]
name = "unicode-normalization"
version = "0.1.16"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606"
checksum = "b7f98e67a4d84f730d343392f9bfff7d21e3fca562b9cb7a43b768350beeddc6"
dependencies = [
"tinyvec",
]

2
third_party/rust/glean-core/Cargo.toml поставляемый
Просмотреть файл

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "glean-core"
version = "33.5.0"
version = "33.4.0"
authors = ["Jan-Erik Rediger <jrediger@mozilla.com>", "The Glean Team <glean-team@mozilla.com>"]
include = ["/README.md", "/LICENSE", "/src", "/examples", "/tests", "/Cargo.toml"]
description = "A modern Telemetry library"

Просмотреть файл

@ -4,7 +4,6 @@
use uuid::Uuid;
use crate::error_recording::{record_error, ErrorType};
use crate::metrics::Metric;
use crate::metrics::MetricType;
use crate::storage::StorageManager;
@ -55,28 +54,6 @@ impl UuidMetric {
glean.storage().record(glean, &self.meta, &value)
}
/// Sets to the specified value, from a string.
///
/// This should only be used from FFI. When calling directly from Rust, it
/// is better to use `set`.
///
/// # Arguments
///
/// * `glean` - The Glean instance this metric belongs to.
/// * `value` - The UUID to set the metric to.
pub fn set_from_str(&self, glean: &Glean, value: &str) {
if !self.should_record(glean) {
return;
}
if let Ok(uuid) = uuid::Uuid::parse_str(&value) {
self.set(glean, uuid);
} else {
let msg = format!("Unexpected UUID value '{}'", value);
record_error(glean, &self.meta, ErrorType::InvalidValue, msg, None);
}
}
/// Generates a new random UUID and set the metric to it.
///
/// # Arguments
@ -114,7 +91,14 @@ impl UuidMetric {
/// Gets the currently stored value as a string.
///
/// This doesn't clear the stored value.
pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<Uuid> {
self.get_value(glean, storage_name)
pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<String> {
match StorageManager.snapshot_metric(
glean.storage(),
storage_name,
&self.meta.identifier(glean),
) {
Some(Metric::Uuid(s)) => Some(s),
_ => None,
}
}
}

Просмотреть файл

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::ErrorType;
use crate::metrics::MetricType;
/// A description for the `LabeledMetric` type.
///
@ -10,7 +10,7 @@ use crate::ErrorType;
/// implemented in the related type in `../metrics/`.
pub trait Labeled<T>
where
T: Clone,
T: MetricType + Clone,
{
/// Gets a specific metric for a given label.
///
@ -25,22 +25,9 @@ where
/// If an invalid label is used, the metric will be recorded in the special `OTHER_LABEL` label.
fn get(&self, label: &str) -> T;
/// **Exported for test purposes.**
/// Gets the template submetric.
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32;
/// The template submetric is the actual metric that is cloned and modified
/// to record for a specific label.
fn get_submetric(&self) -> &T;
}

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::error::Result;
/// A description for the `PingType` type.
///
/// When changing this trait, make sure all the operations are
@ -13,5 +15,9 @@ pub trait Ping {
///
/// * `reason` - the reason the ping was triggered. Included in the
/// `ping_info.reason` part of the payload.
fn submit(&self, reason: Option<&str>);
///
/// # Returns
///
/// See [`Glean#submit_ping`](../struct.Glean.html#method.submit_ping) for details.
fn submit(&self, reason: Option<&str>) -> Result<bool>;
}

Просмотреть файл

@ -2,8 +2,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::ErrorType;
/// A description for the `QuantityMetric` type.
///
/// When changing this trait, make sure all the operations are
@ -31,23 +29,4 @@ pub trait Quantity {
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<i64>;
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32;
}

Просмотреть файл

@ -2,8 +2,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::ErrorType;
/// A description for the `UuidMetric` type.
///
/// When changing this trait, make sure all the operations are
@ -29,24 +27,5 @@ pub trait Uuid {
///
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<uuid::Uuid>;
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32;
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<String>;
}

2
third_party/rust/glean/.cargo-checksum.json поставляемый
Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"844796de9e9ae84430437001e4128aca390d634de1bcc9e9393e318f47539efc","LICENSE":"2684de17300e0a434686f1ec7f8af6045207a4b457a3fe04b2b9ce655e7c5d50","README.md":"7bfc89b6f6f0b7d1ca202ec0e24dc74fb2b2dfdea895b1d729d608f7f0ced5d7","src/common_test.rs":"a27d62d2de94e67f1e795a1e2cf9a08b0da24ca41fdcb2b2c17555ce27d97950","src/configuration.rs":"115f8f08058791c579828914ae03719d92d55b14206186c04ba74546dead2b6f","src/core_metrics.rs":"b07cfcb8e23a7b2eed1e6e21a44b9319b55bb8b1e86954fae7005ef27cafbcc6","src/dispatcher/global.rs":"ac32e02349ed1befca11ba09039f31983131d9daf2b169cdb210487915e88470","src/dispatcher/mod.rs":"dfbdf320e52b9273b6795f9a49eaa2e696308df5135243e64475039f6a81d4cf","src/glean_metrics.rs":"68cc4760363de5d5f986fe91628ec0ae2935f4fbd6a3af3d5100f4db3c20377d","src/lib.rs":"6a41c6b9f1df9e7a0d4ca35773651a034c34ae1bd667b31f755d635f761c1649","src/net/http_uploader.rs":"9ac1fa57f87093a61f810f3d484766d2e8a1504f63b4581f1b9c521b084000bc","src/net/mod.rs":"4ea59a2e450a4af66aa7ead237731f1b9333c8f9351adafac01270bba7c79d6d","src/pings.rs":"03e1d55aa1c2bcb7ab79c72ae7c3a02eb1e082bfd4012f7bd5c8ebdcf2ee8eb6","src/private/boolean.rs":"df583a3dca03566d71def9b4138fc77c5d749de524d22f8826015c31e0d3d81f","src/private/counter.rs":"20eb3a9e4454759b4769890f2c0556e7be6b84875ffd0a3babdae43d7091067d","src/private/labeled.rs":"afaece046cb0df9c5a5c01fb96b9a5d6791a8e757727259893a8b035023888a6","src/private/mod.rs":"92ccbe5929d2f31de040433d09b2e7c214f2a588a513206d9d4eeee192602ea4","src/private/ping.rs":"845ebbac3b956a3ccf323d12cd5ebfd518d9925647090e23eb70f00496f89b84","src/private/quantity.rs":"50de8becc001601634acdb3f75dc1567e5451cb637d850ee848680c1e2dc23dd","src/private/recorded_experiment_data.rs":"321f9a8fd77b69c8a33d9339facc6c7eaa990e3cd2cca8b3933650fef3e4b16c","src/private/string.rs":"9ff0d4fa6cbbf2b8762c2d7d869628ea84df8c7e6192e09ef9c272ce2eb46256","src/private/uuid.rs":"e18432e3b344ea49391e58a96385c35c57911d3271ee8ba53732a80b4c4d8f8c","src/system.rs":"094f44bdb99aa581f7482b4007237881b1fecafa5e6fec64ea586f76e17894cc","src/test.rs":"75e450c8b02b41717052879012f39b716c750833fb72c67407a61deb2dade0fb","tests/schema.rs":"4b3f0a2a2dbe83240bb6511f33a13ddf38b3b299000959b2a7ca56e63f35c073"},"package":"b1d5556ec294a763121f57384cf09be9b7f8eebbfc075040f9120b84f6a1160b"}
{"files":{"Cargo.toml":"0cf7769b2e228dbe53b2062492e86c2fe0d49f57f3b55a955708ccfbcf87686f","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"fd9e0ca6907917ea6bec5de05e15dd21d20fae1cb7f3250467bb20231a8e1065","src/configuration.rs":"b8747397761a9cf6dc64150855b75fd8e48dfe9951ce69e25d646b3a6f46456f","src/core_metrics.rs":"e20697e04f707c34c3c7a0cc4e2ed93e638d3028f03eb75a93f53ae722243986","src/dispatcher/global.rs":"7a2cd33616cbb5d86df617c5dcce50a0149c250e4acbfffb6037618cc722065b","src/dispatcher/mod.rs":"202a1de03bbaff76d1c41b8859f0ac409b0b40f426e22c8b4c0d642a07c2ebf5","src/glean_metrics.rs":"a5e1ea9c4dccb81aec4aa584bd76cf47e916c66af4aff4a0ef5aa297ee2d9aa3","src/lib.rs":"e13ee2939efe7e10f8fc2e921ee91f63e541fa322b3bb690f995c86011815a0d","src/net/http_uploader.rs":"9e8c1837ca0d3f6ea165ec936ab054173c4fe95a958710176c33b4d4d1d98beb","src/net/mod.rs":"ae1f5fcba401b0ebc31a078c96624ad03a39fb359aa0d8182beae32733375554","src/pings.rs":"2dfccd84848e1933aa4f6a7a707c58ec794c8f73ef2d93ea4d4df71d4e6abc31","src/private/boolean.rs":"2ead8da55eca0c8738f3c07445b46b1efa706b3e8a1e60428347e9fcb1d1fd3f","src/private/counter.rs":"b7e9f943d25dfb0cb5df797556dec5193606e3ab126e35fc8b6053530618fd0f","src/private/mod.rs":"d084cf3e1a69a6f1c8602ec86338d7161935b3390580875d57f36040a23a066d","src/private/ping.rs":"a837bc63436fb56ca0fac41c9139c72b8580941d7e8014004be353873a28ac77","src/private/recorded_experiment_data.rs":"3450e6abb48fc1ca9c11d42ef209e4d9b87ccbca0baf8893381ce7c62681f833","src/private/string.rs":"585cd5276bd1ea2570153ee72d53191def198b2618fda3aae3f8332af5651fa8","src/system.rs":"ba7b3eac040abe4691d9d287562ddca6d7e92a6d6109c3f0c443b707a100d75a","src/test.rs":"942f36b3ea18c33000f77e2fdd8194212d7685d5449728707bd36b6f2d5e35fd","tests/schema.rs":"b5acf42de034626f2b7e61fec9709a00370ce80ae3b2bab4db9fc79a20ea5f31"},"package":"8f52254ae2baf857eec45b424a0d2dfe6ac63f353b594cfa4bee033f8386b25c"}

8
third_party/rust/glean/Cargo.toml поставляемый
Просмотреть файл

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "glean"
version = "33.5.0"
version = "33.4.0"
authors = ["Jan-Erik Rediger <jrediger@mozilla.com>", "The Glean Team <glean-team@mozilla.com>"]
include = ["/README.md", "/LICENSE", "/src", "/tests", "/Cargo.toml"]
description = "Glean SDK Rust language bindings"
@ -25,7 +25,7 @@ repository = "https://github.com/mozilla/glean"
version = "0.4.3"
[dependencies.glean-core]
version = "33.5.0"
version = "33.4.0"
[dependencies.inherent]
version = "0.1.4"
@ -45,10 +45,6 @@ version = "1.0.44"
[dependencies.thiserror]
version = "1.0.4"
[dependencies.uuid]
version = "0.8.1"
features = ["v4"]
[dev-dependencies.env_logger]
version = "0.7.1"
features = ["termcolor", "atty", "humantime"]

57
third_party/rust/glean/src/common_test.rs поставляемый
Просмотреть файл

@ -1,57 +0,0 @@
// 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 https://mozilla.org/MPL/2.0/.
use crate::ClientInfoMetrics;
use crate::Configuration;
use std::sync::{Mutex, MutexGuard};
use once_cell::sync::Lazy;
pub(crate) const GLOBAL_APPLICATION_ID: &str = "org.mozilla.rlb.test";
// Because Glean uses a global-singleton, we need to run the tests one-by-one to
// avoid different tests stomping over each other.
// This is only an issue because we're resetting Glean, this cannot happen in normal
// use of the RLB.
//
// We use a global lock to force synchronization of all tests, even if run multi-threaded.
// This allows us to run without `--test-threads 1`.`
pub(crate) fn lock_test() -> MutexGuard<'static, ()> {
static GLOBAL_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
// This is going to be called from all the tests: make sure
// to enable logging.
env_logger::try_init().ok();
let lock = GLOBAL_LOCK.lock().unwrap();
lock
}
// Create a new instance of Glean with a temporary directory.
// We need to keep the `TempDir` alive, so that it's not deleted before we stop using it.
pub(crate) fn new_glean(
configuration: Option<Configuration>,
clear_stores: bool,
) -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = match configuration {
Some(c) => c,
None => Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: Some("testing".into()),
server_endpoint: Some("invalid-test-host".into()),
uploader: None,
},
};
crate::test_reset_glean(cfg, ClientInfoMetrics::unknown(), clear_stores);
dir
}

129
third_party/rust/glean/src/lib.rs поставляемый
Просмотреть файл

@ -45,9 +45,7 @@ use std::sync::Mutex;
pub use configuration::Configuration;
use configuration::DEFAULT_GLEAN_ENDPOINT;
pub use core_metrics::ClientInfoMetrics;
pub use glean_core::{
global_glean, setup_glean, CommonMetricData, Error, ErrorType, Glean, Lifetime, Result,
};
pub use glean_core::{global_glean, setup_glean, CommonMetricData, Error, Glean, Lifetime, Result};
use private::RecordedExperimentData;
mod configuration;
@ -58,9 +56,6 @@ pub mod net;
pub mod private;
mod system;
#[cfg(test)]
mod common_test;
const LANGUAGE_BINDING_NAME: &str = "Rust";
/// State to keep track for the Rust Language bindings.
@ -81,11 +76,6 @@ struct RustBindingsState {
/// Note: The initialization might still be in progress, as it runs in a separate thread.
static INITIALIZE_CALLED: AtomicBool = AtomicBool::new(false);
/// Keep track of the debug features before Glean is initialized.
static PRE_INIT_DEBUG_VIEW_TAG: OnceCell<Mutex<String>> = OnceCell::new();
static PRE_INIT_LOG_PINGS: AtomicBool = AtomicBool::new(false);
static PRE_INIT_SOURCE_TAGS: OnceCell<Mutex<Vec<String>>> = OnceCell::new();
/// A global singleton storing additional state for Glean.
///
/// Requires a Mutex, because in tests we can actual reset this.
@ -228,29 +218,6 @@ pub fn initialize(cfg: Configuration, client_info: ClientInfoMetrics) {
with_glean_mut(|glean| {
let state = global_state().lock().unwrap();
// The debug view tag might have been set before initialize,
// get the cached value and set it.
if let Some(tag) = PRE_INIT_DEBUG_VIEW_TAG.get() {
let lock = tag.try_lock();
if let Ok(ref debug_tag) = lock {
glean.set_debug_view_tag(debug_tag);
}
}
// The log pings debug option might have been set before initialize,
// get the cached value and set it.
let log_pigs = PRE_INIT_LOG_PINGS.load(Ordering::SeqCst);
if log_pigs {
glean.set_log_pings(log_pigs);
}
// The source tags might have been set before initialize,
// get the cached value and set them.
if let Some(tags) = PRE_INIT_SOURCE_TAGS.get() {
let lock = tags.try_lock();
if let Ok(ref source_tags) = lock {
glean.set_source_tags(source_tags.to_vec());
}
}
// Get the current value of the dirty flag so we know whether to
// send a dirty startup baseline ping below. Immediately set it to
// `false` so that dirty startup pings won't be sent if Glean
@ -322,16 +289,6 @@ pub fn initialize(cfg: Configuration, client_info: ClientInfoMetrics) {
INITIALIZE_CALLED.store(true, Ordering::SeqCst);
}
/// Shuts down Glean.
///
/// This currently only attempts to shut down the
/// internal dispatcher.
pub fn shutdown() {
if let Err(e) = dispatcher::try_shutdown() {
log::error!("Can't shutdown dispatcher thread: {:?}", e);
}
}
/// Checks if `glean::initialize` was ever called.
///
/// # Returns
@ -430,15 +387,12 @@ pub fn register_ping_type(ping: &private::PingType) {
/// Collects and submits a ping for eventual uploading.
///
/// See `glean_core::Glean.submit_ping`.
pub(crate) fn submit_ping(ping: &private::PingType, reason: Option<&str>) {
pub fn submit_ping(ping: &private::PingType, reason: Option<&str>) {
submit_ping_by_name(&ping.name, reason)
}
/// Collects and submits a ping for eventual uploading by name.
///
/// Note that this needs to be public in order for RLB consumers to
/// use Glean debugging facilities.
///
/// See `glean_core::Glean.submit_ping_by_name`.
pub fn submit_ping_by_name(ping: &str, reason: Option<&str>) {
let ping = ping.to_string();
@ -461,7 +415,7 @@ pub fn submit_ping_by_name(ping: &str, reason: Option<&str>) {
/// queued for sending, unless explicitly specified otherwise in the registry
/// file.
///
/// # Arguments
/// ## Arguments
///
/// * `ping_name` - the name of the ping to submit.
/// * `reason` - the reason the ping is being submitted.
@ -542,6 +496,7 @@ pub(crate) fn test_get_experiment_data(experiment_id: String) -> RecordedExperim
}
/// Destroy the global Glean state.
#[cfg(test)]
pub(crate) fn destroy_glean(clear_stores: bool) {
// Destroy the existing glean instance from glean-core.
if was_initialize_called() {
@ -564,9 +519,10 @@ pub(crate) fn destroy_glean(clear_stores: bool) {
}
}
/// TEST ONLY FUNCTION.
/// Resets the Glean state and triggers init again.
pub fn test_reset_glean(cfg: Configuration, client_info: ClientInfoMetrics, clear_stores: bool) {
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn reset_glean(cfg: Configuration, client_info: ClientInfoMetrics, clear_stores: bool) {
destroy_glean(clear_stores);
// Always log pings for tests
@ -574,76 +530,5 @@ pub fn test_reset_glean(cfg: Configuration, client_info: ClientInfoMetrics, clea
initialize(cfg, client_info);
}
/// Sets a debug view tag.
///
/// When the debug view tag is set, pings are sent with a `X-Debug-ID` header with the
/// value of the tag and are sent to the ["Ping Debug Viewer"](https://mozilla.github.io/glean/book/dev/core/internal/debug-pings.html).
///
/// # Arguments
///
/// * `tag` - A valid HTTP header value. Must match the regex: "[a-zA-Z0-9-]{1,20}".
///
/// # Returns
///
/// This will return `false` in case `tag` is not a valid tag and `true` otherwise.
/// If called before Glean is initialized it will always return `true`.
pub fn set_debug_view_tag(tag: &str) -> bool {
if was_initialize_called() {
with_glean_mut(|glean| glean.set_debug_view_tag(tag))
} else {
// Glean has not been initialized yet. Cache the provided tag value.
let m = PRE_INIT_DEBUG_VIEW_TAG.get_or_init(Default::default);
let mut lock = m.lock().unwrap();
*lock = tag.to_string();
// When setting the debug view tag before initialization,
// we don't validate the tag, thus this function always returns true.
true
}
}
/// Sets the log pings debug option.
///
/// When the log pings debug option is `true`,
/// we log the payload of all succesfully assembled pings.
///
/// # Arguments
///
/// * `value` - The value of the log pings option
pub fn set_log_pings(value: bool) {
if was_initialize_called() {
with_glean_mut(|glean| glean.set_log_pings(value));
} else {
PRE_INIT_LOG_PINGS.store(value, Ordering::SeqCst);
}
}
/// Sets source tags.
///
/// Overrides any existing source tags.
/// Source tags will show in the destination datasets, after ingestion.
///
/// # Arguments
///
/// * `tags` - A vector of at most 5 valid HTTP header values. Individual
/// tags must match the regex: "[a-zA-Z0-9-]{1,20}".
///
/// # Returns
///
/// This will return `false` in case `value` contains invalid tags and `true`
/// otherwise or if the tag is set before Glean is initialized.
pub fn set_source_tags(tags: Vec<String>) -> bool {
if was_initialize_called() {
with_glean_mut(|glean| glean.set_source_tags(tags))
} else {
// Glean has not been initialized yet. Cache the provided source tags.
let m = PRE_INIT_SOURCE_TAGS.get_or_init(Default::default);
let mut lock = m.lock().unwrap();
*lock = tags;
// When setting the source tags before initialization,
// we don't validate the tags, thus this function always returns true.
true
}
}
#[cfg(test)]
mod test;

Просмотреть файл

@ -84,8 +84,6 @@ impl glean_core::traits::Counter for CounterMetric {
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)

381
third_party/rust/glean/src/private/labeled.rs поставляемый
Просмотреть файл

@ -1,381 +0,0 @@
// 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 https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use std::sync::Arc;
use glean_core::metrics::MetricType;
use glean_core::ErrorType;
use crate::dispatcher;
/// Sealed traits protect against downstream implementations.
///
/// We wrap it in a private module that is inaccessible outside of this module.
mod private {
use crate::{
private::BooleanMetric, private::CounterMetric, private::StringMetric, CommonMetricData,
};
use std::sync::Arc;
/// The sealed labeled trait.
///
/// This also allows us to hide methods, that are only used internally
/// and should not be visible to users of the object implementing the
/// `Labeled<T>` trait.
pub trait Sealed {
/// The `glean_core` metric type representing the labeled metric.
type Inner: glean_core::metrics::MetricType + Clone;
/// Create a new metric object implementing this trait from the inner type.
fn from_inner(metric: Self::Inner) -> Self;
/// Create a new `glean_core` metric from the metadata.
fn new_inner(meta: crate::CommonMetricData) -> Self::Inner;
}
// `LabeledMetric<BooleanMetric>` is possible.
//
// See [Labeled Booleans](https://mozilla.github.io/glean/book/user/metrics/labeled_booleans.html).
impl Sealed for BooleanMetric {
type Inner = glean_core::metrics::BooleanMetric;
fn from_inner(metric: Self::Inner) -> Self {
BooleanMetric(Arc::new(metric))
}
fn new_inner(meta: CommonMetricData) -> Self::Inner {
glean_core::metrics::BooleanMetric::new(meta)
}
}
// `LabeledMetric<StringMetric>` is possible.
//
// See [Labeled Strings](https://mozilla.github.io/glean/book/user/metrics/labeled_strings.html).
impl Sealed for StringMetric {
type Inner = glean_core::metrics::StringMetric;
fn from_inner(metric: Self::Inner) -> Self {
StringMetric(Arc::new(metric))
}
fn new_inner(meta: CommonMetricData) -> Self::Inner {
glean_core::metrics::StringMetric::new(meta)
}
}
// `LabeledMetric<CounterMetric>` is possible.
//
// See [Labeled Counters](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html).
impl Sealed for CounterMetric {
type Inner = glean_core::metrics::CounterMetric;
fn from_inner(metric: Self::Inner) -> Self {
CounterMetric(Arc::new(metric))
}
fn new_inner(meta: CommonMetricData) -> Self::Inner {
glean_core::metrics::CounterMetric::new(meta)
}
}
}
/// Marker trait for metrics that can be nested inside a labeled metric.
///
/// This trait is sealed and cannot be implemented for types outside this crate.
pub trait AllowLabeled: private::Sealed {}
// Implement the trait for everything we marked as allowed.
impl<T> AllowLabeled for T where T: private::Sealed {}
// We need to wrap the glean-core type: otherwise if we try to implement
// the trait for the metric in `glean_core::metrics` we hit error[E0117]:
// only traits defined in the current crate can be implemented for arbitrary
// types.
/// This implements the specific facing API for recording labeled metrics.
///
/// Instances of this type are automatically generated by the parser
/// at build time, allowing developers to record values that were previously
/// registered in the metrics.yaml file.
/// Unlike most metric types, `LabeledMetric` does not have its own corresponding
/// storage, but records metrics for the underlying metric type `T` in the storage
/// for that type.
#[derive(Clone)]
pub struct LabeledMetric<T: AllowLabeled>(
pub(crate) Arc<glean_core::metrics::LabeledMetric<T::Inner>>,
);
impl<T> LabeledMetric<T>
where
T: AllowLabeled,
{
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData, labels: Option<Vec<String>>) -> Self {
let submetric = T::new_inner(meta);
let core = glean_core::metrics::LabeledMetric::new(submetric, labels);
Self(Arc::new(core))
}
}
#[inherent(pub)]
impl<T> glean_core::traits::Labeled<T> for LabeledMetric<T>
where
T: AllowLabeled + Clone,
{
/// Gets a specific metric for a given label.
///
/// If a set of acceptable labels were specified in the `metrics.yaml` file,
/// and the given label is not in the set, it will be recorded under the special `OTHER_LABEL` label.
///
/// If a set of acceptable labels was not specified in the `metrics.yaml` file,
/// only the first 16 unique labels will be used.
/// After that, any additional labels will be recorded under the special `OTHER_LABEL` label.
///
/// Labels must be `snake_case` and less than 30 characters.
/// If an invalid label is used, the metric will be recorded in the special `OTHER_LABEL` label.
fn get(&self, label: &str) -> T {
let inner = self.0.get(label);
T::from_inner(inner)
}
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(
&glean,
self.0.get_submetric().meta(),
error,
ping_name.into(),
)
.unwrap_or(0)
})
}
}
#[cfg(test)]
mod test {
use super::ErrorType;
use crate::common_test::{lock_test, new_glean};
use crate::destroy_glean;
use crate::private::{BooleanMetric, CounterMetric, LabeledMetric, StringMetric};
use crate::CommonMetricData;
#[test]
fn test_labeled_counter_type() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: LabeledMetric<CounterMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_counter".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
None,
);
metric.get("label1").add(1);
metric.get("label2").add(2);
assert_eq!(1, metric.get("label1").test_get_value("test1").unwrap());
assert_eq!(2, metric.get("label2").test_get_value("test1").unwrap());
}
#[test]
fn test_other_label_with_predefined_labels() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: LabeledMetric<CounterMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_counter".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
Some(vec!["foo".into(), "bar".into(), "baz".into()]),
);
metric.get("foo").add(1);
metric.get("foo").add(2);
metric.get("bar").add(1);
metric.get("not_there").add(1);
metric.get("also_not_there").add(1);
metric.get("not_me").add(1);
assert_eq!(3, metric.get("foo").test_get_value(None).unwrap());
assert_eq!(1, metric.get("bar").test_get_value(None).unwrap());
assert!(metric.get("baz").test_get_value(None).is_none());
// The rest all lands in the __other__ bucket.
assert_eq!(3, metric.get("__other__").test_get_value(None).unwrap());
}
#[test]
fn test_other_label_without_predefined_labels() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: LabeledMetric<CounterMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_counter".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
None,
);
// Record in 20 labels: it will go over the maximum number of supported
// dynamic labels.
for i in 0..=20 {
metric.get(format!("label_{}", i).as_str()).add(1);
}
// Record in a label once again.
metric.get("label_0").add(1);
assert_eq!(2, metric.get("label_0").test_get_value(None).unwrap());
for i in 1..15 {
assert_eq!(
1,
metric
.get(format!("label_{}", i).as_str())
.test_get_value(None)
.unwrap()
);
}
assert_eq!(5, metric.get("__other__").test_get_value(None).unwrap());
}
#[test]
fn test_other_label_without_predefined_labels_before_glean_init() {
let _lock = lock_test();
// We explicitly want Glean to not be initialized.
destroy_glean(true);
let metric: LabeledMetric<CounterMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_counter".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
None,
);
// Record in 20 labels: it will go over the maximum number of supported
// dynamic labels.
for i in 0..=20 {
metric.get(format!("label_{}", i).as_str()).add(1);
}
// Record in a label once again.
metric.get("label_0").add(1);
// Initialize Glean.
let _t = new_glean(None, false);
assert_eq!(2, metric.get("label_0").test_get_value(None).unwrap());
for i in 1..15 {
assert_eq!(
1,
metric
.get(format!("label_{}", i).as_str())
.test_get_value(None)
.unwrap()
);
}
assert_eq!(5, metric.get("__other__").test_get_value(None).unwrap());
}
#[test]
fn test_labeled_string_type() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: LabeledMetric<StringMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_string".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
None,
);
metric.get("label1").set("foo");
metric.get("label2").set("bar");
assert_eq!("foo", metric.get("label1").test_get_value("test1").unwrap());
assert_eq!("bar", metric.get("label2").test_get_value("test1").unwrap());
}
#[test]
fn test_labeled_boolean_type() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: LabeledMetric<BooleanMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_boolean".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
None,
);
metric.get("label1").set(false);
metric.get("label2").set(true);
assert!(!metric.get("label1").test_get_value("test1").unwrap());
assert!(metric.get("label2").test_get_value("test1").unwrap());
}
#[test]
fn test_invalid_labels_record_errors() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: LabeledMetric<BooleanMetric> = LabeledMetric::new(
CommonMetricData {
name: "labeled_boolean".into(),
category: "labeled".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
None,
);
let invalid_label = "!#I'm invalid#--_";
metric.get(invalid_label).set(true);
assert_eq!(true, metric.get("__other__").test_get_value(None).unwrap());
assert_eq!(
1,
metric.test_get_num_recorded_errors(ErrorType::InvalidLabel, None)
);
}
}

6
third_party/rust/glean/src/private/mod.rs поставляемый
Просмотреть файл

@ -6,18 +6,12 @@
mod boolean;
mod counter;
mod labeled;
mod ping;
mod quantity;
mod recorded_experiment_data;
mod string;
mod uuid;
pub use self::uuid::UuidMetric;
pub use boolean::BooleanMetric;
pub use counter::CounterMetric;
pub use labeled::{AllowLabeled, LabeledMetric};
pub use ping::PingType;
pub use quantity::QuantityMetric;
pub use recorded_experiment_data::RecordedExperimentData;
pub use string::StringMetric;

7
third_party/rust/glean/src/private/ping.rs поставляемый
Просмотреть файл

@ -2,8 +2,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
/// A Glean ping.
#[derive(Clone, Debug)]
pub struct PingType {
@ -38,10 +36,7 @@ impl PingType {
crate::register_ping_type(&me);
me
}
}
#[inherent(pub)]
impl glean_core::traits::Ping for PingType {
/// Collect and submit the ping for eventual upload.
///
/// This will collect all stored data to be included in the ping.
@ -61,7 +56,7 @@ impl glean_core::traits::Ping for PingType {
///
/// * `reason` - The reason the ping is being submitted.
/// Must be one of the configured `reason_codes`.
fn submit(&self, reason: Option<&str>) {
pub fn submit(&self, reason: Option<&str>) {
crate::submit_ping(self, reason)
}
}

Просмотреть файл

@ -1,91 +0,0 @@
// 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 https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use std::sync::Arc;
use glean_core::metrics::MetricType;
use glean_core::ErrorType;
use crate::dispatcher;
// We need to wrap the glean-core type, otherwise if we try to implement
// the trait for the metric in `glean_core::metrics` we hit error[E0117]:
// only traits defined in the current crate can be implemented for arbitrary
// types.
/// This implements the developer facing API for recording Quantity metrics.
///
/// Instances of this class type are automatically generated by the parsers
/// at build time, allowing developers to record values that were previously
/// registered in the metrics.yaml file.
#[derive(Clone)]
pub struct QuantityMetric(pub(crate) Arc<glean_core::metrics::QuantityMetric>);
impl QuantityMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData) -> Self {
Self(Arc::new(glean_core::metrics::QuantityMetric::new(meta)))
}
}
#[inherent(pub)]
impl glean_core::traits::Quantity for QuantityMetric {
/// Sets to the specified value. Must be non-negative.
///
/// # Arguments
///
/// * `value` - The Quantity to set the metric to.
fn set(&self, value: i64) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || crate::with_glean(|glean| metric.set(glean, value)));
}
/// **Exported for test purposes.**
///
/// Gets the currently stored value.
///
/// This doesn't clear the stored value.
///
/// # Arguments
///
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<i64> {
dispatcher::block_on_queue();
let queried_ping_name = ping_name
.into()
.unwrap_or_else(|| &self.0.meta().send_in_pings[0]);
crate::with_glean(|glean| self.0.test_get_value(glean, queried_ping_name))
}
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
#[allow(dead_code)] // Remove after mozilla/glean#1328
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)
})
}
}

Просмотреть файл

@ -88,8 +88,6 @@ impl glean_core::traits::String for StringMetric {
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)

96
third_party/rust/glean/src/private/uuid.rs поставляемый
Просмотреть файл

@ -1,96 +0,0 @@
// 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 https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use std::sync::Arc;
use glean_core::metrics::MetricType;
use glean_core::ErrorType;
use crate::dispatcher;
// We need to wrap the glean-core type, otherwise if we try to implement
// the trait for the metric in `glean_core::metrics` we hit error[E0117]:
// only traits defined in the current crate can be implemented for arbitrary
// types.
/// This implements the developer facing API for recording UUID metrics.
///
/// Instances of this class type are automatically generated by the parsers
/// at build time, allowing developers to record values that were previously
/// registered in the metrics.yaml file.
#[derive(Clone)]
pub struct UuidMetric(pub(crate) Arc<glean_core::metrics::UuidMetric>);
impl UuidMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData) -> Self {
Self(Arc::new(glean_core::metrics::UuidMetric::new(meta)))
}
}
#[inherent(pub)]
impl glean_core::traits::Uuid for UuidMetric {
/// Sets to the specified value.
///
/// # Arguments
///
/// * `value` - The UUID to set the metric to.
fn set(&self, value: uuid::Uuid) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || crate::with_glean(|glean| metric.set(glean, value)));
}
/// Generates a new random UUID and sets the metric to it.
fn generate_and_set(&self) -> uuid::Uuid {
// TODO: We can use glean-core's generate_and_set after bug 1673017.
let uuid = uuid::Uuid::new_v4();
self.set(uuid);
uuid
}
/// **Exported for test purposes.**
///
/// Gets the currently stored value.
///
/// This doesn't clear the stored value.
///
/// # Arguments
///
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<uuid::Uuid> {
dispatcher::block_on_queue();
let queried_ping_name = ping_name
.into()
.unwrap_or_else(|| &self.0.meta().send_in_pings[0]);
crate::with_glean(|glean| self.0.test_get_value(glean, queried_ping_name))
}
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)
})
}
}

190
third_party/rust/glean/src/test.rs поставляемый
Просмотреть файл

@ -3,14 +3,49 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::private::{BooleanMetric, CounterMetric};
use once_cell::sync::Lazy;
use std::path::PathBuf;
use std::sync::Mutex;
use super::*;
use crate::common_test::{lock_test, new_glean, GLOBAL_APPLICATION_ID};
// Because glean_preview is a global-singleton, we need to run the tests one-by-one to avoid different tests stomping over each other.
// This is only an issue because we're resetting Glean, this cannot happen in normal use of the
// RLB.
//
// We use a global lock to force synchronization of all tests, even if run multi-threaded.
// This allows us to run without `--test-threads 1`.`
static GLOBAL_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
const GLOBAL_APPLICATION_ID: &str = "org.mozilla.rlb.test";
// Create a new instance of Glean with a temporary directory.
// We need to keep the `TempDir` alive, so that it's not deleted before we stop using it.
fn new_glean(configuration: Option<Configuration>, clear_stores: bool) -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = match configuration {
Some(c) => c,
None => Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: Some("testing".into()),
server_endpoint: Some("invalid-test-host".into()),
uploader: None,
},
};
crate::reset_glean(cfg, ClientInfoMetrics::unknown(), clear_stores);
dir
}
#[test]
fn send_a_ping() {
let _lock = lock_test();
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
let (s, r) = crossbeam_channel::bounded::<String>(1);
@ -62,7 +97,8 @@ fn send_a_ping() {
#[test]
fn disabling_upload_disables_metrics_recording() {
let _lock = lock_test();
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
let _t = new_glean(None, true);
crate::dispatcher::block_on_queue();
@ -83,7 +119,9 @@ fn disabling_upload_disables_metrics_recording() {
#[test]
fn test_experiments_recording() {
let _lock = lock_test();
// setup glean for the test
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
let _t = new_glean(None, true);
@ -107,7 +145,8 @@ fn test_experiments_recording() {
#[test]
fn test_experiments_recording_before_glean_inits() {
let _lock = lock_test();
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
// Destroy the existing glean instance from glean-core so that we
// can test the pre-init queueing of the experiment api commands.
@ -145,7 +184,7 @@ fn test_experiments_recording_before_glean_inits() {
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
test_reset_glean(
reset_glean(
Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
@ -183,7 +222,8 @@ fn test_sending_of_startup_baseline_ping() {
#[test]
fn initialize_must_not_crash_if_data_dir_is_messed_up() {
let _lock = lock_test();
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
let dir = tempfile::tempdir().unwrap();
let tmpdirname = dir.path().display().to_string();
@ -203,7 +243,7 @@ fn initialize_must_not_crash_if_data_dir_is_messed_up() {
uploader: None,
};
test_reset_glean(cfg, ClientInfoMetrics::unknown(), false);
reset_glean(cfg, ClientInfoMetrics::unknown(), false);
// TODO(bug 1675215): ensure initialize runs through dispatcher.
// Glean init is async and, for this test, it bails out early due to
// an caused by not being able to create the data dir: we can do nothing
@ -216,7 +256,8 @@ fn initialize_must_not_crash_if_data_dir_is_messed_up() {
#[test]
fn queued_recorded_metrics_correctly_record_during_init() {
let _lock = lock_test();
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
destroy_glean(true);
@ -240,7 +281,7 @@ fn queued_recorded_metrics_correctly_record_during_init() {
// Calling `new_glean` here will cause Glean to be initialized and should cause the queued
// tasks recording metrics to execute
let _t = new_glean(None, false);
let _ = new_glean(None, false);
// Verify that the callback was executed by testing for the correct value
assert!(metric.test_get_value(None).is_some(), "Value must exist");
@ -249,12 +290,13 @@ fn queued_recorded_metrics_correctly_record_during_init() {
#[test]
fn initializing_twice_is_a_noop() {
let _lock = lock_test();
let _lock = GLOBAL_LOCK.lock().unwrap();
env_logger::try_init().ok();
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
test_reset_glean(
reset_glean(
Configuration {
data_path: tmpname.clone(),
application_id: GLOBAL_APPLICATION_ID.into(),
@ -271,7 +313,7 @@ fn initializing_twice_is_a_noop() {
dispatcher::block_on_queue();
test_reset_glean(
reset_glean(
Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
@ -354,128 +396,6 @@ fn test_dirty_flag_is_reset_to_false() {
todo!()
}
#[test]
fn setting_debug_view_tag_before_initialization_should_not_crash() {
let _lock = lock_test();
destroy_glean(true);
assert!(!was_initialize_called());
// Define a fake uploader that reports back the submission headers
// using a crossbeam channel.
let (s, r) = crossbeam_channel::bounded::<Vec<(String, String)>>(1);
#[derive(Debug)]
pub struct FakeUploader {
sender: crossbeam_channel::Sender<Vec<(String, String)>>,
};
impl net::PingUploader for FakeUploader {
fn upload(
&self,
_url: String,
_body: Vec<u8>,
headers: Vec<(String, String)>,
) -> net::UploadResult {
self.sender.send(headers).unwrap();
net::UploadResult::HttpStatus(200)
}
}
// Attempt to set a debug view tag before Glean is initialized.
set_debug_view_tag("valid-tag");
// Create a custom configuration to use a fake uploader.
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: Some("testing".into()),
server_endpoint: Some("invalid-test-host".into()),
uploader: Some(Box::new(FakeUploader { sender: s })),
};
let _t = new_glean(Some(cfg), true);
crate::dispatcher::block_on_queue();
// Submit a baseline ping.
submit_ping_by_name("baseline", Some("background"));
// Wait for the ping to arrive.
let headers = r.recv().unwrap();
assert_eq!(
"valid-tag",
headers.iter().find(|&kv| kv.0 == "X-Debug-ID").unwrap().1
);
}
#[test]
fn setting_source_tags_before_initialization_should_not_crash() {
let _lock = lock_test();
destroy_glean(true);
assert!(!was_initialize_called());
// Define a fake uploader that reports back the submission headers
// using a crossbeam channel.
let (s, r) = crossbeam_channel::bounded::<Vec<(String, String)>>(1);
#[derive(Debug)]
pub struct FakeUploader {
sender: crossbeam_channel::Sender<Vec<(String, String)>>,
};
impl net::PingUploader for FakeUploader {
fn upload(
&self,
_url: String,
_body: Vec<u8>,
headers: Vec<(String, String)>,
) -> net::UploadResult {
self.sender.send(headers).unwrap();
net::UploadResult::HttpStatus(200)
}
}
// Attempt to set source tags before Glean is initialized.
set_source_tags(vec!["valid-tag1".to_string(), "valid-tag2".to_string()]);
// Create a custom configuration to use a fake uploader.
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: Some("testing".into()),
server_endpoint: Some("invalid-test-host".into()),
uploader: Some(Box::new(FakeUploader { sender: s })),
};
let _t = new_glean(Some(cfg), true);
crate::dispatcher::block_on_queue();
// Submit a baseline ping.
submit_ping_by_name("baseline", Some("background"));
// Wait for the ping to arrive.
let headers = r.recv().unwrap();
assert_eq!(
"valid-tag1,valid-tag2",
headers
.iter()
.find(|&kv| kv.0 == "X-Source-Tags")
.unwrap()
.1
);
}
#[test]
#[ignore] // TODO: To be done in bug 1673672.
fn flipping_upload_enabled_respects_order_of_events() {

Просмотреть файл

@ -6,8 +6,8 @@ edition = "2018"
license = "MPL-2.0"
[dependencies]
glean = "33.5.0"
glean-core = { version = "33.5.0", features = ["rkv-safe-mode"] }
glean = "33.4.0"
glean-core = { version = "33.4.0", features = ["rkv-safe-mode"] }
log = "0.4"
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }

Просмотреть файл

@ -9,9 +9,8 @@ publish = false
bincode = "1.0"
chrono = "0.4.10"
ffi-support = "0.4"
glean = "33.5.0"
glean-core = { version = "33.5.0", features = ["rkv-safe-mode"] }
inherent = "0.1.4"
glean = "33.4.0"
glean-core = { version = "33.4.0", features = ["rkv-safe-mode"] }
log = "0.4"
nsstring = { path = "../../../../xpcom/rust/nsstring", optional = true }
once_cell = "1.2.0"

Просмотреть файл

@ -29,23 +29,20 @@ fn setup_glean(tempdir: Option<tempfile::TempDir>) -> tempfile::TempDir {
};
let tmpname = dir.path().display().to_string();
let cfg = glean::Configuration {
upload_enabled: true,
let cfg = glean_core::Configuration {
data_path: tmpname,
application_id: GLOBAL_APPLICATION_ID.into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: None,
server_endpoint: None,
uploader: None,
language_binding_name: "Rust".into(),
};
let glean = glean_core::Glean::new(cfg).unwrap();
glean_core::setup_glean(glean).expect("can't set up global Glean object");
let client_info = glean::ClientInfoMetrics {
app_build: "test-build".into(),
app_display_version: "1.2.3".into(),
};
glean::test_reset_glean(cfg, client_info, true);
// This might have been flushed by other tests already, so we ignore the return value.
// The dispatch queue is definitely unblocked after this, no matter what.
let _ = super::flush_init();
dir
}

Просмотреть файл

@ -96,9 +96,7 @@ pub extern "C" fn fog_uuid_set(id: u32, value: &nsACString) {
#[no_mangle]
pub extern "C" fn fog_uuid_generate_and_set(id: u32) {
match crate::metrics::__glean_metric_maps::UUID_MAP.get(&id.into()) {
Some(metric) => {
metric.generate_and_set();
}
Some(metric) => metric.generate_and_set(),
None => panic!("No metric for id {}", id),
}
}

Просмотреть файл

@ -2,7 +2,13 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! The public FOG APIs, for Rust consumers.
//! The public Glean SDK API, for Rust consumers.
//!
//! ## Example:
//!
//! ```rust,ignore
//! assert!(glean::is_upload_enabled())
//! ```
// Re-exporting for later use in generated code.
pub extern crate chrono;
@ -10,6 +16,7 @@ pub extern crate once_cell;
pub extern crate uuid;
pub mod metrics;
pub mod ping_upload;
pub mod pings;
pub mod private;
@ -31,3 +38,20 @@ where
.unwrap();
f(&mut lock)
}
/// Determine whether upload is enabled.
///
/// See `glean_core::Glean.is_upload_enabled`.
pub fn is_upload_enabled() -> bool {
with_glean(|glean| glean.is_upload_enabled())
}
pub fn flush_init() -> Result<(), dispatcher::DispatchError> {
dispatcher::flush_init()
}
pub fn shutdown() {
if let Err(e) = dispatcher::try_shutdown() {
log::error!("Can't shutdown dispatcher thread: {:?}", e);
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// 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 https://mozilla.org/MPL/2.0/.
//! The Ping Upload Scheduler logic.
//!
//! Register your application's PingUploader to upload pings when scheduled.
//!
//! ## Example:
//!
//! ```rust,ignore
//! fn during_init() {
//! ping_upload::register_uploader(Box::new(|ping_request| do_the_thing(ping_request)));
//! }
//! ```
use glean_core::upload::PingUploadTask::*;
pub use glean_core::upload::{PingRequest, UploadResult};
use once_cell::sync::OnceCell;
use std::sync::Mutex;
use std::thread;
pub type UploadFn = dyn (FnMut(&PingRequest) -> UploadResult) + Send;
static UPLOADER: OnceCell<Mutex<Box<UploadFn>>> = OnceCell::new();
/// Threadsafe. Set the uploader to be used for all pings.
/// Subsequent calls fail.
pub fn register_uploader(uploader: Box<UploadFn>) -> Result<(), ()> {
UPLOADER.set(Mutex::new(uploader)).map_err(|_| ())
}
/// Called occasionally on any thread to nudge the Scheduler to ask Glean for
/// ping requests.
pub fn check_for_uploads() {
if UPLOADER.get().is_none() {
return;
}
thread::spawn(move || {
while let Some(mutex) = UPLOADER.get() {
let uploader = &mut *mutex.lock().unwrap();
if let Upload(request) = crate::with_glean(|glean| glean.get_upload_task()) {
let response = (*uploader)(&request);
crate::with_glean(|glean| {
glean.process_ping_upload_response(&request.document_id, response)
});
} else {
// For now, don't bother distinguishing between Wait and Done.
// Either mean there's no task to execute right now.
break;
}
}
});
}

Просмотреть файл

@ -2,24 +2,25 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use glean_core::traits::Boolean;
use std::sync::Arc;
use super::CommonMetricData;
use crate::dispatcher;
use crate::ipc::need_ipc;
use crate::private::MetricId;
/// A boolean metric.
///
/// Records a simple true or false value.
#[derive(Clone)]
#[derive(Debug)]
pub enum BooleanMetric {
Parent(glean::private::BooleanMetric),
Parent(Arc<BooleanMetricImpl>),
Child(BooleanMetricIpc),
}
#[derive(Clone, Debug)]
pub struct BooleanMetricImpl(pub(crate) glean_core::metrics::BooleanMetric);
#[derive(Debug)]
pub struct BooleanMetricIpc;
impl BooleanMetric {
@ -28,7 +29,7 @@ impl BooleanMetric {
if need_ipc() {
BooleanMetric::Child(BooleanMetricIpc)
} else {
BooleanMetric::Parent(glean::private::BooleanMetric::new(meta))
BooleanMetric::Parent(Arc::new(BooleanMetricImpl::new(meta)))
}
}
@ -39,22 +40,23 @@ impl BooleanMetric {
BooleanMetric::Child(_) => panic!("Can't get a child metric from a child metric"),
}
}
}
#[inherent(pub)]
impl Boolean for BooleanMetric {
/// Set to the specified boolean value.
///
/// ## Arguments
///
/// * `value` - the value to set.
fn set(&self, value: bool) {
pub fn set(&self, value: bool) {
match self {
BooleanMetric::Parent(p) => {
Boolean::set(&*p, value);
let metric = Arc::clone(&p);
dispatcher::launch(move || metric.set(value));
}
BooleanMetric::Child(_) => {
log::error!("Unable to set boolean metric in non-parent process. Ignoring.");
log::error!(
"Unable to set boolean metric {:?} in non-parent process. Ignoring.",
self
);
// TODO: Record an error.
}
}
@ -67,21 +69,39 @@ impl Boolean for BooleanMetric {
///
/// ## Arguments
///
/// * `ping_name` - the storage name to look into.
/// * `storage_name` - the storage name to look into.
///
/// ## Return value
///
/// Returns the stored value or `None` if nothing stored.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<bool> {
pub fn test_get_value(&self, storage_name: &str) -> Option<bool> {
match self {
BooleanMetric::Parent(p) => p.test_get_value(ping_name),
BooleanMetric::Child(_) => {
panic!("Cannot get test value for boolean metric in non-parent process!",)
BooleanMetric::Parent(p) => {
dispatcher::block_on_queue();
p.test_get_value(storage_name)
}
BooleanMetric::Child(_) => panic!(
"Cannot get test value for {:?} in non-parent process!",
self
),
}
}
}
impl BooleanMetricImpl {
pub fn new(meta: CommonMetricData) -> Self {
Self(glean_core::metrics::BooleanMetric::new(meta))
}
pub fn set(&self, value: bool) {
crate::with_glean(move |glean| self.0.set(glean, value))
}
pub fn test_get_value(&self, storage_name: &str) -> Option<bool> {
crate::with_glean(move |glean| self.0.test_get_value(glean, storage_name))
}
}
#[cfg(test)]
mod test {
use crate::{common_test::*, ipc, metrics};

Просмотреть файл

@ -2,12 +2,11 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use glean_core::traits::Counter;
use std::sync::Arc;
use super::CommonMetricData;
use crate::dispatcher;
use crate::ipc::{need_ipc, with_ipc_payload};
use crate::private::MetricId;
@ -15,18 +14,20 @@ use crate::private::MetricId;
///
/// Used to count things.
/// The value can only be incremented, not decremented.
#[derive(Clone)]
#[derive(Debug)]
pub enum CounterMetric {
Parent {
/// The metric's ID.
///
/// **TEST-ONLY** - Do not use unless gated with `#[cfg(test)]`.
id: MetricId,
inner: glean::private::CounterMetric,
inner: Arc<CounterMetricImpl>,
},
Child(CounterMetricIpc),
}
#[derive(Clone, Debug)]
pub struct CounterMetricImpl(pub(crate) glean_core::metrics::CounterMetric);
#[derive(Debug)]
pub struct CounterMetricIpc(MetricId);
impl CounterMetric {
@ -35,7 +36,7 @@ impl CounterMetric {
if need_ipc() {
CounterMetric::Child(CounterMetricIpc(id))
} else {
let inner = glean::private::CounterMetric::new(meta);
let inner = Arc::new(CounterMetricImpl::new(meta));
CounterMetric::Parent { id, inner }
}
}
@ -55,10 +56,7 @@ impl CounterMetric {
CounterMetric::Child(_) => panic!("Can't get a child metric from a child metric"),
}
}
}
#[inherent(pub)]
impl Counter for CounterMetric {
/// Increase the counter by `amount`.
///
/// ## Arguments
@ -68,10 +66,11 @@ impl Counter for CounterMetric {
/// ## Notes
///
/// Logs an error if the `amount` is 0 or negative.
fn add(&self, amount: i32) {
pub fn add(&self, amount: i32) {
match self {
CounterMetric::Parent { inner, .. } => {
Counter::add(&*inner, amount);
let metric = Arc::clone(&inner);
dispatcher::launch(move || metric.add(amount));
}
CounterMetric::Child(c) => {
with_ipc_payload(move |payload| {
@ -92,50 +91,39 @@ impl Counter for CounterMetric {
///
/// ## Arguments
///
/// * `ping_name` - the storage name to look into.
/// * `storage_name` - the storage name to look into.
///
/// ## Return value
///
/// Returns the stored value or `None` if nothing stored.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<i32> {
match self {
CounterMetric::Parent { inner, .. } => inner.test_get_value(ping_name),
CounterMetric::Child(c) => {
panic!("Cannot get test value for {:?} in non-parent process!", c.0)
}
}
}
/// **Test-only API.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: glean::ErrorType,
ping_name: S,
) -> i32 {
pub fn test_get_value(&self, storage_name: &str) -> Option<i32> {
match self {
CounterMetric::Parent { inner, .. } => {
inner.test_get_num_recorded_errors(error, ping_name)
dispatcher::block_on_queue();
inner.test_get_value(storage_name)
}
CounterMetric::Child(c) => panic!(
"Cannot get the number of recorded errors for {:?} in non-parent process!",
c.0
CounterMetric::Child(_c) => panic!(
"Cannot get test value for {:?} in non-parent process!",
self
),
}
}
}
impl CounterMetricImpl {
pub fn new(meta: CommonMetricData) -> Self {
Self(glean_core::metrics::CounterMetric::new(meta))
}
pub fn add(&self, amount: i32) {
crate::with_glean(move |glean| self.0.add(glean, amount))
}
pub fn test_get_value(&self, storage_name: &str) -> Option<i32> {
crate::with_glean(move |glean| self.0.test_get_value(glean, storage_name))
}
}
#[cfg(test)]
mod test {
use crate::{common_test::*, ipc, metrics};

Просмотреть файл

@ -193,7 +193,6 @@ mod test {
use crate::{common_test::*, ipc, metrics};
#[test]
#[ignore] // TODO: Enable them back when bug 1677448 lands.
fn sets_datetime_value() {
let _lock = lock_test();
@ -211,7 +210,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1677448 lands.
fn sets_datetime_value_with_details() {
let _lock = lock_test();
@ -226,7 +224,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1677448 lands.
fn datetime_ipc() {
// DatetimeMetric doesn't support IPC.
let _lock = lock_test();

Просмотреть файл

@ -197,7 +197,6 @@ mod test {
use crate::{common_test::*, ipc, metrics};
#[test]
#[ignore] // TODO: Enable them back when bug 1673668 lands.
fn smoke_test_event() {
let _lock = lock_test();
@ -221,7 +220,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1673668 lands.
fn smoke_test_event_with_extra() {
let _lock = lock_test();
@ -269,7 +267,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1673668 lands.
fn event_ipc() {
use metrics::test_only_ipc::AnEventKeys;

Просмотреть файл

@ -2,44 +2,91 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use std::sync::RwLock;
use glean_core::metrics::MetricType;
use super::{BooleanMetric, CommonMetricData, CounterMetric, ErrorType, MetricId, StringMetric};
use crate::dispatcher;
use crate::ipc::need_ipc;
/// Sealed traits protect against downstream implementations.
///
/// We wrap it in a private module that is inaccessible outside of this module.
mod private {
use super::{BooleanMetric, CounterMetric, StringMetric};
use super::{BooleanMetric, CommonMetricData, CounterMetric, MetricId, StringMetric};
use crate::ipc::need_ipc;
use std::sync::Arc;
/// The sealed trait.
///
/// This allows us to define which FOG metrics can be used
/// as labeled types.
/// This also allows us to hide methods, that are only used internally
/// and should not be visible to users.
pub trait Sealed {
type GleanMetric: glean::private::AllowLabeled + Clone;
type Inner: glean_core::metrics::MetricType + Clone;
/// Create a new metric object from the inner type.
fn from_inner(id: MetricId, metric: Self::Inner) -> Self;
/// Create a new `glean_core `metric of the inner type.
fn new_inner(meta: CommonMetricData) -> Self::Inner;
}
// `LabeledMetric<BooleanMetric>` is possible.
//
// See [Labeled Booleans](https://mozilla.github.io/glean/book/user/metrics/labeled_booleans.html).
impl Sealed for BooleanMetric {
type GleanMetric = glean::private::BooleanMetric;
type Inner = glean_core::metrics::BooleanMetric;
fn from_inner(_id: MetricId, metric: Self::Inner) -> Self {
assert!(
!need_ipc(),
"Labeled Boolean metrics are not supported in non-main processes"
);
BooleanMetric::Parent(Arc::new(crate::private::boolean::BooleanMetricImpl(metric)))
}
fn new_inner(meta: CommonMetricData) -> Self::Inner {
glean_core::metrics::BooleanMetric::new(meta)
}
}
// `LabeledMetric<StringMetric>` is possible.
//
// See [Labeled Strings](https://mozilla.github.io/glean/book/user/metrics/labeled_strings.html).
impl Sealed for StringMetric {
type GleanMetric = glean::private::StringMetric;
type Inner = glean_core::metrics::StringMetric;
fn from_inner(_id: MetricId, metric: Self::Inner) -> Self {
assert!(
!need_ipc(),
"Labeled String metrics are not supported in non-main processes"
);
StringMetric::Parent(crate::private::string::StringMetricImpl(metric))
}
fn new_inner(meta: CommonMetricData) -> Self::Inner {
glean_core::metrics::StringMetric::new(meta)
}
}
// `LabeledMetric<CounterMetric>` is possible.
//
// See [Labeled Counters](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html).
impl Sealed for CounterMetric {
type GleanMetric = glean::private::CounterMetric;
type Inner = glean_core::metrics::CounterMetric;
fn from_inner(id: MetricId, metric: Self::Inner) -> Self {
assert!(!need_ipc());
CounterMetric::Parent {
id,
inner: Arc::new(crate::private::counter::CounterMetricImpl(metric)),
}
}
fn new_inner(meta: CommonMetricData) -> Self::Inner {
glean_core::metrics::CounterMetric::new(meta)
}
}
}
@ -80,18 +127,17 @@ impl<T> AllowLabeled for T where T: private::Sealed {}
/// ```rust,ignore
/// errro::seen_one.get("upload").set(true);
/// ```
//#[derive(Debug)]
#[derive(Debug)]
pub struct LabeledMetric<T: AllowLabeled> {
// TODO: the `_id` is currently not needed, hence the
// prefix, but it will be needed when adding IPC support
// to this type.
/// The metric ID of the underlying metric.
_id: MetricId,
id: MetricId,
/// Wrapping the underlying core metric.
///
/// We delegate all functionality to this and wrap it up again in our own metric type.
core: glean::private::LabeledMetric<T::GleanMetric>,
///
/// *Note*: Needs to be thread-safe mutable, as required by the underlying `glean_core` type.
core: RwLock<glean_core::metrics::LabeledMetric<T::Inner>>,
}
impl<T> LabeledMetric<T>
@ -106,58 +152,72 @@ where
meta: CommonMetricData,
labels: Option<Vec<String>>,
) -> LabeledMetric<T> {
let core = glean::private::LabeledMetric::new(meta, labels);
LabeledMetric { _id: id, core }
}
}
let submetric = T::new_inner(meta);
let core = glean_core::metrics::LabeledMetric::new(submetric, labels);
#[inherent(pub)]
impl<U> glean_core::traits::Labeled<U::GleanMetric> for LabeledMetric<U>
where
U: AllowLabeled + Clone,
{
/// Gets a specific metric for a given label.
LabeledMetric {
id,
core: RwLock::new(core),
}
}
/// Get a specific metric for a given label.
///
/// If a set of acceptable labels were specified in the `metrics.yaml` file,
/// and the given label is not in the set, it will be recorded under the special `OTHER_LABEL` label.
/// and the given label is not in the set, it will be recorded under the special `__other__` label.
///
/// If a set of acceptable labels was not specified in the `metrics.yaml` file,
/// only the first 16 unique labels will be used.
/// After that, any additional labels will be recorded under the special `OTHER_LABEL` label.
/// After that, any additional labels will be recorded under the special `__other__` label.
///
/// Labels must be `snake_case` and less than 30 characters.
/// If an invalid label is used, the metric will be recorded in the special `OTHER_LABEL` label.
fn get(&self, label: &str) -> U::GleanMetric {
/// Labels must conform to the [label formatting regular expression](https://mozilla.github.io/glean/book/user/metrics/index.html#label-format).
/// Labels must be made up of dot-separated identifiers with lowercase ASCII alphanumerics, containing underscores and dashes.
///
/// If an invalid label is used, the metric will be recorded in the special `__other__` label.
pub fn get(&self, label: &str) -> T {
if need_ipc() {
panic!("Use of labeled metrics in IPC land not yet implemented!");
} else {
self.core.get(label)
let core = self
.core
.write()
.expect("lock of wrapped metric was poisoned");
let inner = core.get(label);
T::from_inner(self.id, inner)
}
}
/// **Exported for test purposes.**
/// **Test-only API.**
///
/// Gets the number of recorded errors for the given metric and error type.
/// Get the number of recorded errors for this labeled metric and error type.
///
/// # Arguments
/// ## Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
/// * error - The type of error
/// * `storage_name` - the storage name to look into.
///
/// # Returns
/// ## Return value
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
/// The number of errors reported if any.
/// Otherwise an error.
pub fn test_get_num_recorded_errors(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
if need_ipc() {
panic!("Use of labeled metrics in IPC land not yet implemented!");
} else {
self.core.test_get_num_recorded_errors(error, ping_name)
}
error_type: ErrorType,
storage_name: Option<&str>,
) -> Result<i32, String> {
dispatcher::block_on_queue();
crate::with_glean(move |glean| {
let core = self
.core
.read()
.expect("lock of wrapped metric was poisoned");
glean_core::test_get_num_recorded_errors(
&glean,
&core.get_submetric().meta(),
error_type,
storage_name,
)
})
}
}
@ -288,7 +348,7 @@ mod test {
.set(true);
assert_eq!(
1,
Ok(1),
metric.test_get_num_recorded_errors(ErrorType::InvalidLabel, None)
);
}
@ -325,9 +385,8 @@ mod test {
metric.get("__other__").test_get_value("store1").unwrap()
);
assert_eq!(
0,
metric.test_get_num_recorded_errors(ErrorType::InvalidLabel, None)
);
assert!(metric
.test_get_num_recorded_errors(ErrorType::InvalidLabel, None)
.is_err());
}
}

Просмотреть файл

@ -129,7 +129,6 @@ mod test {
use crate::{common_test::*, ipc, metrics};
#[test]
#[ignore] // TODO: Enable them back when bug 1677451 lands.
fn smoke_test_memory_distribution() {
let _lock = lock_test();
@ -154,7 +153,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1677451 lands.
fn memory_distribution_child() {
let _lock = lock_test();

Просмотреть файл

@ -2,18 +2,20 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use std::sync::Arc;
use crate::ipc::need_ipc;
use crate::{dispatcher, ipc::need_ipc};
/// A Glean ping.
///
/// See [Glean Pings](https://mozilla.github.io/glean/book/user/pings/index.html).
#[derive(Clone, Debug)]
pub enum Ping {
Parent(glean::private::PingType),
Parent(Arc<PingImpl>),
Child,
}
#[derive(Debug)]
pub struct PingImpl(glean_core::metrics::PingType);
impl Ping {
/// Create a new ping type for the given name, whether to include the client ID and whether to
@ -34,28 +36,39 @@ impl Ping {
if need_ipc() {
Ping::Child
} else {
Ping::Parent(glean::private::PingType::new(
Ping::Parent(Arc::new(PingImpl::new(
name,
include_client_id,
send_if_empty,
reason_codes,
))
)))
}
}
}
#[inherent(pub)]
impl glean_core::traits::Ping for Ping {
/// Submits the ping for eventual uploading
/// Collect and submit the ping for eventual upload.
///
/// # Arguments
/// This will collect all stored data to be included in the ping.
/// Data with lifetime `ping` will then be reset.
///
/// * `reason` - the reason the ping was triggered. Included in the
/// `ping_info.reason` part of the payload.
fn submit(&self, reason: Option<&str>) {
/// If the ping is configured with `send_if_empty = false`
/// and the ping currently contains no content,
/// it will not be queued for upload.
/// If the ping is configured with `send_if_empty = true`
/// it will be queued for upload even if otherwise empty.
///
/// Pings always contain the `ping_info` and `client_info` sections.
/// See [ping sections](https://mozilla.github.io/glean/book/user/pings/index.html#ping-sections)
/// for details.
///
/// ## Parameters
/// * `reason` - The reason the ping is being submitted.
/// Must be one of the configured `reason_codes`.
pub fn submit(&self, reason: Option<&str>) {
match self {
Ping::Parent(p) => {
glean_core::traits::Ping::submit(p, reason);
let ping = Arc::clone(&p);
let reason = reason.map(|x| x.to_owned());
dispatcher::launch(move || ping.submit(reason.as_deref()));
}
Ping::Child => {
log::error!(
@ -68,6 +81,35 @@ impl glean_core::traits::Ping for Ping {
}
}
impl PingImpl {
pub fn new<S: Into<String>>(
name: S,
include_client_id: bool,
send_if_empty: bool,
reason_codes: Vec<String>,
) -> Self {
let ping = glean_core::metrics::PingType::new(
name,
include_client_id,
send_if_empty,
reason_codes,
);
crate::with_glean(|glean| {
glean.register_ping_type(&ping);
});
Self(ping)
}
pub fn submit(&self, reason: Option<&str>) {
let res = crate::with_glean(|glean| self.0.submit(glean, reason).unwrap_or(false));
if res {
crate::ping_upload::check_for_uploads();
}
}
}
#[cfg(test)]
mod test {
use once_cell::sync::Lazy;

Просмотреть файл

@ -2,8 +2,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use super::{CommonMetricData, MetricId};
use crate::ipc::need_ipc;
@ -37,12 +35,15 @@ use crate::ipc::need_ipc;
/// ```rust,ignore
/// browser::search_engine.set("websearch");
/// ```
#[derive(Clone)]
#[derive(Debug)]
pub enum StringMetric {
Parent(glean::private::StringMetric),
Parent(StringMetricImpl),
Child(StringMetricIpc),
}
#[derive(Clone, Debug)]
pub struct StringMetricImpl(pub(crate) glean_core::metrics::StringMetric);
#[derive(Debug)]
pub struct StringMetricIpc;
impl StringMetric {
@ -51,7 +52,7 @@ impl StringMetric {
if need_ipc() {
StringMetric::Child(StringMetricIpc)
} else {
StringMetric::Parent(glean::private::StringMetric::new(meta))
StringMetric::Parent(StringMetricImpl::new(meta))
}
}
@ -62,80 +63,68 @@ impl StringMetric {
StringMetric::Child(_) => panic!("Can't get a child metric from a child metric"),
}
}
}
#[inherent(pub)]
impl glean_core::traits::String for StringMetric {
/// Sets to the specified value.
/// Set to the specified value.
///
/// # Arguments
/// ## Arguments
///
/// * `value` - The string to set the metric to.
///
/// ## Notes
///
/// Truncates the value if it is longer than `MAX_STRING_LENGTH` bytes and logs an error.
fn set<S: Into<std::string::String>>(&self, value: S) {
/// See [String metric limits](https://mozilla.github.io/glean/book/user/metrics/string.html#limits).
pub fn set<S: Into<String>>(&self, value: S) {
match self {
StringMetric::Parent(p) => {
glean_core::traits::String::set(&*p, value);
}
StringMetric::Parent(p) => p.set(value),
// No truncation here. Hrm.
StringMetric::Child(_) => {
log::error!("Unable to set string metric in non-main process. Ignoring.");
log::error!(
"Unable to set string metric {:?} in non-main process. Ignoring.",
self
);
// TODO: Record an error.
}
};
}
/// **Exported for test purposes.**
///
/// Gets the currently stored value as a string.
/// **Test-only API.**
///
/// Get the currently stored value as a string.
/// This doesn't clear the stored value.
///
/// # Arguments
/// ## Arguments
///
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
fn test_get_value<'a, S: Into<Option<&'a str>>>(
&self,
ping_name: S,
) -> Option<std::string::String> {
/// * `storage_name` - the storage name to look into.
///
/// ## Return value
///
/// Returns the stored value or `None` if nothing stored.
pub fn test_get_value(&self, storage_name: &str) -> Option<String> {
match self {
StringMetric::Parent(p) => p.test_get_value(ping_name),
StringMetric::Child(_) => {
panic!("Cannot get test value for string metric in non-parent process!")
}
}
}
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: glean::ErrorType,
ping_name: S,
) -> i32 {
match self {
StringMetric::Parent(p) => p.test_get_num_recorded_errors(error, ping_name),
StringMetric::Parent(p) => p.test_get_value(storage_name),
StringMetric::Child(_) => panic!(
"Cannot get the number of recorded errors for string metric in non-parent process!"
"Cannot get test value for {:?} in non-parent process!",
self
),
}
}
}
impl StringMetricImpl {
fn new(meta: CommonMetricData) -> Self {
Self(glean_core::metrics::StringMetric::new(meta))
}
fn set<S: Into<String>>(&self, value: S) {
crate::with_glean(move |glean| self.0.set(glean, value))
}
fn test_get_value(&self, storage_name: &str) -> Option<String> {
crate::with_glean(move |glean| self.0.test_get_value(glean, storage_name))
}
}
#[cfg(test)]
mod test {
use crate::{common_test::*, ipc, metrics};

Просмотреть файл

@ -156,7 +156,6 @@ mod test {
use crate::{common_test::*, ipc, metrics};
#[test]
#[ignore] // TODO: Enable them back when bug 1677454 lands.
fn sets_string_list_value() {
let _lock = lock_test();
@ -172,7 +171,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1677454 lands.
fn string_list_ipc() {
// StringListMetric supports IPC only for `add`, not `set`.
let _lock = lock_test();

Просмотреть файл

@ -160,7 +160,6 @@ mod test {
use crate::{common_test::*, ipc, metrics};
#[test]
#[ignore] // TODO: Enable them back when bug 1677455 lands.
fn smoke_test_timespan() {
let _lock = lock_test();
@ -186,7 +185,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1677455 lands.
fn timespan_ipc() {
let _lock = lock_test();
let _raii = ipc::test_set_need_ipc(true);

Просмотреть файл

@ -291,7 +291,6 @@ mod test {
use crate::{common_test::*, ipc, metrics};
#[test]
#[ignore] // TODO: Enable them back when bug 1677456 lands.
fn smoke_test_timing_distribution() {
let _lock = lock_test();
@ -308,7 +307,6 @@ mod test {
}
#[test]
#[ignore] // TODO: Enable them back when bug 1677456 lands.
fn timing_distribution_child() {
let _lock = lock_test();

Просмотреть файл

@ -2,22 +2,25 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use inherent::inherent;
use std::sync::Arc;
use uuid::Uuid;
use super::{CommonMetricData, MetricId};
use crate::ipc::need_ipc;
use crate::{dispatcher, ipc::need_ipc};
/// A UUID metric.
///
/// Stores UUID values.
#[derive(Debug)]
pub enum UuidMetric {
Parent(glean::private::UuidMetric),
Parent(Arc<UuidMetricImpl>),
Child(UuidMetricIpc),
}
#[derive(Clone, Debug)]
pub struct UuidMetricImpl(pub(crate) glean_core::metrics::UuidMetric);
#[derive(Debug)]
pub struct UuidMetricIpc;
@ -27,7 +30,7 @@ impl UuidMetric {
if need_ipc() {
UuidMetric::Child(UuidMetricIpc)
} else {
UuidMetric::Parent(glean::private::UuidMetric::new(meta))
UuidMetric::Parent(Arc::new(UuidMetricImpl::new(meta)))
}
}
@ -38,42 +41,43 @@ impl UuidMetric {
UuidMetric::Child(_) => panic!("Can't get a child metric from a child metric"),
}
}
}
#[inherent(pub)]
impl glean_core::traits::Uuid for UuidMetric {
/// Set to the specified value.
///
/// ## Arguments
///
/// * `value` - The UUID to set the metric to.
fn set(&self, value: Uuid) {
pub fn set(&self, value: Uuid) {
match self {
UuidMetric::Parent(p) => {
glean_core::traits::Uuid::set(&*p, value);
let metric = Arc::clone(&p);
dispatcher::launch(move || metric.set(value));
}
UuidMetric::Child(_c) => {
log::error!("Unable to set the uuid metric in non-main process. Ignoring.");
log::error!(
"Unable to set UUID metric {:?} in non-main process. Ignoring.",
self
);
// TODO: Record an error.
}
};
}
/// Generate a new random UUID and set the metric to it.
///
/// ## Return value
///
/// Returns the stored UUID value or `Uuid::nil` if called from
/// a non-parent process.
fn generate_and_set(&self) -> Uuid {
pub fn generate_and_set(&self) {
match self {
UuidMetric::Parent(p) => glean_core::traits::Uuid::generate_and_set(&*p),
UuidMetric::Child(_c) => {
log::error!("Unable to set the uuid metric in non-main process. Ignoring.");
// TODO: Record an error.
Uuid::nil()
UuidMetric::Parent(p) => {
let metric = Arc::clone(&p);
dispatcher::launch(move || metric.generate_and_set());
}
}
UuidMetric::Child(_c) => {
log::error!(
"Unable to set UUID metric {:?} in non-main process. Ignoring.",
self
);
// TODO: Record an error.
}
};
}
/// **Test-only API.**
@ -88,37 +92,37 @@ impl glean_core::traits::Uuid for UuidMetric {
/// ## Return value
///
/// Returns the stored value or `None` if nothing stored.
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, storage_name: S) -> Option<Uuid> {
pub fn test_get_value(&self, storage_name: &str) -> Option<Uuid> {
match self {
UuidMetric::Parent(p) => p.test_get_value(storage_name),
UuidMetric::Child(_c) => panic!("Cannot get test value for in non-parent process!"),
UuidMetric::Parent(p) => {
dispatcher::block_on_queue();
p.test_get_value(storage_name).map(|uuid| {
Uuid::parse_str(&uuid).expect("can't parse internally created UUID value")
})
}
UuidMetric::Child(_c) => panic!(
"Cannot get test value for {:?} in non-parent process!",
self
),
}
}
}
/// **Exported for test purposes.**
///
/// Gets the number of recorded errors for the given metric and error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: glean::ErrorType,
ping_name: S,
) -> i32 {
match self {
UuidMetric::Parent(p) => p.test_get_num_recorded_errors(error, ping_name),
UuidMetric::Child(_c) => {
panic!("Cannot get test value for UuidMetric in non-parent process!")
}
}
impl UuidMetricImpl {
fn new(meta: CommonMetricData) -> Self {
Self(glean_core::metrics::UuidMetric::new(meta))
}
fn set(&self, value: Uuid) {
crate::with_glean(move |glean| self.0.set(glean, value));
}
fn generate_and_set(&self) {
crate::with_glean(move |glean| self.0.generate_and_set(glean));
}
fn test_get_value(&self, storage_name: &str) -> Option<String> {
crate::with_glean(move |glean| self.0.test_get_value(glean, storage_name))
}
}

Просмотреть файл

@ -36,10 +36,9 @@ TEST(FOG, FogInitDoesntCrash)
Preferences::SetBool(DATA_PREF, true);
}
// TODO: to be enabled after changes from bug 1677455 are vendored.
// extern "C" void Rust_MeasureInitializeTime();
// TEST(FOG, TestMeasureInitializeTime)
// { Rust_MeasureInitializeTime(); }
extern "C" void Rust_MeasureInitializeTime();
TEST(FOG, TestMeasureInitializeTime)
{ Rust_MeasureInitializeTime(); }
TEST(FOG, BuiltinPingsRegistered)
{
@ -48,8 +47,9 @@ TEST(FOG, BuiltinPingsRegistered)
nsAutoCString baselinePingName("baseline");
nsAutoCString eventsPingName("events");
ASSERT_EQ(NS_OK, fog_submit_ping(&metricsPingName));
ASSERT_EQ(NS_OK, fog_submit_ping(&baselinePingName));
ASSERT_EQ(NS_OK, fog_submit_ping(&eventsPingName));
// This will probably change to NS_OK once "duration" is implemented.
ASSERT_EQ(NS_ERROR_NO_CONTENT, fog_submit_ping(&baselinePingName));
ASSERT_EQ(NS_ERROR_NO_CONTENT, fog_submit_ping(&eventsPingName));
}
TEST(FOG, TestCppCounterWorks)
@ -72,17 +72,16 @@ TEST(FOG, TestCppStringWorks)
.get());
}
// TODO: to be enabled after changes from bug 1677455 are vendored.
// TEST(FOG, TestCppTimespanWorks)
// {
// mozilla::glean::test_only::can_we_time_it.Start();
// PR_Sleep(PR_MillisecondsToInterval(10));
// mozilla::glean::test_only::can_we_time_it.Stop();
//
// ASSERT_TRUE(
// mozilla::glean::test_only::can_we_time_it.TestGetValue("test-ping")
// .value() > 0);
// }
TEST(FOG, TestCppTimespanWorks)
{
mozilla::glean::test_only::can_we_time_it.Start();
PR_Sleep(PR_MillisecondsToInterval(10));
mozilla::glean::test_only::can_we_time_it.Stop();
ASSERT_TRUE(
mozilla::glean::test_only::can_we_time_it.TestGetValue("test-ping")
.value() > 0);
}
TEST(FOG, TestCppUuidWorks)
{
@ -98,12 +97,11 @@ TEST(FOG, TestCppUuidWorks)
test_only::what_id_it.TestGetValue("test-ping").value().get());
}
// TODO: to be enabled after changes from bug 1677448 are vendored.
// TEST(FOG, TestCppDatetimeWorks)
// {
// PRExplodedTime date = {0, 35, 10, 12, 6, 10, 2020, 0, 0, {5 * 60 * 60, 0}};
// test_only::what_a_date.Set(&date);
//
// auto received = test_only::what_a_date.TestGetValue("test-ping");
// ASSERT_STREQ(received.value().get(), "2020-11-06T12:10:35+05:00");
// }
TEST(FOG, TestCppDatetimeWorks)
{
PRExplodedTime date = {0, 35, 10, 12, 6, 10, 2020, 0, 0, {5 * 60 * 60, 0}};
test_only::what_a_date.Set(&date);
auto received = test_only::what_a_date.TestGetValue("test-ping");
ASSERT_STREQ(received.value().get(), "2020-11-06T12:10:35+05:00");
}

Просмотреть файл

@ -0,0 +1,223 @@
// 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 https://mozilla.org/MPL/2.0/.
//! The general API to initialize and control Glean.
//!
//! ## Example
//!
//! ```ignore
//! let configuration = Configuration { /* ... */ };
//! let client_info = ClientInfo { /* ... */ };
//!
//! // Initialize Glean once and passing in client information.
//! initialize(configuration, client_info)?;
//!
//! // Toggle the upload enabled preference.
//! set_upload_enabled(false);
//! ```
// FIXME: Remove when code gets actually used eventually (by initializing Glean).
#![allow(dead_code)]
use fog::dispatcher;
use fog::ping_upload::{self, UploadResult};
use glean_core::{global_glean, setup_glean, Configuration, Glean, Result};
use once_cell::sync::OnceCell;
use url::Url;
use viaduct::Request;
use crate::client_info::ClientInfo;
use crate::core_metrics::InternalMetrics;
/// Application state to keep track of.
#[derive(Debug, Clone)]
pub struct AppState {
/// Client info metrics set by the application.
client_info: ClientInfo,
}
/// A global singleton storing additional state for Glean.
static STATE: OnceCell<AppState> = OnceCell::new();
/// Get a reference to the global state object.
///
/// Panics if no global state object was set.
fn global_state() -> &'static AppState {
STATE.get().unwrap()
}
/// Run a closure with a mutable reference to the locked global Glean object,
/// or return None if the global Glean isn't available.
fn with_glean_mut<F, R>(f: F) -> Option<R>
where
F: Fn(&mut Glean) -> R,
{
let mut glean = global_glean()?.lock().unwrap();
Some(f(&mut glean))
}
/// Create and initialize a new Glean object.
///
/// See `glean_core::Glean::new`.
///
/// ## Thread safety
///
/// Many threads may call `initialize` concurrently with different configuration and client info,
/// but it is guaranteed that only one function will be executed.
///
/// Glean will only be initialized exactly once with the configuration and client info obtained
/// from the first call.
/// Subsequent calls have no effect.
pub fn initialize(cfg: Configuration, client_info: ClientInfo) -> Result<()> {
STATE
.get_or_try_init(|| {
let mut glean = Glean::new(cfg)?;
// First initialize core metrics
initialize_core_metrics(&glean, &client_info);
// Then register builtin pings.
// Borrowed from glean-core's internal_pings.rs.
let mping = glean_core::metrics::PingType::new(
"metrics",
true,
false,
vec![
"overdue".to_string(),
"reschedule".to_string(),
"today".to_string(),
"tomorrow".to_string(),
"upgrade".to_string(),
],
);
glean.register_ping_type(&mping);
let bping = glean_core::metrics::PingType::new("baseline", true, false, vec![]);
glean.register_ping_type(&bping);
let eping = glean_core::metrics::PingType::new("events", true, false, vec![]);
glean.register_ping_type(&eping);
// Now make this the global object available to others.
setup_glean(glean)?;
// Register the uploader so we can upload pings.
register_uploader();
Ok(AppState { client_info })
})
.map(|_| ())
}
/// Set the application's core metrics based on the passed client info.
fn initialize_core_metrics(glean: &Glean, client_info: &ClientInfo) {
let core_metrics = InternalMetrics::new();
core_metrics
.app_build
.set(glean, &client_info.app_build[..]);
core_metrics
.app_display_version
.set(glean, &client_info.app_display_version[..]);
if let Some(app_channel) = &client_info.channel {
core_metrics.app_channel.set(glean, app_channel);
}
core_metrics
.os_version
.set(glean, &client_info.os_version[..]);
core_metrics
.architecture
.set(glean, &client_info.architecture);
}
/// Set whether upload is enabled or not.
///
/// See `glean_core::Glean.set_upload_enabled`.
pub fn set_upload_enabled(enabled: bool) {
dispatcher::launch(move || {
with_glean_mut(|glean| {
let state = global_state();
let old_enabled = glean.is_upload_enabled();
glean.set_upload_enabled(enabled);
if !old_enabled && enabled {
// If uploading is being re-enabled, we have to restore the
// application-lifetime metrics.
initialize_core_metrics(&glean, &state.client_info);
} else if old_enabled && !enabled {
// If upload is being disabled, check for pings to send.
ping_upload::check_for_uploads();
}
enabled
})
.expect("Setting upload enabled failed!");
});
}
fn register_uploader() {
let result = ping_upload::register_uploader(Box::new(|ping_request| {
log::trace!(
"FOG Ping Uploader uploading ping {}",
ping_request.document_id
);
let result: std::result::Result<UploadResult, viaduct::Error> = (move || {
const SERVER: &str = "https://incoming.telemetry.mozilla.org";
let mut server = String::from(SERVER);
let localhost_port = static_prefs::pref!("telemetry.fog.test.localhost_port");
if localhost_port > 0 {
server = format!("http://localhost:{}", localhost_port);
} else if localhost_port < 0 {
log::info!("FOG Ping uploader faking success");
return Ok(UploadResult::HttpStatus(200));
}
let url = Url::parse(&server)?.join(&ping_request.path)?;
log::info!("FOG Ping uploader uploading to {:?}", url);
let mut req = Request::post(url).body(ping_request.body.clone());
for (header_key, header_value) in &ping_request.headers {
req = req.header(header_key.to_owned(), header_value)?;
}
log::trace!(
"FOG Ping Uploader sending ping {}",
ping_request.document_id
);
let res = req.send()?;
Ok(UploadResult::HttpStatus(res.status.into()))
})();
log::trace!(
"FOG Ping Uploader completed uploading ping {} (Result {:?})",
ping_request.document_id,
result
);
match result {
Ok(result) => result,
_ => UploadResult::UnrecoverableFailure,
}
}));
if result.is_err() {
log::warn!(
"Couldn't register uploader because one's already in there. {:?}",
result
);
}
}
pub fn set_debug_view_tag(value: &str) -> bool {
with_glean_mut(|glean| glean.set_debug_view_tag(value)).unwrap_or(false)
}
pub fn submit_ping(ping_name: &str) -> Result<bool> {
match with_glean_mut(|glean| glean.submit_ping_by_name(ping_name, None)) {
Some(Ok(true)) => {
ping_upload::check_for_uploads();
Ok(true)
}
Some(result) => result,
None => Ok(false),
}
}
pub fn set_log_pings(value: bool) -> bool {
with_glean_mut(|glean| glean.set_log_pings(value)).unwrap_or(false)
}

Просмотреть файл

@ -0,0 +1,18 @@
// 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 https://mozilla.org/MPL/2.0/.
/// Metrics included in every ping as `client_info`.
#[derive(Debug, Clone)]
pub struct ClientInfo {
/// The build identifier generated by the CI system (e.g. "1234/A").
pub app_build: String,
/// The user visible version string (e.g. "1.0.3").
pub app_display_version: String,
/// The release channel the application is on, if known.
pub channel: Option<String>,
/// The user-visible version of the operating system (e.g. "1.2.3").
pub os_version: String,
/// The architecture of the device, (e.g. "x86-64", "arm").
pub architecture: String,
}

Просмотреть файл

@ -0,0 +1,65 @@
// 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 https://mozilla.org/MPL/2.0/.
//! Internal metrics used to fill in the [client info section][client_info] included in every ping.
//!
//! [client_info]: https://mozilla.github.io/glean/book/user/pings/index.html#the-client_info-section
use glean_core::{metrics::StringMetric, CommonMetricData, Lifetime};
#[derive(Debug)]
pub struct InternalMetrics {
pub app_build: StringMetric,
pub app_display_version: StringMetric,
pub app_channel: StringMetric,
pub os_version: StringMetric,
pub architecture: StringMetric,
}
impl InternalMetrics {
pub fn new() -> Self {
Self {
app_build: StringMetric::new(CommonMetricData {
name: "app_build".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
app_display_version: StringMetric::new(CommonMetricData {
name: "app_display_version".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
app_channel: StringMetric::new(CommonMetricData {
name: "app_channel".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
os_version: StringMetric::new(CommonMetricData {
name: "os_version".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
architecture: StringMetric::new(CommonMetricData {
name: "architecture".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
}
}
}

Просмотреть файл

@ -29,18 +29,19 @@ extern crate xpcom;
use std::ffi::CStr;
use std::os::raw::c_char;
use nserror::{nsresult, NS_ERROR_FAILURE, NS_OK};
use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_NO_CONTENT, NS_OK};
use nsstring::{nsACString, nsAString, nsCStr, nsCString, nsStr, nsString};
use xpcom::interfaces::{
mozIViaduct, nsIFile, nsIObserver, nsIPrefBranch, nsIPropertyBag2, nsISupports, nsIXULAppInfo,
};
use xpcom::{RefPtr, XpCom};
use glean::{ClientInfoMetrics, Configuration};
use client_info::ClientInfo;
use glean_core::Configuration;
mod viaduct_uploader;
use crate::viaduct_uploader::ViaductUploader;
mod api;
mod client_info;
mod core_metrics;
/// Project FOG's entry point.
///
@ -62,15 +63,17 @@ pub unsafe extern "C" fn fog_init() -> nsresult {
Err(e) => return e,
};
// TODO: os_version will be sent as a new metric in bug 1679835.
let (_os_version, _architecture) = match get_system_info() {
let (os_version, architecture) = match get_system_info() {
Ok(si) => si,
Err(e) => return e,
};
let client_info = ClientInfoMetrics {
let client_info = ClientInfo {
app_build,
app_display_version,
channel: Some(channel),
os_version,
architecture,
};
log::debug!("Client Info: {:#?}", client_info);
@ -83,14 +86,6 @@ pub unsafe extern "C" fn fog_init() -> nsresult {
return e;
}
const SERVER: &str = "https://incoming.telemetry.mozilla.org";
let localhost_port = static_prefs::pref!("telemetry.fog.test.localhost_port");
let server = if localhost_port > 0 {
format!("http://localhost:{}", localhost_port)
} else {
String::from(SERVER)
};
let upload_enabled = static_prefs::pref!("datareporting.healthreport.uploadEnabled");
let data_path = data_path.to_string();
let configuration = Configuration {
@ -99,9 +94,7 @@ pub unsafe extern "C" fn fog_init() -> nsresult {
application_id: "firefox.desktop".to_string(),
max_events: None,
delay_ping_lifetime_io: false,
channel: Some(channel),
server_endpoint: Some(server),
uploader: Some(Box::new(crate::ViaductUploader) as Box<dyn glean::net::PingUploader>),
language_binding_name: "Rust".into(),
};
log::debug!("Configuration: {:#?}", configuration);
@ -120,9 +113,20 @@ pub unsafe extern "C" fn fog_init() -> nsresult {
}
if configuration.data_path.len() > 0 {
glean::initialize(configuration, client_info);
fog::metrics::fog::initialization.stop();
schedule_fog_validation_ping();
std::thread::spawn(move || {
if let Err(e) = api::initialize(configuration, client_info) {
log::error!("Failed to init FOG due to {:?}", e);
return;
}
if let Err(e) = fog::flush_init() {
log::error!("Failed to flush pre-init buffer due to {:?}", e);
return;
}
fog::metrics::fog::initialization.stop();
schedule_fog_validation_ping();
});
}
NS_OK
@ -130,7 +134,7 @@ pub unsafe extern "C" fn fog_init() -> nsresult {
#[no_mangle]
pub unsafe extern "C" fn fog_shutdown() {
glean::shutdown();
fog::shutdown();
}
/// Construct and return the data_path from the profile dir, or return an error.
@ -271,7 +275,7 @@ impl UploadPrefObserver {
);
let upload_enabled = static_prefs::pref!("datareporting.healthreport.uploadEnabled");
glean::set_upload_enabled(upload_enabled);
api::set_upload_enabled(upload_enabled);
NS_OK
}
}
@ -325,7 +329,7 @@ pub unsafe extern "C" fn fog_use_ipc_buf(buf: *const u8, buf_len: usize) {
/// Sets the debug tag for pings assembled in the future.
/// Returns an error result if the provided value is not a valid tag.
pub unsafe extern "C" fn fog_set_debug_view_tag(value: &nsACString) -> nsresult {
let result = glean::set_debug_view_tag(&value.to_string());
let result = api::set_debug_view_tag(&value.to_string());
if result {
return NS_OK;
} else {
@ -335,17 +339,26 @@ pub unsafe extern "C" fn fog_set_debug_view_tag(value: &nsACString) -> nsresult
#[no_mangle]
/// Submits a ping by name.
/// Returns NS_OK if the ping was successfully submitted, NS_ERROR_NO_CONTENT
/// if the ping wasn't sent, or NS_ERROR_FAILURE if some part of the ping
/// submission mechanism failed.
pub unsafe extern "C" fn fog_submit_ping(ping_name: &nsACString) -> nsresult {
glean::submit_ping_by_name(&ping_name.to_string(), None);
NS_OK
match api::submit_ping(&ping_name.to_string()) {
Ok(true) => NS_OK,
Ok(false) => NS_ERROR_NO_CONTENT,
_ => NS_ERROR_FAILURE,
}
}
#[no_mangle]
/// Turns ping logging on or off.
/// Returns an error if the logging failed to be configured.
pub unsafe extern "C" fn fog_set_log_pings(value: bool) -> nsresult {
glean::set_log_pings(value);
NS_OK
if api::set_log_pings(value) {
return NS_OK;
} else {
return NS_ERROR_FAILURE;
}
}
fn schedule_fog_validation_ping() {

Просмотреть файл

@ -1,54 +0,0 @@
// 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 https://mozilla.org/MPL/2.0/.
use glean::net::{PingUploader, UploadResult};
use url::Url;
use viaduct::Request;
/// An uploader that uses [Viaduct](https://github.com/mozilla/application-services/tree/main/components/viaduct).
#[derive(Debug)]
pub(crate) struct ViaductUploader;
impl PingUploader for ViaductUploader {
/// Uploads a ping to a server.
///
/// # Arguments
///
/// * `url` - the URL path to upload the data to.
/// * `body` - the serialized text data to send.
/// * `headers` - a vector of tuples containing the headers to send with
/// the request, i.e. (Name, Value).
fn upload(&self, url: String, body: Vec<u8>, headers: Vec<(String, String)>) -> UploadResult {
log::trace!("FOG Ping Uploader uploading to {}", url);
let url_clone = url.clone();
let result: std::result::Result<UploadResult, viaduct::Error> = (move || {
let localhost_port = static_prefs::pref!("telemetry.fog.test.localhost_port");
if localhost_port < 0 {
log::info!("FOG Ping uploader faking success");
return Ok(UploadResult::HttpStatus(200));
}
let parsed_url = Url::parse(&url_clone)?;
log::info!("FOG Ping uploader uploading to {:?}", parsed_url);
let mut req = Request::post(parsed_url.clone()).body(body.clone());
for (header_key, header_value) in &headers {
req = req.header(header_key.to_owned(), header_value)?;
}
log::trace!("FOG Ping Uploader sending ping to {}", parsed_url);
let res = req.send()?;
Ok(UploadResult::HttpStatus(res.status.into()))
})();
log::trace!(
"FOG Ping Uploader completed uploading to {} (Result {:?})",
url,
result
);
match result {
Ok(result) => result,
_ => UploadResult::UnrecoverableFailure,
}
}
}

Просмотреть файл

@ -38,8 +38,7 @@ add_task(async function test_fog_string_works() {
Assert.equal(value, Glean.test_only.cheesy_string.testGetValue("test-ping"));
});
// Enable test after bug 1677455 is fixed.
add_task({ skip_if: () => true }, async function test_fog_timespan_works() {
add_task(async function test_fog_timespan_works() {
// We start, briefly sleep and then stop.
// That guarantees some time to measure.
Glean.test_only.can_we_time_it.start();
@ -63,8 +62,7 @@ add_task(async function test_fog_uuid_works() {
);
});
// Enable test after bug 1677448 is fixed.
add_task({ skip_if: () => true }, function test_fog_datetime_works() {
add_task(function test_fog_datetime_works() {
const value = new Date("2020-06-11T12:00:00");
Glean.test_only.what_a_date.set(value.getTime() * 1000);