Bug 1682638 - Update to Glean v33.9.1. r=Dexter

Differential Revision: https://phabricator.services.mozilla.com/D100006
This commit is contained in:
Jan-Erik Rediger 2020-12-17 13:12:08 +00:00
Родитель a7af908f30
Коммит 04b73ee4f1
57 изменённых файлов: 1254 добавлений и 451 удалений

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

@ -2083,10 +2083,11 @@ dependencies = [
[[package]]
name = "glean"
version = "33.8.0"
version = "33.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91b0b03e572ce70d06cf92ca899bdab8679e4ca07a2877928df028c848a1e9a"
checksum = "120a2f092bcf0b8fa0ec864e1a063426638f7084671eddfd138b5571e1e2c6fd"
dependencies = [
"chrono",
"crossbeam-channel",
"glean-core",
"inherent",
@ -2101,9 +2102,9 @@ dependencies = [
[[package]]
name = "glean-core"
version = "33.8.0"
version = "33.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440d35335296536f0cf46ca79b6edc4f93b3cfdaef2ce8696b7f7e6ee3d7b69f"
checksum = "b2c8e087b69c8392fca868214b4675230e36832f231cc6045d08caed0d33e3c1"
dependencies = [
"bincode",
"chrono",

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

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

@ -180,7 +180,7 @@ dependencies = [
[[package]]
name = "glean-core"
version = "33.8.0"
version = "33.9.1"
dependencies = [
"bincode",
"chrono",

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

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "glean-core"
version = "33.8.0"
version = "33.9.1"
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"

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

@ -48,7 +48,21 @@ mod backend {
pub type Writer<'t> = rkv::Writer<rkv::backend::SafeModeRwTransaction<'t>>;
pub fn rkv_new(path: &Path) -> Result<Rkv, rkv::StoreError> {
Rkv::new::<rkv::backend::SafeMode>(path)
match Rkv::new::<rkv::backend::SafeMode>(path) {
// An invalid file can mean:
// 1. An empty file.
// 2. A corrupted file.
//
// In both instances there's not much we can do.
// Drop the data by removing the file, and start over.
Err(rkv::StoreError::FileInvalid) => {
let safebin = path.join("data.safe.bin");
fs::remove_file(safebin).map_err(|_| rkv::StoreError::FileInvalid)?;
// Now try again, we only handle that error once.
Rkv::new::<rkv::backend::SafeMode>(path)
}
other => other,
}
}
fn delete_and_log(path: &Path, msg: &str) {
@ -1308,11 +1322,71 @@ mod test {
);
}
/// LDMB ignores an empty database file just fine.
#[cfg(not(feature = "rkv-safe-mode"))]
#[test]
fn empty_data_file() {
let dir = tempdir().unwrap();
let str_dir = dir.path().display().to_string();
// Create database directory structure.
let database_dir = dir.path().join("db");
fs::create_dir_all(&database_dir).expect("create database dir");
// Create empty database file.
let datamdb = database_dir.join("data.mdb");
let f = fs::File::create(datamdb).expect("create database file");
drop(f);
Database::new(&str_dir, false).unwrap();
assert!(dir.path().exists());
}
#[cfg(feature = "rkv-safe-mode")]
mod safe_mode_migration {
mod safe_mode {
use std::fs::File;
use super::*;
use rkv::Value;
#[test]
fn empty_data_file() {
let dir = tempdir().unwrap();
let str_dir = dir.path().display().to_string();
// Create database directory structure.
let database_dir = dir.path().join("db");
fs::create_dir_all(&database_dir).expect("create database dir");
// Create empty database file.
let safebin = database_dir.join("data.safe.bin");
let f = File::create(safebin).expect("create database file");
drop(f);
Database::new(&str_dir, false).unwrap();
assert!(dir.path().exists());
}
#[test]
fn corrupted_data_file() {
let dir = tempdir().unwrap();
let str_dir = dir.path().display().to_string();
// Create database directory structure.
let database_dir = dir.path().join("db");
fs::create_dir_all(&database_dir).expect("create database dir");
// Create empty database file.
let safebin = database_dir.join("data.safe.bin");
fs::write(safebin, "<broken>").expect("write to database file");
Database::new(&str_dir, false).unwrap();
assert!(dir.path().exists());
}
#[test]
fn migration_works_on_startup() {
let dir = tempdir().unwrap();

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

@ -49,6 +49,7 @@ use crate::debug::DebugOptions;
pub use crate::error::{Error, ErrorKind, Result};
pub use crate::error_recording::{test_get_num_recorded_errors, ErrorType};
use crate::event_database::EventDatabase;
pub use crate::histogram::HistogramType;
use crate::internal_metrics::{CoreMetrics, DatabaseMetrics};
use crate::internal_pings::InternalPings;
use crate::metrics::{Metric, MetricType, PingType};
@ -863,6 +864,7 @@ impl Glean {
self.storage(),
INTERNAL_STORAGE,
&dirty_bit_metric.meta().identifier(self),
dirty_bit_metric.meta().lifetime,
) {
Some(Metric::Boolean(b)) => b,
_ => false,

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

@ -61,6 +61,7 @@ impl BooleanMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Boolean(b)) => Some(b),
_ => None,

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

@ -84,6 +84,7 @@ impl CounterMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Counter(i)) => Some(i),
_ => None,

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

@ -162,6 +162,7 @@ impl CustomDistributionMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
// Boxing the value, in order to return either of the possible buckets
Some(Metric::CustomDistributionExponential(hist)) => Some(snapshot(&hist)),

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

@ -13,7 +13,7 @@ use crate::util::{get_iso_time_string, local_now_with_offset};
use crate::CommonMetricData;
use crate::Glean;
use chrono::{DateTime, FixedOffset, TimeZone};
use chrono::{DateTime, FixedOffset, TimeZone, Timelike};
/// A datetime type.
///
@ -136,13 +136,73 @@ impl DatetimeMetric {
match StorageManager.snapshot_metric(
glean.storage(),
storage_name,
&self.meta().identifier(glean),
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Datetime(dt, _)) => Some(dt),
_ => None,
}
}
/// **Test-only API (exported for FFI purposes).**
///
/// Gets the stored datetime value.
///
/// The precision of this value is truncated to the `time_unit` precision.
///
/// # Arguments
///
/// * `glean` - the Glean instance this metric belongs to.
/// * `storage_name` - the storage name to look into.
///
/// # Returns
///
/// The stored value or `None` if nothing stored.
pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<Datetime> {
match StorageManager.snapshot_metric(
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Datetime(d, tu)) => {
// The string version of the test function truncates using string
// parsing. Unfortunately `parse_from_str` errors with `NotEnough` if we
// try to truncate with `get_iso_time_string` and then parse it back
// in a `Datetime`. So we need to truncate manually.
let time = d.time();
match tu {
TimeUnit::Nanosecond => d.date().and_hms_nano_opt(
time.hour(),
time.minute(),
time.second(),
time.nanosecond(),
),
TimeUnit::Microsecond => d.date().and_hms_nano_opt(
time.hour(),
time.minute(),
time.second(),
time.nanosecond() / 1000,
),
TimeUnit::Millisecond => d.date().and_hms_nano_opt(
time.hour(),
time.minute(),
time.second(),
time.nanosecond() / 1000000,
),
TimeUnit::Second => {
d.date()
.and_hms_nano_opt(time.hour(), time.minute(), time.second(), 0)
}
TimeUnit::Minute => d.date().and_hms_nano_opt(time.hour(), time.minute(), 0, 0),
TimeUnit::Hour => d.date().and_hms_nano_opt(time.hour(), 0, 0, 0),
TimeUnit::Day => d.date().and_hms_nano_opt(0, 0, 0, 0),
}
}
_ => None,
}
}
/// **Test-only API (exported for FFI purposes).**
///
/// Gets the currently stored value as a String.
@ -155,6 +215,7 @@ impl DatetimeMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Datetime(d, tu)) => Some(get_iso_time_string(d, tu)),
_ => None,

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

@ -225,6 +225,7 @@ impl ExperimentMetric {
glean.storage(),
INTERNAL_STORAGE,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Experiment(e)) => Some(json!(e).to_string()),
_ => None,

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

@ -294,6 +294,7 @@ impl JweMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Jwe(b)) => Some(b),
_ => None,

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

@ -190,6 +190,7 @@ impl MemoryDistributionMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::MemoryDistribution(hist)) => Some(snapshot(&hist)),
_ => None,

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

@ -78,6 +78,7 @@ impl QuantityMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Quantity(i)) => Some(i),
_ => None,

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

@ -71,6 +71,7 @@ impl StringMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::String(s)) => Some(s),
_ => None,

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

@ -137,6 +137,7 @@ impl StringListMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::StringList(values)) => Some(values),
_ => None,

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

@ -108,7 +108,7 @@ impl TimespanMetric {
}
};
let duration = Duration::from_nanos(duration);
self.set_raw(glean, duration, false);
self.set_raw(glean, duration);
}
/// Aborts a previous [`set_start`](TimespanMetric::set_start) call. No
@ -132,8 +132,7 @@ impl TimespanMetric {
/// # Arguments
///
/// * `elapsed` - The elapsed time to record.
/// * `overwrite` - Whether or not to overwrite existing data.
pub fn set_raw(&self, glean: &Glean, elapsed: Duration, overwrite: bool) {
pub fn set_raw(&self, glean: &Glean, elapsed: Duration) {
if !self.should_record(glean) {
return;
}
@ -151,19 +150,15 @@ impl TimespanMetric {
let mut report_value_exists: bool = false;
glean.storage().record_with(glean, &self.meta, |old_value| {
if overwrite {
Metric::Timespan(elapsed, self.time_unit)
} else {
match old_value {
Some(old @ Metric::Timespan(..)) => {
// If some value already exists, report an error.
// We do this out of the storage since recording an
// error accesses the storage as well.
report_value_exists = true;
old
}
_ => Metric::Timespan(elapsed, self.time_unit),
match old_value {
Some(old @ Metric::Timespan(..)) => {
// If some value already exists, report an error.
// We do this out of the storage since recording an
// error accesses the storage as well.
report_value_exists = true;
old
}
_ => Metric::Timespan(elapsed, self.time_unit),
}
});
@ -188,6 +183,7 @@ impl TimespanMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Timespan(time, time_unit)) => Some(time_unit.duration_convert(time)),
_ => None,

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

@ -323,6 +323,7 @@ impl TimingDistributionMetric {
glean.storage(),
storage_name,
&self.meta.identifier(glean),
self.meta.lifetime,
) {
Some(Metric::TimingDistribution(hist)) => Some(snapshot(&hist)),
_ => None,

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

@ -103,6 +103,7 @@ impl UuidMetric {
glean.storage(),
storage_name,
&self.meta().identifier(glean),
self.meta.lifetime,
) {
Some(Metric::Uuid(uuid)) => Uuid::parse_str(&uuid).ok(),
_ => None,

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

@ -65,6 +65,7 @@ impl PingMaker {
glean.storage(),
INTERNAL_STORAGE,
&seq.meta().identifier(glean),
seq.meta().lifetime,
) {
Some(Metric::Counter(i)) => i,
_ => 0,

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

@ -129,6 +129,7 @@ impl StorageManager {
storage: &Database,
store_name: &str,
metric_id: &str,
metric_lifetime: Lifetime,
) -> Option<Metric> {
let mut snapshot: Option<Metric> = None;
@ -139,9 +140,7 @@ impl StorageManager {
}
};
storage.iter_store_from(Lifetime::Ping, &store_name, None, &mut snapshotter);
storage.iter_store_from(Lifetime::Application, &store_name, None, &mut snapshotter);
storage.iter_store_from(Lifetime::User, &store_name, None, &mut snapshotter);
storage.iter_store_from(metric_lifetime, &store_name, None, &mut snapshotter);
snapshot
}

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

@ -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::ErrorType;
/// A description for the
/// [`CustomDistributionMetric`](crate::metrics::CustomDistributionMetric) type.
///
@ -43,16 +45,20 @@ pub trait CustomDistribution {
/// **Exported for test purposes.**
///
/// Gets the currently stored histogram as a JSON String of the serialized value.
///
/// This doesn't clear the stored value.
/// Gets the number of recorded errors for the given 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`.
fn test_get_value_as_json_string<'a, S: Into<Option<&'a str>>>(
///
/// # Returns
///
/// The number of errors recorded.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> Option<String>;
) -> i32;
}

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

@ -4,36 +4,13 @@
#![allow(clippy::too_many_arguments)]
use crate::ErrorType;
/// A description for the [`DatetimeMetric`](crate::metrics::DatetimeMetric) type.
///
/// When changing this trait, make sure all the operations are
/// implemented in the related type in `../metrics/`.
pub trait Datetime {
/// Sets the metric to a date/time including the timezone offset.
///
/// # Arguments
///
/// * `year` - the year to set the metric to.
/// * `month` - the month to set the metric to (1-12).
/// * `day` - the day to set the metric to (1-based).
/// * `hour` - the hour to set the metric to.
/// * `minute` - the minute to set the metric to.
/// * `second` - the second to set the metric to.
/// * `nano` - the nanosecond fraction to the last whole second.
/// * `offset_seconds` - the timezone difference, in seconds, for the Eastern
/// Hemisphere. Negative seconds mean Western Hemisphere.
fn set_with_details(
&self,
year: i32,
month: u32,
day: u32,
hour: u32,
minute: u32,
second: u32,
nano: u32,
offset_seconds: i32,
);
/// Sets the metric to a date/time which including the timezone offset.
///
/// # Arguments
@ -62,18 +39,20 @@ pub trait Datetime {
/// **Exported for test purposes.**
///
/// Gets the currently stored value as a String.
///
/// The precision of this value is truncated to the `time_unit` precision.
///
/// This doesn't clear the stored value.
/// 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`.
fn test_get_value_as_string<'a, S: Into<Option<&'a str>>>(
///
/// # Returns
///
/// The number of errors reported.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> Option<String>;
) -> i32;
}

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

@ -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::ErrorType;
/// A description for the [`StringListMetric`](crate::metrics::StringListMetric) type.
///
/// When changing this trait, make sure all the operations are
@ -45,17 +47,20 @@ pub trait StringList {
/// **Exported for test purposes.**
///
/// Gets the currently-stored values as a JSON String of the format
/// ["string1", "string2", ...]
///
/// This doesn't clear the stored value.
/// Gets the number of recorded errors for the given 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`.
fn test_get_value_as_json_string<'a, S: Into<Option<&'a str>>>(
///
/// # Returns
///
/// The number of errors recorded.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> Option<String>;
) -> i32;
}

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

@ -4,6 +4,7 @@
use crate::metrics::DistributionData;
use crate::metrics::TimerId;
use crate::ErrorType;
/// A description for the [`TimingDistributionMetric`](crate::metrics::TimingDistributionMetric) type.
///
@ -13,23 +14,19 @@ pub trait TimingDistribution {
/// Starts tracking time for the provided metric.
///
/// This records an error if its already tracking time (i.e.
/// [`set_start`](TimingDistribution::set_start) was already called with no corresponding
/// [`set_stop_and_accumulate`](TimingDistribution::set_stop_and_accumulate)): in that case the
/// [`start`](TimingDistribution::start) was already called with no corresponding
/// [`stop_and_accumulate`](TimingDistribution::stop_and_accumulate)): in that case the
/// original start time will be preserved.
///
/// # Arguments
///
/// * `start_time` - Timestamp in nanoseconds.
///
/// # Returns
///
/// A unique [`TimerId`] for the new timer.
fn set_start(&mut self, start_time: u64);
fn start(&mut self) -> TimerId;
/// Stops tracking time for the provided metric and associated timer id.
///
/// Adds a count to the corresponding bucket in the timing distribution.
/// This will record an error if no [`set_start`](TimingDistribution::set_start) was
/// This will record an error if no [`start`](TimingDistribution::start) was
/// called.
///
/// # Arguments
@ -37,11 +34,10 @@ pub trait TimingDistribution {
/// * `id` - The [`TimerId`] to associate with this timing. This allows
/// for concurrent timing of events associated with different ids to the
/// same timespan metric.
/// * `stop_time` - Timestamp in nanoseconds.
fn set_stop_and_accumulate(&mut self, id: TimerId, stop_time: u64);
fn stop_and_accumulate(&mut self, id: TimerId);
/// Aborts a previous [`set_start`](TimingDistribution::set_start) call. No
/// error is recorded if no [`set_start`](TimingDistribution::set_start) was
/// Aborts a previous [`start`](TimingDistribution::start) call. No
/// error is recorded if no [`start`](TimingDistribution::start) was
/// called.
///
/// # Arguments
@ -51,34 +47,6 @@ pub trait TimingDistribution {
/// same timing distribution metric.
fn cancel(&mut self, id: TimerId);
/// Accumulates the provided signed samples in the metric.
///
/// This is required so that the platform-specific code can provide us with
/// 64 bit signed integers if no `u64` comparable type is available. This
/// will take care of filtering and reporting errors for any provided negative
/// sample.
///
/// Please note that this assumes that the provided samples are already in
/// the "unit" declared by the instance of the implementing metric type
/// (e.g. if the implementing class is a [TimingDistribution] and the
/// instance this method was called on is using second, then `samples` are
/// assumed to be in that unit).
///
/// # Arguments
///
/// * `samples` - The vector holding the samples to be recorded by the metric.
///
/// ## Notes
///
/// Discards any negative value in `samples` and report an
/// [`ErrorType::InvalidValue`](crate::ErrorType::InvalidValue) for each of
/// them.
///
/// Reports an
/// [`ErrorType::InvalidOverflow`](crate::ErrorType::InvalidOverflow) error
/// for samples that are longer than `MAX_SAMPLE_TIME`.
fn accumulate_samples_signed(&mut self, samples: Vec<i64>);
/// **Exported for test purposes.**
///
/// Gets the currently stored value as an integer.
@ -96,16 +64,20 @@ pub trait TimingDistribution {
/// **Exported for test purposes.**
///
/// Gets the currently-stored histogram as a JSON String of the serialized value.
///
/// This doesn't clear the stored value.
/// Gets the number of recorded errors for the given 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`.
fn test_get_value_as_json_string<'a, S: Into<Option<&'a str>>>(
///
/// # Returns
///
/// The number of errors recorded.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> Option<String>;
) -> i32;
}

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

@ -32,6 +32,8 @@ mod policy;
mod request;
mod result;
const WAIT_TIME_FOR_PING_PROCESSING: u64 = 1000; // in milliseconds
#[derive(Debug)]
struct RateLimiter {
/// The instant the current interval has started.
@ -50,7 +52,10 @@ enum RateLimiterState {
/// The RateLimiter has not reached the maximum count and is still incrementing.
Incrementing,
/// The RateLimiter has reached the maximum count for the current interval.
Throttled,
///
/// This variant contains the remaining time (in milliseconds)
/// until the rate limiter is not throttled anymore.
Throttled(u64),
}
impl RateLimiter {
@ -68,6 +73,10 @@ impl RateLimiter {
self.count = 0;
}
fn elapsed(&self) -> Duration {
self.started.unwrap().elapsed()
}
// The counter should reset if
//
// 1. It has never started;
@ -79,8 +88,7 @@ impl RateLimiter {
}
// Safe unwrap, we already stated that `self.started` is not `None` above.
let elapsed = self.started.unwrap().elapsed();
if elapsed > self.interval {
if self.elapsed() > self.interval {
return true;
}
@ -98,7 +106,14 @@ impl RateLimiter {
}
if self.count == self.max_count {
return RateLimiterState::Throttled;
// Note that `remining` can't be a negative number because we just called `reset`,
// which will check if it is and reset if so.
let remaining = self.interval.as_millis() - self.elapsed().as_millis();
return RateLimiterState::Throttled(
remaining
.try_into()
.unwrap_or(self.interval.as_secs() * 1000),
);
}
self.count += 1;
@ -119,7 +134,10 @@ pub enum PingUploadTask {
Upload(PingRequest),
/// A flag signaling that the pending pings directories are not done being processed,
/// thus the requester should wait and come back later.
Wait,
///
/// Contains the amount of time in milliseconds
/// the requester should wait before requesting a new task.
Wait(u64),
/// A flag signaling that requester doesn't need to request any more upload tasks at this moment.
///
/// There are three possibilities for this scenario:
@ -135,6 +153,18 @@ pub enum PingUploadTask {
Done,
}
impl PingUploadTask {
/// Whether the current task is an upload task.
pub fn is_upload(&self) -> bool {
matches!(self, PingUploadTask::Upload(_))
}
/// Whether the current task is wait task.
pub fn is_wait(&self) -> bool {
matches!(self, PingUploadTask::Wait(_))
}
}
/// Manages the pending pings queue and directory.
#[derive(Debug)]
pub struct PingUploadManager {
@ -474,12 +504,12 @@ impl PingUploadManager {
//
// We want to limit the amount of PingUploadTask::Wait returned in a row,
// in case we reach MAX_WAIT_ATTEMPTS we want to actually return PingUploadTask::Done.
let wait_or_done = || {
let wait_or_done = |time: u64| {
self.wait_attempt_count.fetch_add(1, Ordering::SeqCst);
if self.wait_attempt_count() > self.policy.max_wait_attempts() {
PingUploadTask::Done
} else {
PingUploadTask::Wait
PingUploadTask::Wait(time)
}
};
@ -487,7 +517,7 @@ impl PingUploadManager {
log::info!(
"Tried getting an upload task, but processing is ongoing. Will come back later."
);
return wait_or_done();
return wait_or_done(WAIT_TIME_FOR_PING_PROCESSING);
}
// This is a no-op in case there are no cached pings.
@ -510,11 +540,11 @@ impl PingUploadManager {
let mut rate_limiter = rate_limiter
.write()
.expect("Can't write to the rate limiter.");
if rate_limiter.get_state() == RateLimiterState::Throttled {
if let RateLimiterState::Throttled(remaining) = rate_limiter.get_state() {
log::info!(
"Tried getting an upload task, but we are throttled at the moment."
);
return wait_or_done();
return wait_or_done(remaining);
}
}
@ -554,13 +584,11 @@ impl PingUploadManager {
pub fn get_upload_task(&self, glean: &Glean, log_ping: bool) -> PingUploadTask {
let task = self.get_upload_task_internal(glean, log_ping);
if task != PingUploadTask::Wait && self.wait_attempt_count() > 0 {
if !task.is_wait() && self.wait_attempt_count() > 0 {
self.wait_attempt_count.store(0, Ordering::SeqCst);
}
if (task == PingUploadTask::Wait || task == PingUploadTask::Done)
&& self.recoverable_failure_count() > 0
{
if !task.is_upload() && self.recoverable_failure_count() > 0 {
self.recoverable_failure_count.store(0, Ordering::SeqCst);
}
@ -747,10 +775,8 @@ mod test {
// Try and get the next request.
// Verify request was returned
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
}
#[test]
@ -767,10 +793,8 @@ mod test {
// Verify a request is returned for each submitted ping
for _ in 0..n {
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
}
// Verify that after all requests are returned, none are left
@ -787,9 +811,8 @@ mod test {
let mut upload_manager = PingUploadManager::no_policy(dir.path());
// Add a rate limiter to the upload mangager with max of 10 pings every 3 seconds.
let secs_per_interval = 3;
let max_pings_per_interval = 10;
upload_manager.set_rate_limiter(secs_per_interval, 10);
upload_manager.set_rate_limiter(3, 10);
// Enqueue the max number of pings allowed per uploading window
for _ in 0..max_pings_per_interval {
@ -798,28 +821,24 @@ mod test {
// Verify a request is returned for each submitted ping
for _ in 0..max_pings_per_interval {
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
}
// Enqueue just one more ping
upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None);
// Verify that we are indeed told to wait because we are at capacity
assert_eq!(
PingUploadTask::Wait,
upload_manager.get_upload_task(&glean, false)
);
// Wait for the uploading window to reset
thread::sleep(Duration::from_secs(secs_per_interval));
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
PingUploadTask::Wait(time) => {
// Wait for the uploading window to reset
thread::sleep(Duration::from_millis(time));
}
_ => panic!("Expected upload manager to return a wait task!"),
};
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
}
#[test]
@ -895,10 +914,8 @@ mod test {
// Verify the requests were properly enqueued
for _ in 0..n {
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
}
// Verify that after all requests are returned, none are left
@ -1113,10 +1130,8 @@ mod test {
upload_manager.enqueue_ping(&glean, &doc_id, &path, "", None);
// Get a task once
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
// There should be no more queued tasks
assert_eq!(
@ -1168,10 +1183,8 @@ mod test {
// Verify all requests are returned when we try again.
for _ in 0..n {
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
}
}
@ -1498,10 +1511,8 @@ mod test {
// we should be throttled and thus get a PingUploadTask::Wait.
// Check that we are indeed allowed to get this response as many times as expected.
for _ in 0..max_wait_attempts {
assert_eq!(
upload_manager.get_upload_task(&glean, false),
PingUploadTask::Wait
);
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_wait());
}
// Check that after we get PingUploadTask::Wait the allowed number of times,
@ -1515,10 +1526,8 @@ mod test {
thread::sleep(Duration::from_secs(secs_per_interval));
// Check that we are allowed again to get pings.
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
let task = upload_manager.get_upload_task(&glean, false);
assert!(task.is_upload());
// And once we are done we don't need to wait anymore.
assert_eq!(
@ -1526,4 +1535,16 @@ mod test {
PingUploadTask::Done
);
}
#[test]
fn wait_task_contains_expected_wait_time_when_pending_pings_dir_not_processed_yet() {
let (glean, dir) = new_glean(None);
let upload_manager = PingUploadManager::new(dir.path(), "test");
match upload_manager.get_upload_task(&glean, false) {
PingUploadTask::Wait(time) => {
assert_eq!(time, WAIT_TIME_FOR_PING_PROCESSING);
}
_ => panic!("Expected upload manager to return a wait task!"),
};
}
}

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

@ -247,7 +247,7 @@ fn set_raw_time() {
);
let time = Duration::from_secs(1);
metric.set_raw(&glean, time, false);
metric.set_raw(&glean, time);
let time_in_ns = time.as_nanos() as u64;
assert_eq!(Some(time_in_ns), metric.test_get_value(&glean, "store1"));
@ -272,7 +272,7 @@ fn set_raw_time_does_nothing_when_timer_running() {
let time = Duration::from_secs(42);
metric.set_start(&glean, 0);
metric.set_raw(&glean, time, false);
metric.set_raw(&glean, time);
metric.set_stop(&glean, 60);
// We expect the start/stop value, not the raw value.

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

@ -1 +1 @@
{"files":{"Cargo.toml":"63c841dda738f53820850e1ab57ee31af77cd8fdec3a92cf2af40ac1ea297a96","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"fd9e0ca6907917ea6bec5de05e15dd21d20fae1cb7f3250467bb20231a8e1065","src/common_test.rs":"cf1ed5c1429e7f2ab5c52a47eb67c14bef455f1853fbdc9c2fd247d9fc7685b6","src/configuration.rs":"b8747397761a9cf6dc64150855b75fd8e48dfe9951ce69e25d646b3a6f46456f","src/core_metrics.rs":"e20697e04f707c34c3c7a0cc4e2ed93e638d3028f03eb75a93f53ae722243986","src/dispatcher/global.rs":"e4a86cf1f8df1728b414dbb3a8cc1a834ebaa0de6c2ffd1d7e9d55a714957193","src/dispatcher/mod.rs":"9bfa5abe6d5fdec06171068abefa419f1d83737f150b7dc191c58bd76fd69bc9","src/glean_metrics.rs":"a5e1ea9c4dccb81aec4aa584bd76cf47e916c66af4aff4a0ef5aa297ee2d9aa3","src/lib.rs":"f006de40c37f65ff5dbad752ae81a6c09fcecf3b8ef546483ed3d2730e24b76f","src/net/http_uploader.rs":"9e8c1837ca0d3f6ea165ec936ab054173c4fe95a958710176c33b4d4d1d98beb","src/net/mod.rs":"4058e8751c44b4785c9d4913789a7e940c0888598228f9378c45132293821fe2","src/pings.rs":"2dfccd84848e1933aa4f6a7a707c58ec794c8f73ef2d93ea4d4df71d4e6abc31","src/private/boolean.rs":"2ead8da55eca0c8738f3c07445b46b1efa706b3e8a1e60428347e9fcb1d1fd3f","src/private/counter.rs":"9b39665fa98e987b091a2a80f23be285bcf0c456ef99c2fcb0d5b42a6c566340","src/private/event.rs":"3ea9d35cab6f42abed853c9f933305d9c04d748e6d2a73a8e7a6a4b25e31f16a","src/private/labeled.rs":"4a9406ca11bc8d14dbc1a822781a3a8156cf99cfa2f548cb1d758d8c94570142","src/private/memory_distribution.rs":"e917a9dc2a26d7039cfcb76b290fb1333e7b38a8131989ce103ea2402c305079","src/private/mod.rs":"2ef82bea88db1565fc915ef3ecb8f3d2507a82e290312d164890f866c48e560e","src/private/ping.rs":"ec956102617989e72c79d61e959bfdd14ab1bb96cc12bd2745e75d5496eba2be","src/private/quantity.rs":"1e3e5677020c73a3f5ff01c1970ff8da8e30c800c5129e568b26260696477a06","src/private/recorded_experiment_data.rs":"66b2601902a2dc2b7a283717c21ce754de94fcca30d12e0398195c8ad49c90af","src/private/string.rs":"1004d0033cbf9191f6c2c8e9e738bf276e0580126c7297ec6ac5c6e6a3f84f58","src/private/timespan.rs":"ddc8d58c006caa9743d0b8386491e5c0715fa93d9ddfa57e3937448b1293836a","src/private/uuid.rs":"c045a6e57e790eea22e77554c7c5afab69e2187c487e503e6b931cff11df5493","src/system.rs":"ba7b3eac040abe4691d9d287562ddca6d7e92a6d6109c3f0c443b707a100d75a","src/test.rs":"0ff633ae8700cc7ee6e293587481bc378e120600e301aef44644e95a59d93141","tests/schema.rs":"b5acf42de034626f2b7e61fec9709a00370ce80ae3b2bab4db9fc79a20ea5f31"},"package":"b91b0b03e572ce70d06cf92ca899bdab8679e4ca07a2877928df028c848a1e9a"}
{"files":{"Cargo.toml":"55bb33b222226dc75b46dde412db46ac1b62aa87054406241828cf634017d8a2","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"fd9e0ca6907917ea6bec5de05e15dd21d20fae1cb7f3250467bb20231a8e1065","src/common_test.rs":"a7c7bfb1215b784ed41a4aebac476b7aeb23631ea5646e642b5673e9067ecd95","src/configuration.rs":"b8747397761a9cf6dc64150855b75fd8e48dfe9951ce69e25d646b3a6f46456f","src/core_metrics.rs":"e20697e04f707c34c3c7a0cc4e2ed93e638d3028f03eb75a93f53ae722243986","src/dispatcher/global.rs":"58591cc7ccf55196fd4d8b8a6a73ed7ac35b5e80534e00e02a012367f3f6d296","src/dispatcher/mod.rs":"e86a10f575364575604b00962755f86a1bcb43b280e00b9505f0e8e14995343d","src/glean_metrics.rs":"a5e1ea9c4dccb81aec4aa584bd76cf47e916c66af4aff4a0ef5aa297ee2d9aa3","src/lib.rs":"d5ad8f4b404a78b685adf8364f352db88d4fe96fd0f0b1a127bec9ff572edcbc","src/net/http_uploader.rs":"9e8c1837ca0d3f6ea165ec936ab054173c4fe95a958710176c33b4d4d1d98beb","src/net/mod.rs":"59db2f4dcfd0a2d77feb63f40cae2252da59fa8a87e10877fcb305eb91aa0645","src/pings.rs":"2dfccd84848e1933aa4f6a7a707c58ec794c8f73ef2d93ea4d4df71d4e6abc31","src/private/boolean.rs":"c6fc72573b5d19748418bcccc42d5f706d820d1e31e35a1aad1202cfc73e16a0","src/private/counter.rs":"104bc1a332306edf3597c627d94bc3024a4239e492e045200b5de0fcb2c0bafa","src/private/custom_distribution.rs":"7c9a56e1beac4bbd80d8acb0463daa240d6e80a424dd2de7c005c6ab355cab91","src/private/datetime.rs":"41ff623d1062ef5a85a8d19fae3d48c88ed8f9b59cf8881524e0f5898324a310","src/private/event.rs":"dfdc5a2aa33d7249fdf1bab162d34b1fd5df6ebe1ea77f617229ba35b393743f","src/private/labeled.rs":"ddc93655ac94e47ccc06a0e96ff8918a9d801c1345b817d5305d319d2da10eb2","src/private/memory_distribution.rs":"fe3c828294c3029af01247230c7aa717aa926db507649707113385ec8923eb23","src/private/mod.rs":"9a9031401285468b98bbafb3a71175bf9950c114aa229ae7634484eac7eb2b12","src/private/ping.rs":"45a78f437543a2c922fd94507446cad8b2ab9955356a87046c2db047d7ae4ae9","src/private/quantity.rs":"db922490b1be80c993bda6e604da8004831ecf20da160847aea49b927aca5bd5","src/private/recorded_experiment_data.rs":"66b2601902a2dc2b7a283717c21ce754de94fcca30d12e0398195c8ad49c90af","src/private/string.rs":"fede1ea64c346e8741af1e3fd8c9259b01bb3726f06bcd24d8b2b0b737dd6706","src/private/string_list.rs":"b4f339bc97a00c505ce56bca706f3d439728a3e349b20f952bddb243155e6d82","src/private/timespan.rs":"c4632c19bf4f357587ed4c1b6cf6d93e695c2f424f0afc4e2b33762b3d3dbbeb","src/private/timing_distribution.rs":"666ecff65d0cc61d21f5d043d982954b1bc284a359ea5cc9f6094d852f43b8e3","src/private/uuid.rs":"5997bb9da63384230e5422bb19e61e954901f44d79e39d6eca0c26444e05c2ca","src/system.rs":"ba7b3eac040abe4691d9d287562ddca6d7e92a6d6109c3f0c443b707a100d75a","src/test.rs":"9441d62ff4e45906908d7b6937c3744212e3cd1cbf214e0f84c14c4e836e830a","tests/common/mod.rs":"4837df2e771929cc077e6fb9a9239645e8e0f7bc6c9f409b71c4d147edf334fc","tests/init_fails.rs":"32614f46e49ec91cd33bc381246b44c22caa19f3eca5c2708589619cd1a99471","tests/never_init.rs":"1f33b8ce7ca3514b57b48cc16d98408974c85cf8aa7d13257ffc2ad878ebb295","tests/no_time_to_init.rs":"af55667ce9a7331d48e6a01815f8f184ae252dfc1aefcd8aeb478100a3726972","tests/schema.rs":"b5acf42de034626f2b7e61fec9709a00370ce80ae3b2bab4db9fc79a20ea5f31","tests/simple.rs":"1c1ec8babd3803a4e117d59c62215acf4bb73b1d9d34278c8882216a2686dbca"},"package":"120a2f092bcf0b8fa0ec864e1a063426638f7084671eddfd138b5571e1e2c6fd"}

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

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "glean"
version = "33.8.0"
version = "33.9.1"
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"
@ -21,11 +21,15 @@ readme = "README.md"
keywords = ["telemetry", "glean"]
license = "MPL-2.0"
repository = "https://github.com/mozilla/glean"
[dependencies.chrono]
version = "0.4.10"
features = ["serde"]
[dependencies.crossbeam-channel]
version = "0.4.3"
[dependencies.glean-core]
version = "33.8.0"
version = "33.9.1"
[dependencies.inherent]
version = "0.1.4"

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

@ -52,7 +52,6 @@ pub(crate) fn new_glean(
},
};
crate::shutdown();
crate::test_reset_glean(cfg, ClientInfoMetrics::unknown(), clear_stores);
dir
}

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

@ -59,13 +59,7 @@ pub fn flush_init() -> Result<(), DispatchError> {
guard().flush_init()
}
/// Shuts down the dispatch queue.
///
/// This will initiate a shutdown of the worker thread
/// and no new tasks will be processed after this.
pub fn shutdown() -> Result<(), DispatchError> {
guard().shutdown()?;
fn join_dispatcher_thread() -> Result<(), DispatchError> {
// After we issue the shutdown command, make sure to wait for the
// worker thread to join.
let mut lock = GLOBAL_DISPATCHER.write().unwrap();
@ -78,6 +72,25 @@ pub fn shutdown() -> Result<(), DispatchError> {
Ok(())
}
/// Kill the blocked dispatcher without processing the queue.
///
/// This will immediately shutdown the worker thread
/// and no other tasks will be processed.
/// This only has an effect when the queue is still blocked.
pub fn kill() -> Result<(), DispatchError> {
guard().kill()?;
join_dispatcher_thread()
}
/// Shuts down the dispatch queue.
///
/// This will initiate a shutdown of the worker thread
/// and no new tasks will be processed after this.
pub fn shutdown() -> Result<(), DispatchError> {
guard().shutdown()?;
join_dispatcher_thread()
}
/// TEST ONLY FUNCTION.
/// Resets the Glean state and triggers init again.
pub(crate) fn reset_dispatcher() {

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

@ -42,6 +42,14 @@ pub use global::*;
mod global;
/// Command received while blocked from further work.
enum Blocked {
/// Shutdown immediately without processing the queue.
Shutdown,
/// Unblock and continue with work as normal.
Continue,
}
/// The command a worker should execute.
enum Command {
/// A task is a user-defined function to run.
@ -100,7 +108,7 @@ struct DispatchGuard {
queue_preinit: Arc<AtomicBool>,
/// Used to unblock the worker thread initially.
block_sender: Sender<()>,
block_sender: Sender<Blocked>,
/// Sender for the preinit queue.
preinit_sender: Sender<Command>,
@ -146,6 +154,18 @@ impl DispatchGuard {
.expect("Failed to receive message on single-use channel");
}
fn kill(&mut self) -> Result<(), DispatchError> {
// We immediately stop queueing in the pre-init buffer.
let old_val = self.queue_preinit.swap(false, Ordering::SeqCst);
if !old_val {
return Err(DispatchError::AlreadyFlushed);
}
// Unblock the worker thread exactly once.
self.block_sender.send(Blocked::Shutdown)?;
Ok(())
}
fn flush_init(&mut self) -> Result<(), DispatchError> {
// We immediately stop queueing in the pre-init buffer.
let old_val = self.queue_preinit.swap(false, Ordering::SeqCst);
@ -154,7 +174,7 @@ impl DispatchGuard {
}
// Unblock the worker thread exactly once.
self.block_sender.send(())?;
self.block_sender.send(Blocked::Continue)?;
// Single-use channel to communicate with the worker thread.
let (swap_sender, swap_receiver) = bounded(0);
@ -193,7 +213,7 @@ impl Dispatcher {
///
/// [`flush_init`]: #method.flush_init
pub fn new(max_queue_size: usize) -> Self {
let (block_sender, block_receiver) = bounded(0);
let (block_sender, block_receiver) = bounded(1);
let (preinit_sender, preinit_receiver) = bounded(max_queue_size);
let (sender, mut unbounded_receiver) = unbounded();
@ -202,11 +222,20 @@ impl Dispatcher {
let worker = thread::Builder::new()
.name("glean.dispatcher".into())
.spawn(move || {
if block_receiver.recv().is_err() {
// The other side was disconnected.
// There's nothing the worker thread can do.
log::error!("The task producer was disconnected. Worker thread will exit.");
return;
match block_receiver.recv() {
Err(_) => {
// The other side was disconnected.
// There's nothing the worker thread can do.
log::error!("The task producer was disconnected. Worker thread will exit.");
return;
}
Ok(Blocked::Shutdown) => {
// The other side wants us to stop immediately
return;
}
Ok(Blocked::Continue) => {
// Queue is unblocked, processing continues as normal.
}
}
let mut receiver = preinit_receiver;

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

@ -49,7 +49,7 @@ pub use core_metrics::ClientInfoMetrics;
pub use glean_core::{
global_glean,
metrics::{DistributionData, MemoryUnit, RecordedEvent, TimeUnit},
setup_glean, CommonMetricData, Error, ErrorType, Glean, Lifetime, Result,
setup_glean, CommonMetricData, Error, ErrorType, Glean, HistogramType, Lifetime, Result,
};
use private::RecordedExperimentData;
@ -92,6 +92,9 @@ 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();
/// Keep track of pings registered before Glean is initialized.
static PRE_INIT_PING_REGISTRATION: OnceCell<Mutex<Vec<private::PingType>>> = OnceCell::new();
/// A global singleton storing additional state for Glean.
///
/// Requires a Mutex, because in tests we can actual reset this.
@ -251,8 +254,16 @@ pub fn initialize(cfg: Configuration, client_info: ClientInfoMetrics) {
glean.register_ping_type(&glean_metrics::pings::metrics.ping_type);
glean.register_ping_type(&glean_metrics::pings::events.ping_type);
// TODO: perform registration of pings that were attempted to be
// registered before init. See bug 1673850.
// Perform registration of pings that were attempted to be
// registered before init.
if let Some(tags) = PRE_INIT_PING_REGISTRATION.get() {
let lock = tags.try_lock();
if let Ok(pings) = lock {
for ping in &*pings {
glean.register_ping_type(&ping.ping_type);
}
}
}
// If this is the first time ever the Glean SDK runs, make sure to set
// some initial core metrics in case we need to generate early pings.
@ -310,8 +321,12 @@ pub fn initialize(cfg: Configuration, client_info: ClientInfoMetrics) {
/// This currently only attempts to shut down the
/// internal dispatcher.
pub fn shutdown() {
if !was_initialize_called() {
if global_glean().is_none() {
log::warn!("Shutdown called before Glean is initialized");
if let Err(e) = dispatcher::kill() {
log::error!("Can't kill dispatcher thread: {:?}", e);
}
return;
}
@ -320,6 +335,17 @@ pub fn shutdown() {
}
}
/// Block on the dispatcher emptying.
///
/// This will panic if called before Glean is initialized.
fn block_on_dispatcher() {
assert!(
was_initialize_called(),
"initialize was never called. Can't block on the dispatcher queue."
);
dispatcher::block_on_queue()
}
/// Checks if [`initialize`] was ever called.
///
/// # Returns
@ -411,6 +437,14 @@ pub fn register_ping_type(ping: &private::PingType) {
glean.register_ping_type(&ping.ping_type);
})
})
} else {
// We need to keep track of pings, so they get re-registered after a reset or
// if ping registration is attempted before Glean initializes.
// This state is kept across Glean resets, which should only ever happen in test mode.
// It's a set and keeping them around forever should not have much of an impact.
let m = PRE_INIT_PING_REGISTRATION.get_or_init(Default::default);
let mut lock = m.lock().unwrap();
lock.push(ping.clone());
}
}
@ -510,7 +544,7 @@ pub fn set_experiment_inactive(experiment_id: String) {
/// Checks if an experiment is currently active.
#[allow(dead_code)]
pub(crate) fn test_is_experiment_active(experiment_id: String) -> bool {
dispatcher::block_on_queue();
block_on_dispatcher();
with_glean(|glean| glean.test_is_experiment_active(experiment_id.to_owned()))
}
@ -519,7 +553,7 @@ pub(crate) fn test_is_experiment_active(experiment_id: String) -> bool {
/// the id isn't found.
#[allow(dead_code)]
pub(crate) fn test_get_experiment_data(experiment_id: String) -> RecordedExperimentData {
dispatcher::block_on_queue();
block_on_dispatcher();
with_glean(|glean| {
let json_data = glean
.test_get_experiment_data_as_json(experiment_id.to_owned())

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

@ -22,9 +22,6 @@ pub use http_uploader::*;
mod http_uploader;
/// The duration the uploader thread should sleep, when told to by glean-core.
const THROTTLE_BACKOFF_TIME: Duration = Duration::from_secs(60);
/// A description of a component used to upload pings.
pub trait PingUploader: std::fmt::Debug + Send + Sync {
/// Uploads a ping to a server.
@ -100,8 +97,8 @@ impl UploadManager {
// Process the upload response.
with_glean(|glean| glean.process_ping_upload_response(&doc_id, result));
}
PingUploadTask::Wait => {
thread::sleep(THROTTLE_BACKOFF_TIME);
PingUploadTask::Wait(time) => {
thread::sleep(Duration::from_millis(time));
}
PingUploadTask::Done => {
// Nothing to do here, break out of the loop and clear the

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

@ -31,28 +31,13 @@ impl BooleanMetric {
#[inherent(pub)]
impl glean_core::traits::Boolean for BooleanMetric {
/// Sets to the specified boolean value.
///
/// # Arguments
///
/// * `value` - the value to set.
fn set(&self, value: bool) {
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 as a boolean.
///
/// 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<bool> {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
let queried_ping_name = match ping_name.into() {
Some(name) => name,

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

@ -32,32 +32,13 @@ impl CounterMetric {
#[inherent(pub)]
impl glean_core::traits::Counter for CounterMetric {
/// Increases the counter by `amount`.
///
/// # Arguments
///
/// * `amount` - The amount to increase by. Should be positive.
///
/// ## Notes
///
/// Logs an error if the `amount` is 0 or negative.
fn add(&self, amount: i32) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || crate::with_glean(|glean| metric.add(glean, amount)));
}
/// **Exported for test purposes.**
///
/// Gets the currently stored value as an integer.
///
/// 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<i32> {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
let queried_ping_name = ping_name
.into()
@ -66,25 +47,12 @@ impl glean_core::traits::Counter for CounterMetric {
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 {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())

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

@ -0,0 +1,81 @@
// 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::{DistributionData, MetricType};
use glean_core::{CommonMetricData, ErrorType, HistogramType};
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 custom distribution 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 CustomDistributionMetric(pub(crate) Arc<glean_core::metrics::CustomDistributionMetric>);
impl CustomDistributionMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(
meta: CommonMetricData,
range_min: u64,
range_max: u64,
bucket_count: u64,
histogram_type: HistogramType,
) -> Self {
Self(Arc::new(
glean_core::metrics::CustomDistributionMetric::new(
meta,
range_min,
range_max,
bucket_count,
histogram_type,
),
))
}
}
#[inherent(pub)]
impl glean_core::traits::CustomDistribution for CustomDistributionMetric {
fn accumulate_samples_signed(&self, samples: Vec<i64>) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || {
crate::with_glean(|glean| metric.accumulate_samples_signed(glean, samples))
});
}
fn test_get_value<'a, S: Into<Option<&'a str>>>(
&self,
ping_name: S,
) -> Option<DistributionData> {
crate::block_on_dispatcher();
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))
}
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)
})
}
}

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

@ -0,0 +1,103 @@
// 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;
pub use glean_core::metrics::{Datetime, TimeUnit};
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 Datetime 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 DatetimeMetric(pub(crate) Arc<glean_core::metrics::DatetimeMetric>);
impl DatetimeMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData, time_unit: TimeUnit) -> Self {
Self(Arc::new(glean_core::metrics::DatetimeMetric::new(
meta, time_unit,
)))
}
}
#[inherent(pub)]
impl glean_core::traits::Datetime for DatetimeMetric {
fn set(&self, value: Option<Datetime>) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || crate::with_glean(|glean| metric.set(glean, value)));
}
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<Datetime> {
crate::block_on_dispatcher();
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))
}
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)
})
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::common_test::{lock_test, new_glean};
use crate::CommonMetricData;
use chrono::prelude::*;
#[test]
fn datetime_convenient_api() {
let _lock = lock_test();
let _t = new_glean(None, true);
let metric: DatetimeMetric = DatetimeMetric::new(
CommonMetricData {
name: "datetime".into(),
category: "test".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
},
TimeUnit::Day,
);
// Record a date: it will get truncated to Day resolution.
let sample_date = FixedOffset::east(0).ymd(2018, 2, 25).and_hms(11, 5, 0);
metric.set(Some(sample_date));
// Check that the value has the correct resolution.
let date = metric.test_get_value(None).unwrap();
assert_eq!(date, FixedOffset::east(0).ymd(2018, 2, 25).and_hms(0, 0, 0));
// Ensure no error was recorded.
assert_eq!(
metric.test_get_num_recorded_errors(ErrorType::InvalidValue, None),
0
)
}
}

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

@ -63,7 +63,7 @@ impl<K: traits::ExtraKeys> traits::Event for EventMetric<K> {
&self,
ping_name: S,
) -> Option<Vec<RecordedEvent>> {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
let queried_ping_name = ping_name
.into()
@ -77,7 +77,7 @@ impl<K: traits::ExtraKeys> traits::Event for EventMetric<K> {
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(

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

@ -8,8 +8,6 @@ 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.
@ -124,41 +122,17 @@ 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::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(

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

@ -43,7 +43,7 @@ impl glean_core::traits::MemoryDistribution for MemoryDistributionMetric {
&self,
ping_name: S,
) -> Option<DistributionData> {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
let queried_ping_name = ping_name
.into()
@ -57,7 +57,7 @@ impl glean_core::traits::MemoryDistribution for MemoryDistributionMetric {
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())

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

@ -6,6 +6,8 @@
mod boolean;
mod counter;
mod custom_distribution;
mod datetime;
mod event;
mod labeled;
mod memory_distribution;
@ -13,12 +15,16 @@ mod ping;
mod quantity;
mod recorded_experiment_data;
mod string;
mod string_list;
mod timespan;
mod timing_distribution;
mod uuid;
pub use self::uuid::UuidMetric;
pub use boolean::BooleanMetric;
pub use counter::CounterMetric;
pub use custom_distribution::CustomDistributionMetric;
pub use datetime::{Datetime, DatetimeMetric};
pub use event::EventMetric;
pub use labeled::{AllowLabeled, LabeledMetric};
pub use memory_distribution::MemoryDistributionMetric;
@ -26,4 +32,6 @@ pub use ping::PingType;
pub use quantity::QuantityMetric;
pub use recorded_experiment_data::RecordedExperimentData;
pub use string::StringMetric;
pub use string_list::StringListMetric;
pub use timespan::TimespanMetric;
pub use timing_distribution::TimingDistributionMetric;

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

@ -42,25 +42,6 @@ impl PingType {
#[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.
/// Data with lifetime `ping` will then be reset.
///
/// 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.
///
/// # Arguments
///
/// * `reason` - The reason the ping is being submitted.
/// Must be one of the configured `reason_codes`.
fn submit(&self, reason: Option<&str>) {
crate::submit_ping(self, reason)
}

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

@ -32,28 +32,13 @@ impl QuantityMetric {
#[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();
crate::block_on_dispatcher();
let queried_ping_name = ping_name
.into()
@ -62,26 +47,13 @@ impl glean_core::traits::Quantity for QuantityMetric {
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::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())

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

@ -32,36 +32,17 @@ impl StringMetric {
#[inherent(pub)]
impl glean_core::traits::String for StringMetric {
/// Sets to the specified value.
///
/// # 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) {
let metric = Arc::clone(&self.0);
let new_value = value.into();
dispatcher::launch(move || crate::with_glean(|glean| metric.set(glean, new_value)));
}
/// **Exported for test purposes.**
///
/// Gets the currently stored value as a string.
///
/// 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<std::string::String> {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
let queried_ping_name = ping_name
.into()
@ -70,25 +51,12 @@ impl glean_core::traits::String for StringMetric {
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 {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())

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

@ -0,0 +1,108 @@
// 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 string list 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 StringListMetric(pub(crate) Arc<glean_core::metrics::StringListMetric>);
impl StringListMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData) -> Self {
Self(Arc::new(glean_core::metrics::StringListMetric::new(meta)))
}
}
#[inherent(pub)]
impl glean_core::traits::StringList for StringListMetric {
fn add<S: Into<String>>(&self, value: S) {
let metric = Arc::clone(&self.0);
let new_value = value.into();
dispatcher::launch(move || crate::with_glean(|glean| metric.add(glean, new_value)));
}
fn set(&self, value: Vec<String>) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || crate::with_glean(|glean| metric.set(glean, value)));
}
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<Vec<String>> {
crate::block_on_dispatcher();
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))
}
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)
})
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::common_test::{lock_test, new_glean};
use crate::{CommonMetricData, ErrorType};
#[test]
fn string_list_metric_docs() {
let _lock = lock_test();
let _t = new_glean(None, true);
let engine_metric: StringListMetric = StringListMetric::new(CommonMetricData {
name: "event".into(),
category: "test".into(),
send_in_pings: vec!["test1".into()],
..Default::default()
});
let engines: Vec<String> = vec!["Google".to_string(), "DuckDuckGo".to_string()];
// Add them one at a time
engines.iter().for_each(|x| engine_metric.add(x));
// Set them in one go
engine_metric.set(engines);
assert!(engine_metric.test_get_value(None).is_some());
assert_eq!(
vec!["Google".to_string(), "DuckDuckGo".to_string()],
engine_metric.test_get_value(None).unwrap()
);
assert_eq!(
0,
engine_metric.test_get_num_recorded_errors(ErrorType::InvalidValue, None)
);
}
}

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

@ -34,14 +34,6 @@ impl TimespanMetric {
#[inherent(pub)]
impl glean_core::traits::Timespan for TimespanMetric {
/// Starts tracking time for the provided metric.
///
/// This uses an internal monotonic timer.
///
/// This records an error if it's already tracking time (i.e.
/// [`start`](TimespanMetric::start) was already called with no
/// corresponding [`stop`](TimespanMetric::stop)): in that case the original
/// start time will be preserved.
fn start(&self) {
let start_time = time::precise_time_ns();
@ -56,9 +48,6 @@ impl glean_core::traits::Timespan for TimespanMetric {
});
}
/// Stops tracking time for the provided metric. Sets the metric to the elapsed time.
///
/// This will record an error if no [`start`](TimespanMetric::start) was called.
fn stop(&self) {
let stop_time = time::precise_time_ns();
@ -73,8 +62,6 @@ impl glean_core::traits::Timespan for TimespanMetric {
});
}
/// Aborts a previous [`start`](TimespanMetric::start) call. No error is
/// recorded if no [`start`](TimespanMetric::start) was called.
fn cancel(&self) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || {
@ -84,18 +71,9 @@ impl glean_core::traits::Timespan for TimespanMetric {
lock.cancel()
});
}
/// **Exported for test purposes.**
///
/// Gets the currently stored value as an integer.
///
/// 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<u64> {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
crate::with_glean(|glean| {
// Note: The order of operations is important here to avoid potential deadlocks because
@ -116,25 +94,12 @@ impl glean_core::traits::Timespan for TimespanMetric {
})
}
/// **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::block_on_dispatcher();
let metric = self
.0

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

@ -0,0 +1,93 @@
// 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, RwLock};
use glean_core::metrics::{DistributionData, MetricType, TimeUnit, TimerId};
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 timing distribution 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 TimingDistributionMetric(
pub(crate) Arc<RwLock<glean_core::metrics::TimingDistributionMetric>>,
);
impl TimingDistributionMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData, time_unit: TimeUnit) -> Self {
Self(Arc::new(RwLock::new(
glean_core::metrics::TimingDistributionMetric::new(meta, time_unit),
)))
}
}
#[inherent(pub)]
impl glean_core::traits::TimingDistribution for TimingDistributionMetric {
fn start(&mut self) -> TimerId {
let start_time = time::precise_time_ns();
self.0.write().unwrap().set_start(start_time)
}
fn stop_and_accumulate(&mut self, id: TimerId) {
let stop_time = time::precise_time_ns();
let metric = Arc::clone(&self.0);
dispatcher::launch(move || {
crate::with_glean(|glean| {
metric
.write()
.unwrap()
.set_stop_and_accumulate(glean, id, stop_time)
})
});
}
fn cancel(&mut self, id: TimerId) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || metric.write().unwrap().cancel(id));
}
fn test_get_value<'a, S: Into<Option<&'a str>>>(
&self,
ping_name: S,
) -> Option<DistributionData> {
crate::block_on_dispatcher();
let inner = self.0.read().unwrap();
let queried_ping_name = ping_name
.into()
.unwrap_or_else(|| &inner.meta().send_in_pings[0]);
crate::with_glean(|glean| inner.test_get_value(glean, queried_ping_name))
}
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(
&glean,
self.0.read().unwrap().meta(),
error,
ping_name.into(),
)
.unwrap_or(0)
})
}
}

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

@ -32,17 +32,11 @@ impl UuidMetric {
#[inherent(pub)]
impl glean_core::traits::Uuid for UuidMetric {
/// Sets to the specified value.
///
/// # Arguments
///
/// * `value` - The [`Uuid`](uuid::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();
@ -50,18 +44,8 @@ impl glean_core::traits::Uuid for UuidMetric {
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();
crate::block_on_dispatcher();
let queried_ping_name = ping_name
.into()
@ -70,25 +54,12 @@ impl glean_core::traits::Uuid for UuidMetric {
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 {
dispatcher::block_on_queue();
crate::block_on_dispatcher();
crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())

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

@ -2,6 +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::private::PingType;
use crate::private::{BooleanMetric, CounterMetric};
use std::path::PathBuf;
@ -48,7 +49,7 @@ fn send_a_ping() {
};
let _t = new_glean(Some(cfg), true);
crate::dispatcher::block_on_queue();
crate::block_on_dispatcher();
// Define a new ping and submit it.
const PING_NAME: &str = "test-ping";
@ -65,7 +66,7 @@ fn disabling_upload_disables_metrics_recording() {
let _lock = lock_test();
let _t = new_glean(None, true);
crate::dispatcher::block_on_queue();
crate::block_on_dispatcher();
let metric = BooleanMetric::new(CommonMetricData {
name: "bool_metric".into(),
@ -159,7 +160,7 @@ fn test_experiments_recording_before_glean_inits() {
ClientInfoMetrics::unknown(),
false,
);
crate::dispatcher::block_on_queue();
crate::block_on_dispatcher();
assert!(test_is_experiment_active(
"experiment_set_preinit".to_string()
@ -269,7 +270,7 @@ fn initializing_twice_is_a_noop() {
true,
);
dispatcher::block_on_queue();
crate::block_on_dispatcher();
test_reset_glean(
Configuration {
@ -400,7 +401,7 @@ fn setting_debug_view_tag_before_initialization_should_not_crash() {
};
let _t = new_glean(Some(cfg), true);
crate::dispatcher::block_on_queue();
crate::block_on_dispatcher();
// Submit a baseline ping.
submit_ping_by_name("baseline", Some("background"));
@ -459,7 +460,7 @@ fn setting_source_tags_before_initialization_should_not_crash() {
};
let _t = new_glean(Some(cfg), true);
crate::dispatcher::block_on_queue();
crate::block_on_dispatcher();
// Submit a baseline ping.
submit_ping_by_name("baseline", Some("background"));
@ -481,3 +482,59 @@ fn setting_source_tags_before_initialization_should_not_crash() {
fn flipping_upload_enabled_respects_order_of_events() {
todo!()
}
#[test]
fn registering_pings_before_init_must_work() {
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::<String>(1);
#[derive(Debug)]
pub struct FakeUploader {
sender: crossbeam_channel::Sender<String>,
};
impl net::PingUploader for FakeUploader {
fn upload(
&self,
url: String,
_body: Vec<u8>,
_headers: Vec<(String, String)>,
) -> net::UploadResult {
self.sender.send(url).unwrap();
net::UploadResult::HttpStatus(200)
}
}
// Create a custom ping and attempt its registration.
let sample_ping = PingType::new("pre-register", true, true, vec![]);
// 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::block_on_dispatcher();
// Submit a baseline ping.
sample_ping.submit(None);
// Wait for the ping to arrive.
let url = r.recv().unwrap();
assert!(url.contains("pre-register"));
}

50
third_party/rust/glean/tests/common/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,50 @@
// 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/.
// #[allow(dead_code)] is required on this module as a workaround for
// https://github.com/rust-lang/rust/issues/46379
#![allow(dead_code)]
use std::{panic, process};
use glean::{ClientInfoMetrics, Configuration};
/// Initialize the env logger for a test environment.
///
/// When testing we want all logs to go to stdout/stderr by default.
pub fn enable_test_logging() {
let _ = env_logger::builder().is_test(true).try_init();
}
/// Install a panic handler that exits the whole process when a panic occurs.
///
/// This causes the process to exit even if a thread panics.
/// This is similar to the `panic=abort` configuration, but works in the default configuration
/// (as used by `cargo test`).
fn install_panic_handler() {
let orig_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
// invoke the default handler and exit the process
orig_hook(panic_info);
process::exit(1);
}));
}
/// Create a new instance of Glean.
pub fn initialize(cfg: Configuration) {
// Ensure panics in threads, such as the init thread or the dispatcher, cause the process to
// exit.
//
// Otherwise in case of a panic in a thread the integration test will just hang.
// CI will terminate it after a timeout, but why stick around if we know nothing is happening?
install_panic_handler();
// Use some default values to make our life easier a bit.
let client_info = ClientInfoMetrics {
app_build: "1.0.0".to_string(),
app_display_version: "1.0.0".to_string(),
};
glean::initialize(cfg, client_info);
}

84
third_party/rust/glean/tests/init_fails.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,84 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! This integration test should model how the RLB is used when embedded in another Rust application
//! (e.g. FOG/Firefox Desktop).
//!
//! We write a single test scenario per file to avoid any state keeping across runs
//! (different files run as different processes).
mod common;
use std::{thread, time::Duration};
use glean::Configuration;
/// Some user metrics.
mod metrics {
use glean::private::*;
use glean::{Lifetime, TimeUnit};
use glean_core::CommonMetricData;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static initialization: Lazy<TimespanMetric> = Lazy::new(|| {
TimespanMetric::new(
CommonMetricData {
name: "initialization".into(),
category: "sample".into(),
send_in_pings: vec!["validation".into()],
lifetime: Lifetime::Ping,
disabled: false,
..Default::default()
},
TimeUnit::Nanosecond,
)
});
}
mod pings {
use glean::private::PingType;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static validation: Lazy<PingType> =
Lazy::new(|| glean::private::PingType::new("validation", true, true, vec![]));
}
/// Test scenario: Glean initialization fails.
///
/// App tries to initialize Glean, but that somehow fails.
#[test]
fn init_fails() {
common::enable_test_logging();
metrics::initialization.start();
// Create a custom configuration to use a validating uploader.
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = Configuration {
data_path: tmpname,
application_id: "".into(), // An empty application ID is invalid.
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: Some("testing".into()),
server_endpoint: Some("invalid-test-host".into()),
uploader: None,
};
common::initialize(cfg);
metrics::initialization.stop();
pings::validation.submit(None);
// We don't test for data here, as that would block on the dispatcher.
// Give it a short amount of time to actually finish initialization.
thread::sleep(Duration::from_millis(500));
glean::shutdown();
}

66
third_party/rust/glean/tests/never_init.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,66 @@
// 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/.
//! This integration test should model how the RLB is used when embedded in another Rust application
//! (e.g. FOG/Firefox Desktop).
//!
//! We write a single test scenario per file to avoid any state keeping across runs
//! (different files run as different processes).
mod common;
/// Some user metrics.
mod metrics {
use glean::private::*;
use glean::{Lifetime, TimeUnit};
use glean_core::CommonMetricData;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static initialization: Lazy<TimespanMetric> = Lazy::new(|| {
TimespanMetric::new(
CommonMetricData {
name: "initialization".into(),
category: "sample".into(),
send_in_pings: vec!["validation".into()],
lifetime: Lifetime::Ping,
disabled: false,
..Default::default()
},
TimeUnit::Nanosecond,
)
});
}
mod pings {
use glean::private::PingType;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static validation: Lazy<PingType> =
Lazy::new(|| glean::private::PingType::new("validation", true, true, vec![]));
}
/// Test scenario: Glean is never initialized.
///
/// Glean is never initialized.
/// Some data is recorded early on.
/// And later the whole process is shutdown.
#[test]
fn never_initialize() {
common::enable_test_logging();
metrics::initialization.start();
// NOT calling `initialize` here.
// In apps this might happen for several reasons:
// 1. Process doesn't run long enough for Glean to be initialized.
// 2. Getting some early data used for initialize fails
pings::validation.submit(None);
// We can't test for data either, as that would panic because init was never called.
glean::shutdown();
}

81
third_party/rust/glean/tests/no_time_to_init.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,81 @@
// 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/.
//! This integration test should model how the RLB is used when embedded in another Rust application
//! (e.g. FOG/Firefox Desktop).
//!
//! We write a single test scenario per file to avoid any state keeping across runs
//! (different files run as different processes).
mod common;
use glean::Configuration;
/// Some user metrics.
mod metrics {
use glean::private::*;
use glean::{Lifetime, TimeUnit};
use glean_core::CommonMetricData;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static initialization: Lazy<TimespanMetric> = Lazy::new(|| {
TimespanMetric::new(
CommonMetricData {
name: "initialization".into(),
category: "sample".into(),
send_in_pings: vec!["validation".into()],
lifetime: Lifetime::Ping,
disabled: false,
..Default::default()
},
TimeUnit::Nanosecond,
)
});
}
mod pings {
use glean::private::PingType;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static validation: Lazy<PingType> =
Lazy::new(|| glean::private::PingType::new("validation", true, true, vec![]));
}
/// Test scenario: Glean initialization fails.
///
/// The app tries to initializate Glean, but that somehow fails.
#[test]
fn init_fails() {
common::enable_test_logging();
metrics::initialization.start();
// Create a custom configuration to use a validating uploader.
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = Configuration {
data_path: tmpname,
application_id: "firefox-desktop".into(), // An empty application ID is invalid.
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
channel: Some("testing".into()),
server_endpoint: Some("invalid-test-host".into()),
uploader: None,
};
common::initialize(cfg);
metrics::initialization.stop();
pings::validation.submit(None);
// We don't test for data here, as that would block on the dispatcher.
// Shut it down immediately; this might not be enough time to initialize.
glean::shutdown();
}

84
third_party/rust/glean/tests/simple.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,84 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! This integration test should model how the RLB is used when embedded in another Rust application
//! (e.g. FOG/Firefox Desktop).
//!
//! We write a single test scenario per file to avoid any state keeping across runs
//! (different files run as different processes).
mod common;
use glean::Configuration;
/// Some user metrics.
mod metrics {
use glean::private::*;
use glean::{Lifetime, TimeUnit};
use glean_core::CommonMetricData;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static initialization: Lazy<TimespanMetric> = Lazy::new(|| {
TimespanMetric::new(
CommonMetricData {
name: "initialization".into(),
category: "sample".into(),
send_in_pings: vec!["validation".into()],
lifetime: Lifetime::Ping,
disabled: false,
..Default::default()
},
TimeUnit::Nanosecond,
)
});
}
mod pings {
use glean::private::PingType;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static validation: Lazy<PingType> =
Lazy::new(|| glean::private::PingType::new("validation", true, true, vec![]));
}
/// Test scenario: A clean run
///
/// The app is initialized, in turn Glean gets initialized without problems.
/// Some data is recorded (before and after initialization).
/// And later the whole process is shutdown.
#[test]
fn simple_lifecycle() {
common::enable_test_logging();
metrics::initialization.start();
// Create a custom configuration to use a validating uploader.
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
let cfg = Configuration {
data_path: tmpname,
application_id: "firefox-desktop".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,
};
common::initialize(cfg);
metrics::initialization.stop();
// This would never be called outside of tests,
// but it's the only way we can really test it's working right now.
assert!(metrics::initialization.test_get_value(None).is_some());
pings::validation.submit(None);
assert!(metrics::initialization.test_get_value(None).is_none());
glean::shutdown();
}

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

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

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

@ -8,8 +8,8 @@ publish = false
[dependencies]
bincode = "1.0"
chrono = "0.4.10"
glean = "33.8.0"
glean-core = { version = "33.8.0", features = ["rkv-safe-mode"] }
glean = "33.9.1"
glean-core = { version = "33.9.1", features = ["rkv-safe-mode"] }
inherent = "0.1.4"
log = "0.4"
nsstring = { path = "../../../../xpcom/rust/nsstring", optional = true }