Bug 1623300 - Replace fogotype with the actual FOG crate now. r=chutten

This also upgrades the vendored Glean version, which thanks to our
upstream work doesn't change anything else (except one small
Mozilla-developed dependency)

It's still feature-gated to nightly.
In C++ there's now a `MOZ_GLEAN` define.
For Rust it's behind the `glean` feature (enabled on nightly only).
The `fog` crate is empty, so no Glean is actually instantiated.

Differential Revision: https://phabricator.services.mozilla.com/D68539

--HG--
rename : third_party/rust/glean-preview/src/metrics/mod.rs => toolkit/components/glean/src/lib.rs
extra : moz-landing-system : lando
This commit is contained in:
Jan-Erik Rediger 2020-03-31 08:24:40 +00:00
Родитель afdcacc413
Коммит 311c2d9ea7
63 изменённых файлов: 1934 добавлений и 1740 удалений

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

@ -1240,12 +1240,10 @@ dependencies = [
[[package]]
name = "ffi-support"
version = "0.3.5"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efee06d8ac3e85a6e9759a0ed2682235a70832ebe10953849b92cdced8688660"
checksum = "087be066eb6e85d7150f0c5400018a32802f99d688b2d3868c526f7bbfe17960"
dependencies = [
"failure",
"failure_derive",
"lazy_static",
"log",
]
@ -1366,8 +1364,7 @@ checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
name = "fog"
version = "0.1.0"
dependencies = [
"cstr",
"glean-preview",
"glean-core",
"log",
"nserror",
"nsstring",
@ -1740,9 +1737,9 @@ dependencies = [
[[package]]
name = "glean-core"
version = "24.0.0"
version = "25.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40afd759281422c5a9d17c5a2cfd6b703fbc6fea0ce1d82d09c4c53a4d98f4cf"
checksum = "a893aa65acba615064c53e2ab091a54227a0253852b8e4a2c813c8338f6095a7"
dependencies = [
"bincode",
"chrono",
@ -1757,17 +1754,6 @@ dependencies = [
"uuid",
]
[[package]]
name = "glean-preview"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "182218f42395f369a1a5372d334699458a606aa557dd2e23998ba25704964e2c"
dependencies = [
"glean-core",
"lazy_static",
"once_cell",
]
[[package]]
name = "glob"
version = "0.3.0"

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

@ -1 +1 @@
{"files":{"Cargo.toml":"f522bcd6e15aa3817fbc327ac33ae663ba494f1d32b9d91a5a35b773f0a0edbb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"63e747d86bdeb67638f26b4b75107f129c5f12de432ae83ccdb1ccbe28debf30","README.md":"67780fbfcaf2cd01e3b7f5c7d1ef8b9e385b7cd4435358954aec24a85755ced2","src/error.rs":"bee4653bcdfac1c903c41c6ae647fbeeb8ce45818886c69cead324156e77a9c5","src/ffistr.rs":"44460d6b0879a76274af8508b9cdbab5b8170f646b05a9415a2e5e51bd2f040b","src/handle_map.rs":"a2f25411c953d07daba18a8a39e5731b01d7b07c78414824b3b66ed13f8f3c2f","src/into_ffi.rs":"05c4a1c9f3aebb4570ac6578f946ba9d9fc90c54abb76f30704868b277df2f9d","src/lib.rs":"6c111cdd9fa2251a9013c19c89930e46bc7357d3ea2f76040cdeb6223d9583e7","src/macros.rs":"1f05d94853bbf5cfb1ece0333dd36e6b8e352ecdcaafc1c6f491934d05e4b140","src/string.rs":"966d2b41fae4e7a6083eb142a57e669e4bafd833f01c8b24fc67dff4fb4a5595"},"package":"efee06d8ac3e85a6e9759a0ed2682235a70832ebe10953849b92cdced8688660"}
{"files":{"Cargo.toml":"7a7e6f298886b5427ccc30719c24816a12c5ec5344ec7d8e610e4d9fdc7d65d4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"63e747d86bdeb67638f26b4b75107f129c5f12de432ae83ccdb1ccbe28debf30","README.md":"67780fbfcaf2cd01e3b7f5c7d1ef8b9e385b7cd4435358954aec24a85755ced2","src/error.rs":"e4c87fe305f7fbb830348c0f5b181385c96aa9561dfa1536ef1ce09065e6ce83","src/ffistr.rs":"12a4f351c248e150da18b6ea3797eca65f63e8fa24c62828a2510b9c3a4b8ca5","src/handle_map.rs":"d5f22ad76260f8c1c9cc019c4fec579281b75ae670742b1c4f2470ae56cce87c","src/into_ffi.rs":"bde79bf6b2bbc3108654bf14ac4216c4c5f2a91962de6f814d0bac1bde243c1c","src/lib.rs":"3aa48de38137e2c8784c65b7d981af01b668e1543fc1cf35d52535828bace13f","src/macros.rs":"479153198e1676fdca0be53cbd437a05cd807a2520bacfdb8849a742188f1359","src/string.rs":"966d2b41fae4e7a6083eb142a57e669e4bafd833f01c8b24fc67dff4fb4a5595"},"package":"087be066eb6e85d7150f0c5400018a32802f99d688b2d3868c526f7bbfe17960"}

20
third_party/rust/ffi-support/Cargo.toml поставляемый
Просмотреть файл

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "ffi-support"
version = "0.3.5"
version = "0.4.0"
authors = ["Thom Chiovoloni <tchiovoloni@mozilla.com>"]
description = "A crate to help expose Rust functions over the FFI."
readme = "README.md"
@ -22,28 +22,22 @@ categories = ["development-tools::ffi"]
license = "Apache-2.0 / MIT"
repository = "https://github.com/mozilla/application-services"
[dependencies.backtrace]
version = "0.3.9"
version = "0.3.38"
optional = true
[dependencies.failure]
version = "0.1.5"
[dependencies.failure_derive]
version = "0.1.5"
[dependencies.lazy_static]
version = "1.3.0"
version = "1.4.0"
[dependencies.log]
version = "0.4"
[dev-dependencies.env_logger]
version = "0.6.2"
[dev-dependencies.rand]
version = "0.7.0"
[dev-dependencies.rand]
version = "0.7.2"
[dev-dependencies.rayon]
version = "1.1.0"
version = "1.3.0"
[features]
default = []

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

@ -258,7 +258,7 @@ impl From<Box<dyn std::any::Any + Send + 'static>> for ExternError {
fn from(e: Box<dyn std::any::Any + Send + 'static>) -> Self {
// The documentation suggests that it will *usually* be a str or String.
let message = if let Some(s) = e.downcast_ref::<&'static str>() {
s.to_string()
(*s).to_string()
} else if let Some(s) = e.downcast_ref::<String>() {
s.clone()
} else {

4
third_party/rust/ffi-support/src/ffistr.rs поставляемый
Просмотреть файл

@ -72,6 +72,10 @@ impl<'a> FfiStr<'a> {
///
/// This should not be needed most of the time, and users should instead
/// accept `FfiStr` in function parameter lists.
///
/// # Safety
///
/// Dereferences a pointer and is thus unsafe.
#[inline]
pub unsafe fn from_raw(ptr: *const c_char) -> Self {
Self {

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

@ -64,7 +64,8 @@
use crate::error::{ErrorCode, ExternError};
use crate::into_ffi::IntoFfi;
use failure_derive::Fail;
use std::error::Error as StdError;
use std::fmt;
use std::ops;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Mutex, RwLock};
@ -170,33 +171,45 @@ pub const MAX_CAPACITY: usize = (1 << 15) - 1;
const MIN_CAPACITY: usize = 4;
/// An error representing the ways a `Handle` may be invalid.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Fail)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum HandleError {
/// Identical to invalid handle, but has a slightly more helpful
/// message for the most common case 0.
#[fail(display = "Tried to use a null handle (this object has probably been closed)")]
NullHandle,
/// Returned from [`Handle::from_u64`] if [`Handle::is_valid`] fails.
#[fail(display = "u64 could not encode a valid Handle")]
InvalidHandle,
/// Returned from get/get_mut/delete if the handle is stale (this indicates
/// something equivalent to a use-after-free / double-free, etc).
#[fail(display = "Handle has stale version number")]
StaleVersion,
/// Returned if the handle index references an index past the end of the
/// HandleMap.
#[fail(display = "Handle references a index past the end of this HandleMap")]
IndexPastEnd,
/// The handle has a map_id for a different map than the one it was
/// attempted to be used with.
#[fail(display = "Handle is from a different map")]
WrongMap,
}
impl StdError for HandleError {}
impl fmt::Display for HandleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use HandleError::*;
match self {
NullHandle => {
f.write_str("Tried to use a null handle (this object has probably been closed)")
}
InvalidHandle => f.write_str("u64 could not encode a valid Handle"),
StaleVersion => f.write_str("Handle has stale version number"),
IndexPastEnd => f.write_str("Handle references a index past the end of this HandleMap"),
WrongMap => f.write_str("Handle is from a different map"),
}
}
}
impl From<HandleError> for ExternError {
fn from(e: HandleError) -> Self {
ExternError::new_error(ErrorCode::INVALID_HANDLE, e.to_string())
@ -1303,5 +1316,4 @@ mod test {
inner.assert_valid();
assert_eq!(inner.len(), 0);
}
}

37
third_party/rust/ffi-support/src/into_ffi.rs поставляемый
Просмотреть файл

@ -143,16 +143,17 @@ use std::ptr;
/// // Note: this type manages memory, so you still will want to expose a destructor for this,
/// // and possibly implement Drop as well.
/// ```
pub unsafe trait IntoFfi {
pub unsafe trait IntoFfi: Sized {
/// This type must be:
///
/// 1. Compatible with C, which is to say `#[repr(C)]`, a numeric primitive, another type that
/// has guarantees made about it's layout, or a `#[repr(transparent)]` wrapper around one of
/// those.
/// 1. Compatible with C, which is to say `#[repr(C)]`, a numeric primitive,
/// another type that has guarantees made about it's layout, or a
/// `#[repr(transparent)]` wrapper around one of those.
///
/// One could even use `&T`, so long as `T: Sized`, although it's extremely dubious to return
/// a reference to borrowed memory over the FFI, since it's very difficult for the caller
/// to know how long it remains valid.
/// One could even use `&T`, so long as `T: Sized`, although it's
/// extremely dubious to return a reference to borrowed memory over the
/// FFI, since it's very difficult for the caller to know how long it
/// remains valid.
///
/// 2. Capable of storing an empty/ignorable/default value.
///
@ -164,19 +165,23 @@ pub unsafe trait IntoFfi {
///
/// - #[repr(C)] structs containing only things on this list.
///
/// - Raw pointers: `*const T`, and `*mut T`
/// - `Option<Box<T>>`, but only if `T` is `Sized`. (Internally this is
/// guaranteed to be represented equivalently to a pointer)
///
/// - Enums with a fixed `repr`, although it's a good idea avoid `#[repr(C)]` enums in favor of
/// `#[repr(i32)]` (for example, any fixed type there should be fine), as it's potentially
/// error prone to access `#[repr(C)]` enums from Android over JNA (it's only safe if C's
/// - Raw pointers such as `*const T`, and `*mut T`, but again, only if `T`
/// is `Sized` (`*const [T]`, `*mut dyn SomeTrait` etc are not valid).
///
/// - Enums with a fixed `repr`, although it's a good idea avoid
/// `#[repr(C)]` enums in favor of, say, `#[repr(i32)]` (for example, any
/// fixed type there should be fine), as it's potentially error prone to
/// access `#[repr(C)]` enums from Android over JNA (it's only safe if C's
/// `sizeof(int) == 4`, which is very common, but not universally true).
///
/// - `&T`/`&mut T` where `T: Sized` but only if you really know what you're doing, because this is
/// probably a mistake.
/// - `&T`/`&mut T` where `T: Sized` but only if you really know what you're
/// doing, because this is probably a mistake.
///
/// Invalid examples include things like `&str`, `&[T]`, `String`, `Vec<T>`, `Box<T>`,
/// `std::ffi::CString`, `&std::ffi::CStr`, etc. (Note that eventually, `Box<T>` may be valid
/// `where T: Sized`, but currently it is not).
/// Invalid examples include things like `&str`, `&[T]`, `String`, `Vec<T>`,
/// `std::ffi::CString`, `&std::ffi::CStr`, etc.
type Value;
/// Return an 'empty' value. This is what's passed back to C in the case of an error,

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

@ -304,12 +304,11 @@ pub mod abort_on_panic {
#[cfg(feature = "log_panics")]
fn init_panic_handling_once() {
use std::sync::{Once, ONCE_INIT};
static INIT_BACKTRACES: Once = ONCE_INIT;
use std::sync::Once;
static INIT_BACKTRACES: Once = Once::new();
INIT_BACKTRACES.call_once(move || {
#[cfg(all(feature = "log_backtraces", not(target_os = "android")))]
{
// Turn on backtraces for failure, if it's still listening.
std::env::set_var("RUST_BACKTRACE", "1");
}
// Turn on a panic hook which logs both backtraces and the panic
@ -325,10 +324,6 @@ fn init_panic_handling_once() {
("<unknown>", 0)
};
log::error!("### Rust `panic!` hit at file '{}', line {}", file, line);
// We could use failure for failure::Backtrace (and we enable RUST_BACKTRACE
// to opt-in to backtraces on failure errors if possible), however:
// - `failure` only checks the RUST_BACKTRACE variable once, and we could have errors
// before this. So we just use the backtrace crate directly.
#[cfg(all(feature = "log_backtraces", not(target_os = "android")))]
{
log::error!(" Complete stack trace:\n{:?}", backtrace::Backtrace::new());

33
third_party/rust/ffi-support/src/macros.rs поставляемый
Просмотреть файл

@ -193,7 +193,15 @@ macro_rules! implement_into_ffi_by_delegation {
#[macro_export]
macro_rules! define_string_destructor {
($mylib_destroy_string:ident) => {
#[doc = "Public destructor for strings managed by the other side of the FFI."]
/// Public destructor for strings managed by the other side of the FFI.
///
/// # Safety
///
/// This will free the string pointer it gets passed in as an argument,
/// and thus can be wildly unsafe if misused.
///
/// See the documentation of `ffi_support::destroy_c_string` and
/// `ffi_support::define_string_destructor!` for further info.
#[no_mangle]
pub unsafe extern "C" fn $mylib_destroy_string(s: *mut std::os::raw::c_char) {
// Note: This should never happen, but in the case of a bug aborting
@ -208,17 +216,22 @@ macro_rules! define_string_destructor {
};
}
/// Define a (public) destructor for a type that was allocated by `Box::into_raw(Box::new(value))`
/// (e.g. a pointer which is probably opaque).
/// Define a (public) destructor for a type that was allocated by
/// `Box::into_raw(Box::new(value))` (e.g. a pointer which is probably opaque).
///
/// ## Caveats
///
/// This can go wrong in a ridiculous number of ways, and we can't really prevent any of them. But
/// essentially, the caller (on the other side of the FFI) needs to be extremely careful to ensure
/// that it stops using the pointer after it's freed.
/// When called over the FFI, this can go wrong in a ridiculous number of ways,
/// and we can't really prevent any of them. But essentially, the caller (on the
/// other side of the FFI) needs to be extremely careful to ensure that it stops
/// using the pointer after it's freed.
///
/// Also, to avoid name collisions, it is strongly recommended that you provide an name for this
/// function unique to your library. (This is true for all functions you expose).
/// Also, to avoid name collisions, it is strongly recommended that you provide
/// an name for this function unique to your library. (This is true for all
/// functions you expose).
///
/// However, when called from rust, this is safe, as it becomes a function that
/// just drops a `Option<Box<T>>` with some panic handling.
///
/// ## Example
///
@ -231,6 +244,10 @@ macro_rules! define_string_destructor {
#[macro_export]
macro_rules! define_box_destructor {
($T:ty, $destructor_name:ident) => {
/// # Safety
/// This is equivalent to calling Box::from_raw with panic handling, and
/// thus inherits [`Box::from_raw`]'s safety properties. That is to say,
/// this function is wildly unsafe.
#[no_mangle]
pub unsafe extern "C" fn $destructor_name(v: *mut $T) {
// We should consider passing an error parameter in here rather than

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

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

@ -2,666 +2,633 @@
# It is not intended for manual editing.
[[package]]
name = "arrayref"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "bincode"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder",
"serde",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.3.2"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "c2-chacha"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
dependencies = [
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ppv-lite86",
]
[[package]]
name = "cc"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
dependencies = [
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer",
"num-traits",
"serde",
"time",
]
[[package]]
name = "ctor"
version = "0.1.12"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47c5e5ac752e18207b12e16b10631ae5f7f68f8805f335f9b817ead83d9ffce1"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty",
"humantime",
"log",
"termcolor",
]
[[package]]
name = "failure"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
dependencies = [
"backtrace 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
dependencies = [
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "ffi-support"
version = "0.3.5"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "087be066eb6e85d7150f0c5400018a32802f99d688b2d3868c526f7bbfe17960"
dependencies = [
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static",
"log",
]
[[package]]
name = "getrandom"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "glean-core"
version = "24.0.0"
version = "25.1.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ffi-support 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"iso8601 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rkv 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode",
"chrono",
"ctor",
"env_logger",
"ffi-support",
"iso8601",
"lazy_static",
"log",
"once_cell",
"regex",
"rkv",
"serde",
"serde_json",
"tempfile",
"uuid 0.8.1",
]
[[package]]
name = "hermit-abi"
version = "0.1.6"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error",
]
[[package]]
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
dependencies = [
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "iso8601"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43e86914a73535f3f541a765adea0a9fafcf53fa6adb73662c4988fd9233766f"
dependencies = [
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nom",
]
[[package]]
name = "itoa"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.66"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
[[package]]
name = "lmdb-rkv"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "605061e5465304475be2041f19967a900175ea1b6d8f47fbab84a84fb8c48452"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"lmdb-rkv-sys 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"byteorder",
"libc",
"lmdb-rkv-sys",
]
[[package]]
name = "lmdb-rkv-sys"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7982ba0460e939e26a52ee12c8075deab0ebd44ed21881f656841b70e021b7c8"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if",
]
[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memchr"
version = "2.3.0"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "nom"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
dependencies = [
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr",
"version_check",
]
[[package]]
name = "num-integer"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.2.0"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
[[package]]
name = "ordered-float"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
dependencies = [
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
[[package]]
name = "ppv-lite86"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
[[package]]
name = "proc-macro2"
version = "1.0.7"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
dependencies = [
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
dependencies = [
"c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"c2-chacha",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "regex"
version = "1.3.3"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
dependencies = [
"regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.13"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06"
[[package]]
name = "remove_dir_all"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
]
[[package]]
name = "rkv"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aab7c645d32e977e186448b0a5c2c3139a91a7f630cfd8a8c314d1d145e78bf"
dependencies = [
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lmdb-rkv 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayref",
"bincode",
"bitflags",
"byteorder",
"failure",
"lazy_static",
"lmdb-rkv",
"ordered-float",
"serde",
"serde_derive",
"url",
"uuid 0.7.4",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ryu"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
[[package]]
name = "serde"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
dependencies = [
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
dependencies = [
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.44"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
[[package]]
name = "syn"
version = "1.0.13"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
dependencies = [
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "synstructure"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if",
"libc",
"rand",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util",
]
[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
dependencies = [
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"matches",
]
[[package]]
name = "unicode-normalization"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
dependencies = [
"smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "url"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
dependencies = [
"idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "uuid"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
[[package]]
name = "uuid"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
dependencies = [
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand",
]
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum backtrace 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "a4ed64ae6d9ebfd9893193c4b2532b1292ec97bd8271c9d7d0fa90cd78a34cba"
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
"checksum ffi-support 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "efee06d8ac3e85a6e9759a0ed2682235a70832ebe10953849b92cdced8688660"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum iso8601 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43e86914a73535f3f541a765adea0a9fafcf53fa6adb73662c4988fd9233766f"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum lmdb-rkv 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "605061e5465304475be2041f19967a900175ea1b6d8f47fbab84a84fb8c48452"
"checksum lmdb-rkv-sys 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7982ba0460e939e26a52ee12c8075deab0ebd44ed21881f656841b70e021b7c8"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum rkv 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9aab7c645d32e977e186448b0a5c2c3139a91a7f630cfd8a8c314d1d145e78bf"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

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

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "glean-core"
version = "24.0.0"
version = "25.1.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"
@ -29,7 +29,7 @@ version = "0.4.10"
features = ["serde"]
[dependencies.ffi-support]
version = "0.3.5"
version = "0.4.0"
[dependencies.lazy_static]
version = "1.4.0"
@ -71,6 +71,9 @@ version = "0.3"
[dev-dependencies.tempfile]
version = "3.1.0"
[features]
upload = []
[badges.circle-ci]
branch = "master"
repository = "mozilla/glean"

4
third_party/rust/glean-core/README.md поставляемый
Просмотреть файл

@ -32,7 +32,7 @@ let cfg = Configuration {
max_events: None,
};
let mut glean = Glean::new(cfg).unwrap();
let ping = PingType::new("sample", true);
let ping = PingType::new("sample", true, true, vec![]);
glean.register_ping_type(&ping);
let call_counter: CounterMetric = CounterMetric::new(CommonMetricData {
@ -44,7 +44,7 @@ let call_counter: CounterMetric = CounterMetric::new(CommonMetricData {
call_counter.add(&glean, 1);
glean.submit_ping(&ping).unwrap();
glean.submit_ping(&ping, None).unwrap();
```
## License

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

@ -25,8 +25,8 @@ fn main() {
delay_ping_lifetime_io: false,
};
let mut glean = Glean::new(cfg).unwrap();
glean.register_ping_type(&PingType::new("baseline", true, false));
glean.register_ping_type(&PingType::new("metrics", true, false));
glean.register_ping_type(&PingType::new("baseline", true, false, vec![]));
glean.register_ping_type(&PingType::new("metrics", true, false, vec![]));
let local_metric: StringMetric = StringMetric::new(CommonMetricData {
name: "local_metric".into(),
@ -67,10 +67,10 @@ fn main() {
let ping_maker = PingMaker::new();
let ping = ping_maker
.collect_string(&glean, glean.get_ping_by_name("baseline").unwrap())
.collect_string(&glean, glean.get_ping_by_name("baseline").unwrap(), None)
.unwrap();
println!("Baseline Ping:\n{}", ping);
let ping = ping_maker.collect_string(&glean, glean.get_ping_by_name("metrics").unwrap());
let ping = ping_maker.collect_string(&glean, glean.get_ping_by_name("metrics").unwrap(), None);
println!("Metrics Ping: {:?}", ping);
}

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

@ -16,15 +16,36 @@ use crate::Glean;
use crate::Lifetime;
use crate::Result;
#[derive(Debug)]
pub struct Database {
/// Handle to the database environment.
rkv: Rkv,
// If the `delay_ping_lifetime_io` Glean config option is `true`,
// we will save metrics with 'ping' lifetime data in a map temporarily
// so as to persist them to disk using rkv in bulk on demand.
/// Handles to the "lifetime" stores.
///
/// A "store" is a handle to the underlying database.
/// We keep them open for fast and frequent access.
user_store: SingleStore,
ping_store: SingleStore,
application_store: SingleStore,
/// If the `delay_ping_lifetime_io` Glean config option is `true`,
/// we will save metrics with 'ping' lifetime data in a map temporarily
/// so as to persist them to disk using rkv in bulk on demand.
ping_lifetime_data: Option<RwLock<BTreeMap<String, Metric>>>,
}
impl std::fmt::Debug for Database {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.debug_struct("Database")
.field("rkv", &self.rkv)
.field("user_store", &"SingleStore")
.field("ping_store", &"SingleStore")
.field("application_store", &"SingleStore")
.field("ping_lifetime_data", &self.ping_lifetime_data)
.finish()
}
}
impl Database {
/// Initialize the data store.
///
@ -34,13 +55,23 @@ impl Database {
/// It also loads any Lifetime::Ping data that might be
/// persisted, in case `delay_ping_lifetime_io` is set.
pub fn new(data_path: &str, delay_ping_lifetime_io: bool) -> Result<Self> {
let rkv = Self::open_rkv(data_path)?;
let user_store = rkv.open_single(Lifetime::User.as_str(), StoreOptions::create())?;
let ping_store = rkv.open_single(Lifetime::Ping.as_str(), StoreOptions::create())?;
let application_store =
rkv.open_single(Lifetime::Application.as_str(), StoreOptions::create())?;
let ping_lifetime_data = if delay_ping_lifetime_io {
Some(RwLock::new(BTreeMap::new()))
} else {
None
};
let db = Self {
rkv: Self::open_rkv(data_path)?,
ping_lifetime_data: if delay_ping_lifetime_io {
Some(RwLock::new(BTreeMap::new()))
} else {
None
},
rkv,
user_store,
ping_store,
application_store,
ping_lifetime_data,
};
db.load_ping_lifetime_data();
@ -48,6 +79,14 @@ impl Database {
Ok(db)
}
fn get_store(&self, lifetime: Lifetime) -> &SingleStore {
match lifetime {
Lifetime::User => &self.user_store,
Lifetime::Ping => &self.ping_store,
Lifetime::Application => &self.application_store,
}
}
/// Creates the storage directories and inits rkv.
fn open_rkv(path: &str) -> Result<Rkv> {
let path = std::path::Path::new(path).join("db");
@ -89,13 +128,8 @@ impl Database {
.write()
.expect("Can't read ping lifetime data");
let store: SingleStore = unwrap_or!(
self.rkv
.open_single(Lifetime::Ping.as_str(), StoreOptions::create()),
return
);
let reader = unwrap_or!(self.rkv.read(), return);
let store = self.get_store(Lifetime::Ping);
let mut iter = unwrap_or!(store.iter_start(&reader), return);
while let Some(Ok((metric_name, value))) = iter.next() {
@ -164,15 +198,12 @@ impl Database {
}
}
let store: SingleStore = unwrap_or!(
self.rkv
.open_single(lifetime.as_str(), StoreOptions::create()),
let reader = unwrap_or!(self.rkv.read(), return);
let mut iter = unwrap_or!(
self.get_store(lifetime).iter_from(&reader, &iter_start),
return
);
let reader = unwrap_or!(self.rkv.read(), return);
let mut iter = unwrap_or!(store.iter_from(&reader, &iter_start), return);
while let Some(Ok((metric_name, value))) = iter.next() {
if !metric_name.starts_with(iter_start.as_bytes()) {
break;
@ -219,13 +250,11 @@ impl Database {
}
}
let store: SingleStore = unwrap_or!(
self.rkv
.open_single(lifetime.as_str(), StoreOptions::create()),
return false
);
let reader = unwrap_or!(self.rkv.read(), return false);
store.get(&reader, &key).unwrap_or(None).is_some()
self.get_store(lifetime)
.get(&reader, &key)
.unwrap_or(None)
.is_some()
}
/// Write to the specified storage with the provided transaction function.
@ -237,14 +266,11 @@ impl Database {
/// * This function will **not** panic on database errors.
pub fn write_with_store<F>(&self, store_name: Lifetime, mut transaction_fn: F) -> Result<()>
where
F: FnMut(rkv::Writer, SingleStore) -> Result<()>,
F: FnMut(rkv::Writer, &SingleStore) -> Result<()>,
{
let store: SingleStore = self
.rkv
.open_single(store_name.as_str(), StoreOptions::create())?;
let writer = self.rkv.write()?;
transaction_fn(writer, store)?;
Ok(())
let writer = self.rkv.write().unwrap();
let store = self.get_store(store_name);
transaction_fn(writer, store)
}
/// Records a metric in the underlying storage system.
@ -293,11 +319,9 @@ impl Database {
let encoded = bincode::serialize(&metric).expect("IMPOSSIBLE: Serializing metric failed");
let value = rkv::Value::Blob(&encoded);
let store_name = lifetime.as_str();
let store = self.rkv.open_single(store_name, StoreOptions::create())?;
let mut writer = self.rkv.write()?;
store.put(&mut writer, final_key, &value)?;
self.get_store(lifetime)
.put(&mut writer, final_key, &value)?;
writer.commit()?;
Ok(())
}
@ -363,10 +387,8 @@ impl Database {
}
}
let store_name = lifetime.as_str();
let store = self.rkv.open_single(store_name, StoreOptions::create())?;
let mut writer = self.rkv.write()?;
let store = self.get_store(lifetime);
let new_value: Metric = {
let old_value = store.get(&writer, &final_key)?;

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

@ -140,7 +140,7 @@ impl EventDatabase {
let mut ping_sent = false;
for store_name in store_names {
if let Err(err) = glean.submit_ping_by_name(&store_name) {
if let Err(err) = glean.submit_ping_by_name(&store_name, None) {
log::error!(
"Error flushing existing events to the '{}' ping: {}",
store_name,
@ -199,7 +199,7 @@ impl EventDatabase {
// If any of the event stores reached maximum size, submit the pings
// containing those events immediately.
for store_name in stores_to_submit {
if let Err(err) = glean.submit_ping_by_name(store_name) {
if let Err(err) = glean.submit_ping_by_name(store_name, None) {
log::error!(
"Got more than {} events, but could not send {} ping: {}",
glean.get_max_events(),

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

@ -4,7 +4,7 @@
use std::collections::HashMap;
use once_cell::unsync::OnceCell;
use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use super::{Bucketing, Histogram};
@ -51,7 +51,7 @@ fn exponential_range(min: u64, max: u64, bucket_count: usize) -> Vec<u64> {
///
/// Buckets are pre-computed at instantiation with an exponential distribution from `min` to `max`
/// and `bucket_count` buckets.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PrecomputedExponential {
// Don't serialize the (potentially large) array of ranges, instead compute them on first
// access.

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

@ -16,7 +16,7 @@ use super::{Bucketing, Histogram};
/// i = ⌊n log<sub>base</sub>(𝑥)⌋
///
/// In other words, there are n buckets for each power of `base` magnitude.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Functional {
exponent: f64,
}

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

@ -5,7 +5,7 @@
use std::cmp;
use std::collections::HashMap;
use once_cell::unsync::OnceCell;
use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use super::{Bucketing, Histogram};
@ -36,7 +36,7 @@ fn linear_range(min: u64, max: u64, count: usize) -> Vec<u64> {
///
/// Buckets are pre-computed at instantiation with a linear distribution from `min` to `max`
/// and `bucket_count` buckets.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PrecomputedLinear {
// Don't serialize the (potentially large) array of ranges, instead compute them on first
// access.

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

@ -58,7 +58,7 @@ impl TryFrom<i32> for HistogramType {
/// assert_eq!(10, hist.count());
/// assert_eq!(55, hist.sum());
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Histogram<B> {
/// Mapping bucket's minimum to sample count.
values: HashMap<u64, u64>,

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

@ -21,10 +21,21 @@ pub struct InternalPings {
impl InternalPings {
pub fn new() -> InternalPings {
InternalPings {
baseline: PingType::new("baseline", true, false),
metrics: PingType::new("metrics", true, false),
events: PingType::new("events", true, false),
deletion_request: PingType::new("deletion-request", true, true),
baseline: PingType::new("baseline", true, false, vec![]),
metrics: PingType::new(
"metrics",
true,
false,
vec![
"overdue".to_string(),
"reschedule".to_string(),
"today".to_string(),
"tomorrow".to_string(),
"upgrade".to_string(),
],
),
events: PingType::new("events", true, false, vec![]),
deletion_request: PingType::new("deletion-request", true, true, vec![]),
}
}
}

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

@ -17,6 +17,8 @@ use std::path::{Path, PathBuf};
use chrono::{DateTime, FixedOffset};
use lazy_static::lazy_static;
use once_cell::sync::OnceCell;
use std::sync::Mutex;
use uuid::Uuid;
// This needs to be included first, and the space below prevents rustfmt from
@ -34,6 +36,8 @@ mod internal_pings;
pub mod metrics;
pub mod ping;
pub mod storage;
#[cfg(feature = "upload")]
mod upload;
mod util;
pub use crate::common_metric_data::{CommonMetricData, Lifetime};
@ -43,9 +47,11 @@ pub use crate::error_recording::{test_get_num_recorded_errors, ErrorType};
use crate::event_database::EventDatabase;
use crate::internal_metrics::CoreMetrics;
use crate::internal_pings::InternalPings;
use crate::metrics::PingType;
use crate::metrics::{Metric, MetricType, PingType};
use crate::ping::PingMaker;
use crate::storage::StorageManager;
#[cfg(feature = "upload")]
use crate::upload::{PingUploadManager, PingUploadTask};
use crate::util::{local_now_with_offset, sanitize_application_id};
const GLEAN_SCHEMA_VERSION: u32 = 1;
@ -55,6 +61,40 @@ lazy_static! {
Uuid::parse_str("c0ffeec0-ffee-c0ff-eec0-ffeec0ffeec0").unwrap();
}
// An internal ping name, not to be touched by anything else
pub(crate) const INTERNAL_STORAGE: &str = "glean_internal_info";
// The names of the pings directories.
pub(crate) const PENDING_PINGS_DIRECTORY: &str = "pending_pings";
pub(crate) const DELETION_REQUEST_PINGS_DIRECTORY: &str = "deletion_request";
/// The global Glean instance.
///
/// This is the singleton used by all wrappers to allow for a nice API.
/// All state for Glean is kept inside this object (such as the database handle and `upload_enabled` flag).
///
/// It should be initialized with `glean_core::initialize` at the start of the application using
/// Glean.
static GLEAN: OnceCell<Mutex<Glean>> = OnceCell::new();
/// Get a reference to the global Glean object.
///
/// Panics if no global Glean object was set.
pub fn global_glean() -> &'static Mutex<Glean> {
GLEAN.get().unwrap()
}
/// Set or replace the global Glean object.
pub fn setup_glean(glean: Glean) -> Result<()> {
if GLEAN.get().is_none() {
GLEAN.set(Mutex::new(glean)).unwrap();
} else {
let mut lock = GLEAN.get().unwrap().lock().unwrap();
*lock = glean;
}
Ok(())
}
/// The Glean configuration.
///
/// Optional values will be filled in with default values.
@ -89,7 +129,7 @@ pub struct Configuration {
/// delay_ping_lifetime_io: false,
/// };
/// let mut glean = Glean::new(cfg).unwrap();
/// let ping = PingType::new("sample", true, false);
/// let ping = PingType::new("sample", true, false, vec![]);
/// glean.register_ping_type(&ping);
///
/// let call_counter: CounterMetric = CounterMetric::new(CommonMetricData {
@ -101,7 +141,7 @@ pub struct Configuration {
///
/// call_counter.add(&glean, 1);
///
/// glean.submit_ping(&ping).unwrap();
/// glean.submit_ping(&ping, None).unwrap();
/// ```
///
/// ## Note
@ -111,7 +151,7 @@ pub struct Configuration {
#[derive(Debug)]
pub struct Glean {
upload_enabled: bool,
data_store: Database,
data_store: Option<Database>,
event_data_store: EventDatabase,
core_metrics: CoreMetrics,
internal_pings: InternalPings,
@ -121,6 +161,8 @@ pub struct Glean {
start_time: DateTime<FixedOffset>,
max_events: usize,
is_first_run: bool,
#[cfg(feature = "upload")]
upload_manager: PingUploadManager,
}
impl Glean {
@ -135,7 +177,7 @@ impl Glean {
// Creating the data store creates the necessary path as well.
// If that fails we bail out and don't initialize further.
let data_store = Database::new(&cfg.data_path, cfg.delay_ping_lifetime_io)?;
let data_store = Some(Database::new(&cfg.data_path, cfg.delay_ping_lifetime_io)?);
let event_data_store = EventDatabase::new(&cfg.data_path)?;
let mut glean = Self {
@ -144,6 +186,8 @@ impl Glean {
event_data_store,
core_metrics: CoreMetrics::new(),
internal_pings: InternalPings::new(),
#[cfg(feature = "upload")]
upload_manager: PingUploadManager::new(&cfg.data_path),
data_path: PathBuf::from(cfg.data_path),
application_id,
ping_registry: HashMap::new(),
@ -173,6 +217,12 @@ impl Glean {
Self::new(cfg)
}
/// Destroy the database.
/// After this Glean needs to be reinitialized.
pub fn destroy_db(&mut self) {
self.data_store = None;
}
/// Initialize the core metrics managed by Glean's Rust core.
fn initialize_core_metrics(&mut self) {
let need_new_client_id = match self
@ -235,14 +285,14 @@ impl Glean {
pub fn set_upload_enabled(&mut self, flag: bool) -> bool {
log::info!("Upload enabled: {:?}", flag);
// When upload is disabled, submit a deletion-request ping
if !flag {
if let Err(err) = self.internal_pings.deletion_request.submit(self) {
log::error!("Failed to send deletion-request ping on optout: {}", err);
}
}
if self.upload_enabled != flag {
// When upload is disabled, submit a deletion-request ping
if !flag {
if let Err(err) = self.internal_pings.deletion_request.submit(self, None) {
log::error!("Failed to submit deletion-request ping on optout: {}", err);
}
}
self.upload_enabled = flag;
self.on_change_upload_enabled(flag);
true
@ -278,6 +328,11 @@ impl Glean {
/// Clear any pending metrics when telemetry is disabled.
fn clear_metrics(&mut self) {
// Clear the pending pings queue and acquire the lock
// so that it can't be accessed until this function is done.
#[cfg(feature = "upload")]
let _lock = self.upload_manager.clear_ping_queue();
// There is only one metric that we want to survive after clearing all
// metrics: first_run_date. Here, we store its value so we can restore
// it after clearing the metrics.
@ -295,7 +350,9 @@ impl Glean {
// Delete all stored metrics.
// Note that this also includes the ping sequence numbers, so it has
// the effect of resetting those to their initial values.
self.data_store.clear_all();
if let Some(data) = self.data_store.as_ref() {
data.clear_all()
}
if let Err(err) = self.event_data_store.clear_all() {
log::error!("Error clearing pending events: {}", err);
}
@ -342,7 +399,7 @@ impl Glean {
/// Get a handle to the database.
pub fn storage(&self) -> &Database {
&self.data_store
&self.data_store.as_ref().expect("No database found")
}
/// Get a handle to the event database.
@ -355,6 +412,32 @@ impl Glean {
self.max_events
}
/// Gets the next task for an uploader. Which can be either:
///
/// * Wait - which means the requester should ask again later;
/// * Upload(PingRequest) - which means there is a ping to upload. This wraps the actual request object;
/// * Done - which means there are no more pings queued right now.
///
/// # Return value
///
/// `PingUploadTask` - an enum representing the possible tasks.
#[cfg(feature = "upload")]
pub fn get_upload_task(&self) -> PingUploadTask {
self.upload_manager.get_upload_task()
}
/// Processes the response from an attempt to upload a ping.
///
/// # Arguments
///
/// `uuid` - The UUID of the ping in question.
/// `status` - The HTTP status of the response.
#[cfg(feature = "upload")]
pub fn process_ping_upload_response(&self, uuid: &str, status: u16) {
self.upload_manager
.process_ping_upload_response(uuid, status);
}
/// Take a snapshot for the given store and optionally clear it.
///
/// ## Arguments
@ -392,7 +475,11 @@ impl Glean {
///
/// Returns true if a ping was assembled and queued, false otherwise.
/// Returns an error if collecting or writing the ping to disk failed.
pub fn submit_ping(&self, ping: &PingType) -> Result<bool> {
///
/// ## Arguments
/// * `ping`: The ping to submit
/// * `reason`: A reason code to include in the ping
pub fn submit_ping(&self, ping: &PingType, reason: Option<&str>) -> Result<bool> {
if !self.is_upload_enabled() {
log::error!("Glean must be enabled before sending pings.");
return Ok(false);
@ -401,7 +488,7 @@ impl Glean {
let ping_maker = PingMaker::new();
let doc_id = Uuid::new_v4().to_string();
let url_path = self.make_path(&ping.name, &doc_id);
match ping_maker.collect(self, &ping) {
match ping_maker.collect(self, &ping, reason) {
None => {
log::info!(
"No content for ping '{}', therefore no ping queued.",
@ -421,6 +508,10 @@ impl Glean {
return Err(e.into());
}
#[cfg(feature = "upload")]
self.upload_manager
.enqueue_ping(&doc_id, &url_path, content);
log::info!(
"The ping '{}' was submitted and will be sent as soon as possible",
ping.name
@ -430,25 +521,6 @@ impl Glean {
}
}
/// Collect and submit a ping for eventual uploading by name.
///
/// See `submit_ping` for detailed information.
///
/// Returns true if at least one ping was assembled and queued, false otherwise.
pub fn submit_pings_by_name(&self, ping_names: &[String]) -> bool {
// TODO: 1553813: glean-ac collects and stores pings in parallel and then joins them all before queueing the worker.
// This here is writing them out sequentially.
let mut result = false;
for ping_name in ping_names {
if let Ok(true) = self.submit_ping_by_name(ping_name) {
result = true;
}
}
result
}
/// Collect and submit a ping by name for eventual uploading.
///
/// The ping content is assembled as soon as possible, but upload is not
@ -459,13 +531,17 @@ impl Glean {
///
/// Returns true if a ping was assembled and queued, false otherwise.
/// Returns an error if collecting or writing the ping to disk failed.
pub fn submit_ping_by_name(&self, ping_name: &str) -> Result<bool> {
///
/// ## Arguments
/// * `ping_name`: The name of the ping to submit
/// * `reason`: A reason code to include in the ping
pub fn submit_ping_by_name(&self, ping_name: &str, reason: Option<&str>) -> Result<bool> {
match self.get_ping_by_name(ping_name) {
None => {
log::error!("Attempted to submit unknown ping '{}'", ping_name);
Ok(false)
}
Some(ping) => self.submit_ping(ping),
Some(ping) => self.submit_ping(ping, reason),
}
}
@ -528,7 +604,11 @@ impl Glean {
///
/// If there is no data to persist, this function does nothing.
pub fn persist_ping_lifetime_data(&self) -> Result<()> {
self.data_store.persist_ping_lifetime_data()
if let Some(data) = self.data_store.as_ref() {
return data.persist_ping_lifetime_data();
}
Ok(())
}
/// ** This is not meant to be used directly.**
@ -536,7 +616,9 @@ impl Glean {
/// Clear all the metrics that have `Lifetime::Application`.
pub fn clear_application_lifetime_metrics(&self) {
log::debug!("Clearing Lifetime::Application metrics");
self.data_store.clear_lifetime(Lifetime::Application);
if let Some(data) = self.data_store.as_ref() {
data.clear_lifetime(Lifetime::Application);
}
}
/// Return whether or not this is the first run on this profile.
@ -544,6 +626,50 @@ impl Glean {
self.is_first_run
}
fn get_dirty_bit_metric(&self) -> metrics::BooleanMetric {
metrics::BooleanMetric::new(CommonMetricData {
name: "dirtybit".into(),
// We don't need a category, the name is already unique
category: "".into(),
send_in_pings: vec![INTERNAL_STORAGE.into()],
lifetime: Lifetime::User,
..Default::default()
})
}
/// ** This is not meant to be used directly.**
///
/// Set the value of a "dirty flag" in the permanent storage.
/// The "dirty flag" is meant to have the following behaviour, implemented
/// by the consumers of the FFI layer:
///
/// - on mobile: set to `false` when going to background or shutting down,
/// set to `true` at startup and when going to foreground.
/// - on non-mobile platforms: set to `true` at startup and `false` at
/// shutdown.
///
/// At startup, before setting its new value, if the "dirty flag" value is
/// `true`, then Glean knows it did not exit cleanly and can implement
/// coping mechanisms (e.g. sending a `baseline` ping).
pub fn set_dirty_flag(&self, new_value: bool) {
self.get_dirty_bit_metric().set(self, new_value);
}
/// ** This is not meant to be used directly.**
///
/// Check the stored value of the "dirty flag".
pub fn is_dirty_flag_set(&self) -> bool {
let dirty_bit_metric = self.get_dirty_bit_metric();
match StorageManager.snapshot_metric(
self.storage(),
INTERNAL_STORAGE,
&dirty_bit_metric.meta().identifier(self),
) {
Some(Metric::Boolean(b)) => b,
_ => false,
}
}
/// **Test-only API (exported for FFI purposes).**
///
/// Check if an experiment is currently active.
@ -584,7 +710,9 @@ impl Glean {
/// Note that this also includes the ping sequence numbers, so it has
/// the effect of resetting those to their initial values.
pub fn test_clear_all_stores(&self) {
self.data_store.clear_all();
if let Some(data) = self.data_store.as_ref() {
data.clear_all()
}
// We don't care about this failing, maybe the data does just not exist.
let _ = self.event_data_store.clear_all();
}

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

@ -10,8 +10,11 @@ use crate::metrics::RecordedExperimentData;
use crate::metrics::StringMetric;
const GLOBAL_APPLICATION_ID: &str = "org.mozilla.glean.test.app";
pub fn new_glean() -> (Glean, tempfile::TempDir) {
let dir = tempfile::tempdir().unwrap();
pub fn new_glean(tempdir: Option<tempfile::TempDir>) -> (Glean, tempfile::TempDir) {
let dir = match tempdir {
Some(tempdir) => tempdir,
None => tempfile::tempdir().unwrap(),
};
let tmpname = dir.path().display().to_string();
let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true).unwrap();
(glean, dir)
@ -19,7 +22,7 @@ pub fn new_glean() -> (Glean, tempfile::TempDir) {
#[test]
fn path_is_constructed_from_data() {
let (glean, _) = new_glean();
let (glean, _) = new_glean(None);
assert_eq!(
"/submit/org-mozilla-glean-test-app/baseline/1/this-is-a-docid",
@ -169,7 +172,7 @@ fn client_id_and_first_run_date_must_be_regenerated() {
{
let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true).unwrap();
glean.data_store.clear_all();
glean.data_store.as_ref().unwrap().clear_all();
assert!(glean
.core_metrics
@ -200,7 +203,7 @@ fn client_id_and_first_run_date_must_be_regenerated() {
#[test]
fn basic_metrics_should_be_cleared_when_uploading_is_disabled() {
let (mut glean, _t) = new_glean();
let (mut glean, _t) = new_glean(None);
let metric = StringMetric::new(CommonMetricData::new(
"category",
"string_metric",
@ -225,7 +228,7 @@ fn basic_metrics_should_be_cleared_when_uploading_is_disabled() {
#[test]
fn first_run_date_is_managed_correctly_when_toggling_uploading() {
let (mut glean, _) = new_glean();
let (mut glean, _) = new_glean(None);
let original_first_run_date = glean
.core_metrics
@ -253,7 +256,7 @@ fn first_run_date_is_managed_correctly_when_toggling_uploading() {
#[test]
fn client_id_is_managed_correctly_when_toggling_uploading() {
let (mut glean, _) = new_glean();
let (mut glean, _) = new_glean(None);
let original_client_id = glean
.core_metrics
@ -394,6 +397,145 @@ fn correct_order() {
}
}
#[test]
#[rustfmt::skip] // Let's not merge lines
fn backwards_compatible_deserialization() {
use std::env;
use std::time::Duration;
use chrono::prelude::*;
use histogram::Histogram;
use metrics::{Metric::*, TimeUnit};
// Prepare some data to fill in
let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 12);
let mut custom_dist_exp = Histogram::exponential(1, 500, 10);
custom_dist_exp.accumulate(10);
let mut custom_dist_linear = Histogram::linear(1, 500, 10);
custom_dist_linear.accumulate(10);
let mut time_dist = Histogram::functional(2.0, 8.0);
time_dist.accumulate(10);
let mut mem_dist = Histogram::functional(2.0, 16.0);
mem_dist.accumulate(10);
// One of every metric type. The values are arbitrary, but stable.
let all_metrics = vec![
(
"boolean",
vec![0, 0, 0, 0, 1],
Boolean(true)
),
(
"counter",
vec![1, 0, 0, 0, 20, 0, 0, 0],
Counter(20)
),
(
"custom exponential distribution",
vec![2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 0, 0, 0, 0, 0, 10, 0,
0, 0, 0, 0, 0, 0],
CustomDistributionExponential(custom_dist_exp)
),
(
"custom linear distribution",
vec![3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 244, 1, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0],
CustomDistributionLinear(custom_dist_linear)
),
(
"datetime",
vec![4, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 50, 48, 49, 52, 45, 49, 49, 45,
50, 56, 84, 50, 49, 58, 52, 53, 58, 53, 57, 46, 48, 48, 48, 48, 48,
48, 48, 49, 50, 43, 48, 57, 58, 48, 48, 3, 0, 0, 0],
Datetime(dt, TimeUnit::Second),
),
(
"experiment",
vec![5, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 98, 114, 97, 110, 99, 104, 0],
Experiment(RecordedExperimentData { branch: "branch".into(), extra: None, }),
),
(
"quantity",
vec![6, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0],
Quantity(17)
),
(
"string",
vec![7, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 103, 108, 101, 97, 110],
String("glean".into())
),
(
"string list",
vec![8, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0,
103, 108, 101, 97, 110],
StringList(vec!["glean".into()])
),
(
"uuid",
vec![9, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 48, 56, 50, 99, 51, 101, 53, 50,
45, 48, 97, 49, 56, 45, 49, 49, 101, 97, 45, 57, 52, 54, 102, 45, 48,
102, 101, 48, 99, 57, 56, 99, 51, 54, 49, 99],
Uuid("082c3e52-0a18-11ea-946f-0fe0c98c361c".into()),
),
(
"timespan",
vec![10, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0],
Timespan(Duration::new(5, 0), TimeUnit::Second),
),
(
"timing distribution",
vec![11, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 123, 81, 125,
60, 184, 114, 241, 63],
TimingDistribution(time_dist),
),
(
"memory distribution",
vec![12, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 15, 137, 249,
108, 88, 181, 240, 63],
MemoryDistribution(mem_dist),
),
];
for (name, data, metric) in all_metrics {
// Helper to print serialization data if instructed by environment variable
// Run with:
//
// ```text
// PRINT_DATA=1 cargo test -p glean-core --lib -- --nocapture backwards
// ```
//
// This should not be necessary to re-run and change here, unless a bincode upgrade
// requires us to also migrate existing data.
if env::var("PRINT_DATA").is_ok() {
let bindata = bincode::serialize(&metric).unwrap();
println!("(\n {:?},\n vec!{:?},", name, bindata);
} else {
// Otherwise run the test
let deserialized = bincode::deserialize(&data).unwrap();
if let CustomDistributionExponential(hist) = &deserialized {
hist.snapshot_values(); // Force initialization of the ranges
}
if let CustomDistributionLinear(hist) = &deserialized {
hist.snapshot_values(); // Force initialization of the ranges
}
assert_eq!(
metric, deserialized,
"Expected properly deserialized {}",
name
);
}
}
}
#[test]
fn test_first_run() {
let dir = tempfile::tempdir().unwrap();
@ -410,3 +552,36 @@ fn test_first_run() {
assert!(!glean.is_first_run());
}
}
#[test]
fn test_dirty_bit() {
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().display().to_string();
{
let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true).unwrap();
// The dirty flag must not be set the first time Glean runs.
assert!(!glean.is_dirty_flag_set());
// Set the dirty flag and check that it gets correctly set.
glean.set_dirty_flag(true);
assert!(glean.is_dirty_flag_set());
}
{
// Check that next time Glean runs, it correctly picks up the "dirty flag".
// It is expected to be 'true'.
let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true).unwrap();
assert!(glean.is_dirty_flag_set());
// Set the dirty flag to false.
glean.set_dirty_flag(false);
assert!(!glean.is_dirty_flag_set());
}
{
// Check that next time Glean runs, it correctly picks up the "dirty flag".
// It is expected to be 'false'.
let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true).unwrap();
assert!(!glean.is_dirty_flag_set());
}
}

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

@ -3,7 +3,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_json::{json, Map as JsonMap, Value as JsonValue};
use std::collections::HashMap;
use crate::error_recording::{record_error, ErrorType};
@ -14,10 +14,7 @@ use crate::util::{truncate_string_at_boundary, truncate_string_at_boundary_with_
use crate::CommonMetricData;
use crate::Glean;
use crate::Lifetime;
// FIXME: this should be shared?
// An internal ping name, not to be touched by anything else
const INTERNAL_STORAGE: &str = "glean_internal_info";
use crate::INTERNAL_STORAGE;
/// The maximum length of the experiment id, the branch id, and the keys of the
/// `extra` map. Identifiers longer than this number of characters are truncated.
@ -37,6 +34,21 @@ pub struct RecordedExperimentData {
pub extra: Option<HashMap<String, String>>,
}
impl RecordedExperimentData {
// For JSON, we don't want to include {"extra": null} -- we just want to skip
// extra entirely. Unfortunately, we can't use a serde field annotation for this,
// since that would break bincode serialization, which doesn't support skipping
// fields. Therefore, we use a custom serialization function just for JSON here.
pub fn as_json(&self) -> JsonValue {
let mut value = JsonMap::new();
value.insert("branch".to_string(), json!(self.branch));
if self.extra.is_some() {
value.insert("extra".to_string(), json!(self.extra));
}
JsonValue::Object(value)
}
}
/// An experiment metric.
///
/// Used to store active experiments.

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

@ -24,7 +24,6 @@ lazy_static! {
/// * `this_is_fine_too`
/// * `this.is_still_fine`
/// * `thisisfine`
/// * `this.is_fine.2`
/// * `_.is_fine`
/// * `this.is-fine`
/// * `this-is-fine`
@ -33,7 +32,9 @@ lazy_static! {
/// * `1.not_fine`
/// * `this.$isnotfine`
/// * `-.not_fine`
static ref LABEL_REGEX: Regex = Regex::new("^[a-z_][a-z0-9_-]{0,29}(\\.[a-z0-9_-]{0,29})*$").unwrap();
static ref LABEL_REGEX: Regex = Regex::new(
"^[a-z_][a-z0-9_-]{0,29}(\\.[a-z_][a-z0-9_-]{0,29})*$"
).unwrap();
}
/// A labeled metric.

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

@ -67,7 +67,7 @@ pub use self::uuid::UuidMetric;
/// Do not reorder the variants.
///
/// **Any new metric must be added at the end.**
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Metric {
/// A boolean metric. See [`BooleanMetric`](struct.BooleanMetric.html) for more information.
Boolean(bool),
@ -150,7 +150,7 @@ impl Metric {
}
Metric::CustomDistributionLinear(hist) => json!(custom_distribution::snapshot(hist)),
Metric::Datetime(d, time_unit) => json!(get_iso_time_string(*d, *time_unit)),
Metric::Experiment(e) => json!(e),
Metric::Experiment(e) => e.as_json(),
Metric::Quantity(q) => json!(q),
Metric::String(s) => json!(s),
Metric::StringList(v) => json!(v),

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

@ -17,6 +17,8 @@ pub struct PingType {
pub include_client_id: bool,
/// Whether the ping should be sent if it is empty
pub send_if_empty: bool,
/// The "reason" codes that this ping can send
pub reason_codes: Vec<String>,
}
impl PingType {
@ -28,11 +30,17 @@ impl PingType {
/// * `name` - The name of the ping.
/// * `include_client_id` - Whether to include the client ID in the assembled ping when.
/// sending.
pub fn new<A: Into<String>>(name: A, include_client_id: bool, send_if_empty: bool) -> Self {
pub fn new<A: Into<String>>(
name: A,
include_client_id: bool,
send_if_empty: bool,
reason_codes: Vec<String>,
) -> Self {
Self {
name: name.into(),
include_client_id,
send_if_empty,
reason_codes,
}
}
@ -41,11 +49,25 @@ impl PingType {
/// ## Arguments
///
/// * `glean` - the Glean instance to use to send the ping.
/// * `reason` - the reason the ping was triggered. Included in the
/// `ping_info.reason` part of the payload.
///
/// ## Return value
///
/// See [`Glean#submit_ping`](../struct.Glean.html#method.submit_ping) for details.
pub fn submit(&self, glean: &Glean) -> Result<bool> {
glean.submit_ping(self)
pub fn submit(&self, glean: &Glean, reason: Option<&str>) -> Result<bool> {
let corrected_reason = match reason {
Some(reason) => {
if self.reason_codes.contains(&reason.to_string()) {
Some(reason)
} else {
log::error!("Invalid reason code {} for ping {}", reason, self.name);
None
}
}
None => None,
};
glean.submit_ping(self, corrected_reason)
}
}

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

@ -11,7 +11,7 @@ use crate::error::{Error, ErrorKind};
/// Different resolutions supported by the time related
/// metric types (e.g. DatetimeMetric).
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TimeUnit {
/// Truncate to nanosecond precision.

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

@ -63,15 +63,20 @@ impl Timings {
///
/// This API exists to satisfy the FFI requirements, where the clock is handled on the
/// application side and passed in as a timestamp.
fn set_stop(&mut self, id: TimerId, stop_time: u64) -> Result<u64, &str> {
fn set_stop(&mut self, id: TimerId, stop_time: u64) -> Result<u64, (ErrorType, &str)> {
let start_time = match self.start_times.remove(&id) {
Some(start_time) => start_time,
None => return Err("Timing not running"),
None => return Err((ErrorType::InvalidState, "Timing not running")),
};
let duration = match stop_time.checked_sub(start_time) {
Some(duration) => duration,
None => return Err("Timer stopped with negative duration"),
None => {
return Err((
ErrorType::InvalidValue,
"Timer stopped with negative duration",
))
}
};
Ok(duration)
@ -162,8 +167,8 @@ impl TimingDistributionMetric {
pub fn set_stop_and_accumulate(&mut self, glean: &Glean, id: TimerId, stop_time: u64) {
// Duration is in nanoseconds.
let mut duration = match self.timings.set_stop(id, stop_time) {
Err(error) => {
record_error(glean, &self.meta, ErrorType::InvalidValue, error, None);
Err((err_type, err_msg)) => {
record_error(glean, &self.meta, err_type, err_msg, None);
return;
}
Ok(duration) => duration,

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

@ -15,10 +15,9 @@ use crate::common_metric_data::{CommonMetricData, Lifetime};
use crate::metrics::{CounterMetric, DatetimeMetric, Metric, MetricType, PingType, TimeUnit};
use crate::storage::StorageManager;
use crate::util::{get_iso_time_string, local_now_with_offset};
use crate::{Glean, Result};
// An internal ping name, not to be touched by anything else
const INTERNAL_STORAGE: &str = "glean_internal_info";
use crate::{
Glean, Result, DELETION_REQUEST_PINGS_DIRECTORY, INTERNAL_STORAGE, PENDING_PINGS_DIRECTORY,
};
/// Collect a ping's data, assemble it into its full payload and store it on disk.
pub struct PingMaker;
@ -108,15 +107,20 @@ impl PingMaker {
(start_time_data, end_time_data)
}
fn get_ping_info(&self, glean: &Glean, storage_name: &str) -> JsonValue {
fn get_ping_info(&self, glean: &Glean, storage_name: &str, reason: Option<&str>) -> JsonValue {
let (start_time, end_time) = self.get_start_end_times(glean, storage_name);
let mut map = json!({
"ping_type": storage_name,
"seq": self.get_ping_seq(glean, storage_name),
"start_time": start_time,
"end_time": end_time,
});
if let Some(reason) = reason {
map.as_object_mut()
.unwrap() // safe unwrap, we created the object above
.insert("reason".to_string(), JsonValue::String(reason.to_string()));
};
// Get the experiment data, if available.
if let Some(experiment_data) =
StorageManager.snapshot_experiments_as_json(glean.storage(), INTERNAL_STORAGE)
@ -162,12 +166,18 @@ impl PingMaker {
///
/// * `glean` - the Glean instance to collect data from.
/// * `ping` - the ping to collect for.
/// * `reason` - an optional reason code to include in the ping.
///
/// ## Return value
///
/// Returns a fully assembled JSON representation of the ping payload.
/// If there is no data stored for the ping, `None` is returned.
pub fn collect(&self, glean: &Glean, ping: &PingType) -> Option<JsonValue> {
pub fn collect(
&self,
glean: &Glean,
ping: &PingType,
reason: Option<&str>,
) -> Option<JsonValue> {
info!("Collecting {}", ping.name);
let metrics_data = StorageManager.snapshot_as_json(glean.storage(), &ping.name, true);
@ -181,7 +191,7 @@ impl PingMaker {
info!("Storage for {} empty. Ping will still be sent.", ping.name);
}
let ping_info = self.get_ping_info(glean, &ping.name);
let ping_info = self.get_ping_info(glean, &ping.name, reason);
let client_info = self.get_client_info(glean, ping.include_client_id);
let mut json = json!({
@ -206,13 +216,19 @@ impl PingMaker {
///
/// * `glean` - the Glean instance to collect data from.
/// * `ping` - the ping to collect for.
/// * `reason` - an optional reason code to include in the ping.
///
/// ## Return value
///
/// Returns a fully assembled ping payload in a string encoded as JSON.
/// If there is no data stored for the ping, `None` is returned.
pub fn collect_string(&self, glean: &Glean, ping: &PingType) -> Option<String> {
self.collect(glean, ping)
pub fn collect_string(
&self,
glean: &Glean,
ping: &PingType,
reason: Option<&str>,
) -> Option<String> {
self.collect(glean, ping, reason)
.map(|ping| ::serde_json::to_string_pretty(&ping).unwrap())
}
@ -224,9 +240,9 @@ impl PingMaker {
// Use a special directory for deletion-request pings
let pings_dir = match ping_type {
Some(ping_type) if ping_type == "deletion-request" => {
data_path.join("deletion_request")
data_path.join(DELETION_REQUEST_PINGS_DIRECTORY)
}
_ => data_path.join("pending_pings"),
_ => data_path.join(PENDING_PINGS_DIRECTORY),
};
create_dir_all(&pings_dir)?;
@ -301,7 +317,7 @@ mod test {
#[test]
fn sequence_numbers_should_be_reset_when_toggling_uploading() {
let (mut glean, _) = new_glean();
let (mut glean, _) = new_glean(None);
let ping_maker = PingMaker::new();
assert_eq!(0, ping_maker.get_ping_seq(&glean, "custom"));

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

@ -231,4 +231,28 @@ mod test {
StorageManager.snapshot_experiments_as_json(glean.storage(), "glean_internal_info");
assert!(empty_snapshot.is_none());
}
#[test]
fn test_experiments_json_serialization_empty() {
let t = tempfile::tempdir().unwrap();
let name = t.path().display().to_string();
let glean = Glean::with_options(&name, "org.mozilla.glean", true).unwrap();
let metric = ExperimentMetric::new(&glean, "some-experiment".to_string());
metric.set_active(&glean, "test-branch".to_string(), None);
let snapshot = StorageManager
.snapshot_experiments_as_json(glean.storage(), "glean_internal_info")
.unwrap();
assert_eq!(
json!({"some-experiment": {"branch": "test-branch"}}),
snapshot
);
metric.set_inactive(&glean);
let empty_snapshot =
StorageManager.snapshot_experiments_as_json(glean.storage(), "glean_internal_info");
assert!(empty_snapshot.is_none());
}
}

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

@ -0,0 +1,389 @@
// 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/.
//! Pings directory processing utilities.
use std::cmp::Ordering;
use std::fs::{self, File};
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use log;
use serde_json::Value as JsonValue;
use uuid::Uuid;
use super::PingRequest;
use crate::{DELETION_REQUEST_PINGS_DIRECTORY, PENDING_PINGS_DIRECTORY};
/// Get the file name from a path as a &str.
///
/// # Panics
///
/// Won't panic if not able to get file name.
fn get_file_name_as_str(path: &Path) -> Option<&str> {
match path.file_name() {
None => {
log::warn!("Error getting file name from path: {}", path.display());
None
}
Some(file_name) => {
let file_name = file_name.to_str();
if file_name.is_none() {
log::warn!("File name is not valid unicode: {}", path.display());
}
file_name
}
}
}
/// Manages the pending pings directories.
#[derive(Debug, Clone)]
pub struct PingDirectoryManager {
/// Paths to the pings directories.
pings_dirs: [PathBuf; 2],
}
impl PingDirectoryManager {
/// Creates a new directory manager.
///
/// # Arguments
///
/// * `data_path` - Path to the pending pings directory.
pub fn new<P: Into<PathBuf>>(data_path: P) -> Self {
let data_path = data_path.into();
Self {
pings_dirs: [
data_path.join(PENDING_PINGS_DIRECTORY),
data_path.join(DELETION_REQUEST_PINGS_DIRECTORY),
],
}
}
/// Attempts to delete a ping file.
///
/// ## Arguments
///
/// * `uuid` - The UUID of the ping file to be deleted
///
/// ## Panics
///
/// Won't panic if unable to delete the file.
pub fn delete_file(&self, uuid: &str) {
let path = match self.get_file_path(uuid) {
Some(path) => path,
None => {
log::error!("Cannot find ping file to delete {}", uuid);
return;
}
};
match fs::remove_file(&path) {
Err(e) => log::error!("Error deleting file {}. {}", path.display(), e),
_ => log::info!("Files was deleted {}", path.display()),
};
}
/// Reads a ping file and returns a `PingRequest` from it.
///
/// If the file is not properly formatted, it will be deleted and `None` will be returned.
///
/// ## Arguments
///
/// * `uuid` - The UUID of the ping file to be processed
pub fn process_file(&self, uuid: &str) -> Option<PingRequest> {
let path = match self.get_file_path(uuid) {
Some(path) => path,
None => {
log::error!("Cannot find ping file to process {}", uuid);
return None;
}
};
let file = match File::open(&path) {
Ok(file) => file,
Err(e) => {
log::error!("Error reading ping file {}. {}", path.display(), e);
return None;
}
};
log::info!("Processing ping at: {}", path.display());
// The way the ping file is structured,
// first line should always have the path
// and second line should have the body with the ping contents in JSON format
let mut lines = BufReader::new(file).lines();
if let (Some(Ok(path)), Some(Ok(body))) = (lines.next(), lines.next()) {
if let Ok(parsed_body) = serde_json::from_str::<JsonValue>(&body) {
return Some(PingRequest::new(uuid, &path, parsed_body));
} else {
log::warn!(
"Error processing ping file: {}. Can't parse ping contents as JSON.",
uuid
);
}
} else {
log::warn!(
"Error processing ping file: {}. Ping file is not formatted as expected.",
uuid
);
}
self.delete_file(uuid);
None
}
/// Process the pings directory and return a vector of `PingRequest`s
/// corresponding to each valid ping file in the directory.
/// This vector will be ordered by file `modified_date`.
///
/// Any files that don't match the UUID regex will be deleted
/// to prevent files from polluting the pings directory.
///
/// Files that are not correctly formatted will also be deleted.
///
/// # Return value
///
/// `Vec<PingRequest>` - see [`PingRequest`](struct.PingRequest.html) for more information.
pub fn process_dir(&self) -> Vec<PingRequest> {
log::info!("Processing persisted pings.");
// Walk the pings directory and process each file in it,
// deleting invalid ones and ignoring unreadable ones.
// Create a vector of tuples: (modified_date, PingRequest)
// using the contents and metadata of all valid files.
let mut pending_pings: Vec<_> = self
.get_ping_entries()
.into_iter()
.filter_map(|entry| {
let path = entry.path();
if let Some(file_name) = get_file_name_as_str(&path) {
// Delete file if it doesn't match the pattern.
if Uuid::parse_str(file_name).is_err() {
log::warn!("Pattern mismatch. Deleting {}", path.display());
self.delete_file(file_name);
return None;
}
// In case we can't process the file we just ignore it.
if let Some(request) = self.process_file(file_name) {
// Get the modified date of the file, which will later be used
// for sorting the resulting vector.
let modified_date = fs::metadata(&path).and_then(|data| data.modified());
return Some((modified_date, request));
}
};
None
})
.collect();
// Sort by `modified_date`.
pending_pings.sort_by(|(a, _), (b, _)| {
// We might not be able to get the modified date for a given file,
// in which case we just put it at the end.
if let (Ok(a), Ok(b)) = (a, b) {
a.partial_cmp(b).unwrap()
} else {
Ordering::Less
}
});
// Return the vector leaving only the `PingRequest`s in it
pending_pings
.into_iter()
.map(|(_, request)| request)
.collect()
}
/// Get all the ping entries in all ping directories.
fn get_ping_entries(&self) -> Vec<fs::DirEntry> {
let mut result = Vec::new();
for dir in &self.pings_dirs {
if let Ok(entries) = dir.read_dir() {
result.extend(entries.filter_map(|entry| entry.ok()))
};
}
result
}
/// Get the path for a ping file based on its uuid.
///
/// Will look for files in each ping directory until something is found.
/// If nothing is found, returns `None`.
fn get_file_path(&self, uuid: &str) -> Option<PathBuf> {
for dir in &self.pings_dirs {
let path = dir.join(uuid);
if path.exists() {
return Some(path);
}
}
None
}
}
#[cfg(test)]
mod test {
use std::fs::File;
use std::io::prelude::*;
use uuid::Uuid;
use super::*;
use crate::metrics::PingType;
use crate::tests::new_glean;
#[test]
fn test_doesnt_panic_if_no_pending_pings_directory() {
let dir = tempfile::tempdir().unwrap();
let directory_manager = PingDirectoryManager::new(dir.path());
// Verify that processing the directory didn't panic
assert_eq!(directory_manager.process_dir().len(), 0);
}
#[test]
fn test_creates_requests_correctly_from_valid_ping_file() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, true, vec![]);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory
glean.submit_ping(&ping_type, None).unwrap();
let directory_manager = PingDirectoryManager::new(dir.path());
// Try and process the pings folder
let requests = directory_manager.process_dir();
// Verify there is just the one request
assert_eq!(requests.len(), 1);
// Verify request was returned for the "test" ping
let request_ping_type = requests[0].path.split('/').nth(3).unwrap();
assert_eq!(request_ping_type, "test");
}
#[test]
fn test_non_uuid_files_are_deleted_and_ignored() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, true, vec![]);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory
glean.submit_ping(&ping_type, None).unwrap();
let directory_manager = PingDirectoryManager::new(&dir.path());
let not_uuid_path = dir
.path()
.join(PENDING_PINGS_DIRECTORY)
.join("not-uuid-file-name.txt");
File::create(&not_uuid_path).unwrap();
// Try and process the pings folder
let requests = directory_manager.process_dir();
// Verify there is just the one request
assert_eq!(requests.len(), 1);
// Verify request was returned for the "test" ping
let request_ping_type = requests[0].path.split('/').nth(3).unwrap();
assert_eq!(request_ping_type, "test");
// Verify that file was indeed deleted
assert!(!not_uuid_path.exists());
}
#[test]
fn test_wrongly_formatted_files_are_deleted_and_ignored() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, true, vec![]);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory
glean.submit_ping(&ping_type, None).unwrap();
let directory_manager = PingDirectoryManager::new(&dir.path());
let wrong_contents_file_path = dir
.path()
.join(PENDING_PINGS_DIRECTORY)
.join(Uuid::new_v4().to_string());
File::create(&wrong_contents_file_path).unwrap();
// Try and process the pings folder
let requests = directory_manager.process_dir();
// Verify there is just the one request
assert_eq!(requests.len(), 1);
// Verify request was returned for the "test" ping
let request_ping_type = requests[0].path.split('/').nth(3).unwrap();
assert_eq!(request_ping_type, "test");
// Verify that file was indeed deleted
assert!(!wrong_contents_file_path.exists());
}
#[test]
fn test_non_json_ping_body_files_are_deleted_and_ignored() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, true, vec![]);
glean.register_ping_type(&ping_type);
// Submit the ping to populate the pending_pings directory
glean.submit_ping(&ping_type, None).unwrap();
let directory_manager = PingDirectoryManager::new(&dir.path());
let non_json_body_file_path = dir
.path()
.join(PENDING_PINGS_DIRECTORY)
.join(Uuid::new_v4().to_string());
let mut non_json_body_file = File::create(&non_json_body_file_path).unwrap();
non_json_body_file
.write_all(
b"https://doc.rust-lang.org/std/fs/struct.File.html
This is not JSON!!!!",
)
.unwrap();
// Try and process the pings folder
let requests = directory_manager.process_dir();
// Verify there is just the one request
assert_eq!(requests.len(), 1);
// Verify request was returned for the "test" ping
let request_ping_type = requests[0].path.split('/').nth(3).unwrap();
assert_eq!(request_ping_type, "test");
// Verify that file was indeed deleted
assert!(!non_json_body_file_path.exists());
}
#[test]
fn test_takes_deletion_request_pings_into_account_while_processing() {
let (glean, dir) = new_glean(None);
// Submit a deletion request ping to populate deletion request folder.
glean
.internal_pings
.deletion_request
.submit(&glean, None)
.unwrap();
let directory_manager = PingDirectoryManager::new(dir.path());
// Try and process the pings folder
let requests = directory_manager.process_dir();
assert_eq!(requests.len(), 1);
assert!(requests[0].is_deletion_request());
}
}

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

@ -0,0 +1,506 @@
// 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/.
//! Manages the pending pings queue and directory.
//!
//! * Keeps track of pending pings, loading any unsent ping from disk on startup;
//! * Exposes `get_upload_task` API for the platform layer to request next upload task;
//! * Exposes `process_ping_upload_response` API to check the HTTP response from the ping upload
//! and either delete the corresponding ping from disk or re-enqueue it for sending.
// !IMPORTANT!
// Remove the next line when this module's functionality is in the Glean object.
// This is here just to not have lint error for now.
#![allow(dead_code)]
use std::collections::VecDeque;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock, RwLockWriteGuard};
use std::thread;
use log;
use serde_json::Value as JsonValue;
use directory::PingDirectoryManager;
use request::PingRequest;
mod directory;
mod request;
/// When asking for the next ping request to upload,
/// the requester may receive one out of three possible tasks.
#[derive(PartialEq, Debug)]
pub enum PingUploadTask {
/// A PingRequest popped from the front of the queue.
/// See [`PingRequest`](struct.PingRequest.html) for more information.
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,
/// A flag signaling that the pending pings queue is empty and requester is done.
Done,
}
/// Manages the pending pings queue and directory.
#[derive(Debug)]
pub struct PingUploadManager {
/// A FIFO queue storing a `PingRequest` for each pending ping.
queue: Arc<RwLock<VecDeque<PingRequest>>>,
/// A manager for the pending pings directories.
directory_manager: PingDirectoryManager,
/// A flag signaling if we are done processing the pending pings directories.
processed_pending_pings: Arc<AtomicBool>,
}
impl PingUploadManager {
/// Create a new PingUploadManager.
///
/// Spawns a new thread and processes the pending pings directory,
/// filling up the queue with whatever pings are in there.
///
/// # Arguments
///
/// * `data_path` - Path to the pending pings directory.
///
/// # Panics
///
/// Will panic if unable to spawn a new thread.
pub fn new<P: Into<PathBuf>>(data_path: P) -> Self {
let queue = Arc::new(RwLock::new(VecDeque::new()));
let directory_manager = PingDirectoryManager::new(data_path);
let processed_pending_pings = Arc::new(AtomicBool::new(false));
let local_queue = queue.clone();
let local_flag = processed_pending_pings.clone();
let local_manager = directory_manager.clone();
let _ = thread::Builder::new()
.name("glean.ping_directory_manager.process_dir".to_string())
.spawn(move || {
let mut local_queue = local_queue
.write()
.expect("Can't write to pending pings queue.");
local_queue.extend(local_manager.process_dir());
local_flag.store(true, Ordering::SeqCst);
})
.expect("Unable to spawn thread to process pings directories.");
Self {
queue,
processed_pending_pings,
directory_manager,
}
}
fn has_processed_pings_dir(&self) -> bool {
self.processed_pending_pings.load(Ordering::SeqCst)
}
/// Creates a `PingRequest` and adds it to the queue.
pub fn enqueue_ping(&self, uuid: &str, path: &str, body: JsonValue) {
let mut queue = self
.queue
.write()
.expect("Can't write to pending pings queue.");
let request = PingRequest::new(uuid, path, body);
queue.push_back(request);
}
/// Clears the pending pings queue, leaves the deletion-request pings.
pub fn clear_ping_queue(&self) -> RwLockWriteGuard<'_, VecDeque<PingRequest>> {
let mut queue = self
.queue
.write()
.expect("Can't write to pending pings queue.");
queue.retain(|ping| ping.is_deletion_request());
queue
}
/// Gets the next `PingUploadTask`.
///
/// # Return value
///
/// `PingUploadTask` - see [`PingUploadTask`](enum.PingUploadTask.html) for more information.
pub fn get_upload_task(&self) -> PingUploadTask {
if !self.has_processed_pings_dir() {
return PingUploadTask::Wait;
}
let mut queue = self
.queue
.write()
.expect("Can't write to pending pings queue.");
match queue.pop_front() {
Some(request) => PingUploadTask::Upload(request),
None => PingUploadTask::Done,
}
}
/// Processes the response from an attempt to upload a ping.
///
/// Based on the HTTP status of said response,
/// the possible outcomes are:
///
/// * **200 - 299 Success**
/// Any status on the 2XX range is considered a succesful upload,
/// which means the corresponding ping file can be deleted.
/// _Known 2XX status:_
/// * 200 - OK. Request accepted into the pipeline.
///
/// * **400 - 499 Unrecoverable error**
/// Any status on the 4XX range means something our client did is not correct.
/// It is unlikely that the client is going to recover from this by retrying,
/// so in this case the corresponding ping file can also be deleted.
/// _Known 4XX status:_
/// * 404 - not found - POST/PUT to an unknown namespace
/// * 405 - wrong request type (anything other than POST/PUT)
/// * 411 - missing content-length header
/// * 413 - request body too large Note that if we have badly-behaved clients that
/// retry on 4XX, we should send back 202 on body/path too long).
/// * 414 - request path too long (See above)
///
/// * **Any other error**
/// For any other error, a warning is logged and the ping is re-enqueued.
/// _Known other errors:_
/// * 500 - internal error
///
/// # Note
///
/// The disk I/O performed by this function is not done off-thread,
/// as it is expected to be called off-thread by the platform.
///
/// # Arguments
///
/// `uuid` - The UUID of the ping in question.
/// `status` - The HTTP status of the response.
pub fn process_ping_upload_response(&self, uuid: &str, status: u16) {
match status {
200..=299 => {
log::info!("Ping {} successfully sent {}.", uuid, status);
self.directory_manager.delete_file(uuid);
}
400..=499 => {
log::error!(
"Server returned client error code {} while attempting to send ping {}.",
status,
uuid
);
self.directory_manager.delete_file(uuid);
}
_ => {
log::error!(
"Server returned response code {} while attempting to send ping {}.",
status,
uuid
);
if let Some(request) = self.directory_manager.process_file(uuid) {
let mut queue = self
.queue
.write()
.expect("Can't write to pending pings queue.");
queue.push_back(request);
}
}
};
}
}
#[cfg(test)]
mod test {
use std::thread;
use std::time::Duration;
use serde_json::json;
use super::*;
use crate::metrics::PingType;
use crate::{tests::new_glean, PENDING_PINGS_DIRECTORY};
const UUID: &str = "40e31919-684f-43b0-a5aa-e15c2d56a674"; // Just a random UUID.
const PATH: &str = "/submit/app_id/ping_name/schema_version/doc_id";
#[test]
fn test_doesnt_error_when_there_are_no_pending_pings() {
// Create a new upload_manager
let dir = tempfile::tempdir().unwrap();
let upload_manager = PingUploadManager::new(dir.path());
// Wait for processing of pending pings directory to finish.
while upload_manager.get_upload_task() == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
}
// Try and get the next request.
// Verify request was not returned
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_returns_ping_request_when_there_is_one() {
// Create a new upload_manager
let dir = tempfile::tempdir().unwrap();
let upload_manager = PingUploadManager::new(dir.path());
// Wait for processing of pending pings directory to finish.
while upload_manager.get_upload_task() == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
}
// Enqueue a ping
upload_manager.enqueue_ping(UUID, PATH, json!({}));
// Try and get the next request.
// Verify request was returned
match upload_manager.get_upload_task() {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
}
#[test]
fn test_returns_as_many_ping_requests_as_there_are() {
// Create a new upload_manager
let dir = tempfile::tempdir().unwrap();
let upload_manager = PingUploadManager::new(dir.path());
// Wait for processing of pending pings directory to finish.
while upload_manager.get_upload_task() == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
}
// Enqueue a ping multiple times
let n = 10;
for _ in 0..n {
upload_manager.enqueue_ping(UUID, PATH, json!({}));
}
// Verify a request is returned for each submitted ping
for _ in 0..n {
match upload_manager.get_upload_task() {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
}
// Verify that after all requests are returned, none are left
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_clearing_the_queue_works_correctly() {
// Create a new upload_manager
let dir = tempfile::tempdir().unwrap();
let upload_manager = PingUploadManager::new(dir.path());
// Wait for processing of pending pings directory to finish.
while upload_manager.get_upload_task() == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
}
// Enqueue a ping multiple times
for _ in 0..10 {
upload_manager.enqueue_ping(UUID, PATH, json!({}));
}
// Clear the queue
let _ = upload_manager.clear_ping_queue();
// Verify there really isn't any ping in the queue
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_clearing_the_queue_doesnt_clear_deletion_request_pings() {
let (mut glean, _) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, /* send_if_empty */ true, vec![]);
glean.register_ping_type(&ping_type);
// Submit the ping multiple times
let n = 10;
for _ in 0..n {
glean.submit_ping(&ping_type, None).unwrap();
}
glean
.internal_pings
.deletion_request
.submit(&glean, None)
.unwrap();
// Clear the queue
let _ = glean.upload_manager.clear_ping_queue();
let upload_task = glean.get_upload_task();
match upload_task {
PingUploadTask::Upload(request) => assert!(request.is_deletion_request()),
_ => panic!("Expected upload manager to return the next request!"),
}
// Verify there really isn't any other pings in the queue
assert_eq!(glean.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_fills_up_queue_successfully_from_disk() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, /* send_if_empty */ true, vec![]);
glean.register_ping_type(&ping_type);
// Submit the ping multiple times
let n = 10;
for _ in 0..n {
glean.submit_ping(&ping_type, None).unwrap();
}
// Create a new upload_manager
let upload_manager = PingUploadManager::new(dir.path());
// Wait for processing of pending pings directory to finish.
let mut upload_task = upload_manager.get_upload_task();
while upload_task == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
upload_task = upload_manager.get_upload_task();
}
// Verify the requests were properly enqueued
for _ in 0..n {
match upload_task {
PingUploadTask::Upload(_) => {}
_ => panic!("Expected upload manager to return the next request!"),
}
upload_task = upload_manager.get_upload_task();
}
// Verify that after all requests are returned, none are left
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_processes_correctly_success_upload_response() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, /* send_if_empty */ true, vec![]);
glean.register_ping_type(&ping_type);
// Submit a ping
glean.submit_ping(&ping_type, None).unwrap();
// Create a new upload_manager
let upload_manager = PingUploadManager::new(&dir.path());
// Wait for processing of pending pings directory to finish.
let mut upload_task = upload_manager.get_upload_task();
while upload_task == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
upload_task = upload_manager.get_upload_task();
}
// Get the pending ping directory path
let pending_pings_dir = dir.path().join(PENDING_PINGS_DIRECTORY);
// Get the submitted PingRequest
match upload_task {
PingUploadTask::Upload(request) => {
// Simulate the processing of a sucessfull request
let uuid = request.uuid;
upload_manager.process_ping_upload_response(&uuid, 200);
// Verify file was deleted
assert!(!pending_pings_dir.join(uuid).exists());
}
_ => panic!("Expected upload manager to return the next request!"),
}
// Verify that after request is returned, none are left
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_processes_correctly_client_error_upload_response() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, /* send_if_empty */ true, vec![]);
glean.register_ping_type(&ping_type);
// Submit a ping
glean.submit_ping(&ping_type, None).unwrap();
// Create a new upload_manager
let upload_manager = PingUploadManager::new(&dir.path());
// Wait for processing of pending pings directory to finish.
let mut upload_task = upload_manager.get_upload_task();
while upload_task == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
upload_task = upload_manager.get_upload_task();
}
// Get the pending ping directory path
let pending_pings_dir = dir.path().join(PENDING_PINGS_DIRECTORY);
// Get the submitted PingRequest
match upload_task {
PingUploadTask::Upload(request) => {
// Simulate the processing of a client error
let uuid = request.uuid;
upload_manager.process_ping_upload_response(&uuid, 404);
// Verify file was deleted
assert!(!pending_pings_dir.join(uuid).exists());
}
_ => panic!("Expected upload manager to return the next request!"),
}
// Verify that after request is returned, none are left
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
#[test]
fn test_processes_correctly_server_error_upload_response() {
let (mut glean, dir) = new_glean(None);
// Register a ping for testing
let ping_type = PingType::new("test", true, /* send_if_empty */ true, vec![]);
glean.register_ping_type(&ping_type);
// Submit a ping
glean.submit_ping(&ping_type, None).unwrap();
// Create a new upload_manager
let upload_manager = PingUploadManager::new(dir.path());
// Wait for processing of pending pings directory to finish.
let mut upload_task = upload_manager.get_upload_task();
while upload_task == PingUploadTask::Wait {
thread::sleep(Duration::from_millis(10));
upload_task = upload_manager.get_upload_task();
}
// Get the submitted PingRequest
match upload_task {
PingUploadTask::Upload(request) => {
// Simulate the processing of a client error
let uuid = request.uuid;
upload_manager.process_ping_upload_response(&uuid, 500);
// Verify this ping was indeed re-enqueued
match upload_manager.get_upload_task() {
PingUploadTask::Upload(request) => {
assert_eq!(uuid, request.uuid);
}
_ => panic!("Expected upload manager to return the next request!"),
}
}
_ => panic!("Expected upload manager to return the next request!"),
}
// Verify that after request is returned, none are left
assert_eq!(upload_manager.get_upload_task(), PingUploadTask::Done);
}
}

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

@ -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/.
//! Ping request representation.
use std::collections::HashMap;
use chrono::prelude::{DateTime, Utc};
use serde_json::Value as JsonValue;
/// Represents a request to upload a ping.
#[derive(PartialEq, Debug, Clone)]
pub struct PingRequest {
/// The Job ID to identify this request,
/// this is the same as the ping UUID.
pub uuid: String,
/// The path for the server to upload the ping to.
pub path: String,
/// The body of the request.
pub body: JsonValue,
/// A map with all the headers to be sent with the request.
pub headers: HashMap<String, String>,
}
impl PingRequest {
/// Creates a new PingRequest.
///
/// Automatically creates the default request headers.
/// Clients may add more headers such as `userAgent` to this list.
pub fn new(uuid: &str, path: &str, body: JsonValue) -> Self {
Self {
uuid: uuid.into(),
path: path.into(),
body,
headers: Self::create_request_headers(),
}
}
pub fn is_deletion_request(&self) -> bool {
// The path format should be `/submit/<app_id>/<ping_name>/<schema_version/<doc_id>`
self.path
.split('/')
.nth(3)
.map(|url| url == "deletion-request")
.unwrap_or(false)
}
/// Creates the default request headers.
fn create_request_headers() -> HashMap<String, String> {
let mut headers = HashMap::new();
let date: DateTime<Utc> = Utc::now();
headers.insert("Date".to_string(), date.to_string());
headers.insert("X-Client-Type".to_string(), "Glean".to_string());
headers.insert(
"Content-Type".to_string(),
"application/json; charset=utf-8".to_string(),
);
headers.insert(
"X-Client-Version".to_string(),
env!("CARGO_PKG_VERSION").to_string(),
);
headers
}
}

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

@ -2,7 +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 chrono::offset::TimeZone;
use chrono::{DateTime, FixedOffset, Local};
use crate::error_recording::{record_error, ErrorType};
@ -19,7 +18,7 @@ pub fn sanitize_application_id(application_id: &str) -> String {
.filter_map(|x| match x {
'A'..='Z' | 'a'..='z' | '0'..='9' => {
last_dash = false;
Some(x)
Some(x.to_ascii_lowercase())
}
_ => {
let result = if last_dash { None } else { Some('-') };
@ -49,12 +48,8 @@ pub fn get_iso_time_string(datetime: DateTime<FixedOffset>, truncate_to: TimeUni
///
/// This converts from the `Local` timezone into its fixed-offset equivalent.
pub(crate) fn local_now_with_offset() -> DateTime<FixedOffset> {
// This looks more complicated than I imagined.
let now: DateTime<Local> = Local::now();
let naive = now.naive_utc();
let fixed_tz = Local.offset_from_utc_datetime(&naive);
fixed_tz.from_utc_datetime(&naive)
now.with_timezone(now.offset())
}
/// Truncates a string, ensuring that it doesn't end in the middle of a codepoint.
@ -119,6 +114,7 @@ pub(crate) fn truncate_string_at_boundary_with_error<S: Into<String>>(
#[cfg(test)]
mod test {
use super::*;
use chrono::offset::TimeZone;
#[test]
fn test_sanitize_application_id() {
@ -134,6 +130,10 @@ mod test {
"org-mozilla-test-app",
sanitize_application_id("org-mozilla-test-app")
);
assert_eq!(
"org-mozilla-test-app",
sanitize_application_id("org.mozilla.Test.App")
);
}
#[test]

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

@ -152,7 +152,7 @@ fn test_sending_of_event_ping_when_it_fills_up() {
let store_names: Vec<String> = vec!["events".into()];
for store_name in &store_names {
glean.register_ping_type(&PingType::new(store_name.clone(), true, false));
glean.register_ping_type(&PingType::new(store_name.clone(), true, false, vec![]));
}
let click = EventMetric::new(

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

@ -226,7 +226,7 @@ fn dynamic_labels_too_long() {
}
#[test]
fn dynamic_labels_regex_mimsatch() {
fn dynamic_labels_regex_mismatch() {
let (glean, _t) = new_glean(None);
let mut labeled = LabeledMetric::new(
CounterMetric::new(CommonMetricData {
@ -247,6 +247,7 @@ fn dynamic_labels_regex_mimsatch() {
"1.not_fine",
"this.$isnotfine",
"-.not_fine",
"this.is_not_fine.2",
];
let num_non_validating = labels_not_validating.len();
@ -291,7 +292,6 @@ fn dynamic_labels_regex_allowed() {
"this_is_fine_too",
"this.is_still_fine",
"thisisfine",
"this.is_fine.2",
"_.is_fine",
"this.is-fine",
"this-is-fine",
@ -313,7 +313,6 @@ fn dynamic_labels_regex_allowed() {
"this_is_fine_too": 1,
"this.is_still_fine": 1,
"thisisfine": 1,
"this.is_fine.2": 1,
"_.is_fine": 1,
"this.is-fine": 1,
"this-is-fine": 1

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

@ -12,7 +12,7 @@ use glean_core::CommonMetricData;
fn write_ping_to_disk() {
let (mut glean, _temp) = new_glean(None);
let ping = PingType::new("metrics", true, false);
let ping = PingType::new("metrics", true, false, vec![]);
glean.register_ping_type(&ping);
// We need to store a metric as an empty ping is not stored.
@ -24,7 +24,7 @@ fn write_ping_to_disk() {
});
counter.add(&glean, 1);
assert!(ping.submit(&glean).unwrap());
assert!(ping.submit(&glean, None).unwrap());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
}
@ -33,7 +33,7 @@ fn write_ping_to_disk() {
fn disabling_upload_clears_pending_pings() {
let (mut glean, _) = new_glean(None);
let ping = PingType::new("metrics", true, false);
let ping = PingType::new("metrics", true, false, vec![]);
glean.register_ping_type(&ping);
// We need to store a metric as an empty ping is not stored.
@ -45,7 +45,7 @@ fn disabling_upload_clears_pending_pings() {
});
counter.add(&glean, 1);
assert!(ping.submit(&glean).unwrap());
assert!(ping.submit(&glean, None).unwrap());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
// At this point no deletion_request ping should exist
// (that is: it's directory should not exist at all)
@ -60,26 +60,44 @@ fn disabling_upload_clears_pending_pings() {
assert_eq!(0, get_queued_pings(glean.get_data_path()).unwrap().len());
counter.add(&glean, 1);
assert!(ping.submit(&glean).unwrap());
assert!(ping.submit(&glean, None).unwrap());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
}
#[test]
fn deletion_request_only_when_toggled_from_on_to_off() {
let (mut glean, _) = new_glean(None);
// Disabling upload generates a deletion ping
glean.set_upload_enabled(false);
assert_eq!(1, get_deletion_pings(glean.get_data_path()).unwrap().len());
// Re-setting it to `false` should not generate an additional ping.
// As we didn't clear the pending ping, that's the only one that sticks around.
glean.set_upload_enabled(false);
assert_eq!(1, get_deletion_pings(glean.get_data_path()).unwrap().len());
// Toggling back to true won't generate a ping either.
glean.set_upload_enabled(true);
assert_eq!(1, get_deletion_pings(glean.get_data_path()).unwrap().len());
}
#[test]
fn empty_pings_with_flag_are_sent() {
let (mut glean, _) = new_glean(None);
let ping1 = PingType::new("custom-ping1", true, true);
let ping1 = PingType::new("custom-ping1", true, true, vec![]);
glean.register_ping_type(&ping1);
let ping2 = PingType::new("custom-ping2", true, false);
let ping2 = PingType::new("custom-ping2", true, false, vec![]);
glean.register_ping_type(&ping2);
// No data is stored in either of the custom pings
// Sending this should succeed.
assert_eq!(true, ping1.submit(&glean).unwrap());
assert_eq!(true, ping1.submit(&glean, None).unwrap());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
// Sending this should fail.
assert_eq!(false, ping2.submit(&glean).unwrap());
assert_eq!(false, ping2.submit(&glean, None).unwrap());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
}

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

@ -22,7 +22,7 @@ fn set_up_basic_ping() -> (Glean, PingMaker, PingType, tempfile::TempDir) {
};
let mut glean = Glean::new(cfg).unwrap();
let ping_maker = PingMaker::new();
let ping_type = PingType::new("store1", true, false);
let ping_type = PingType::new("store1", true, false, vec![]);
glean.register_ping_type(&ping_type);
// Record something, so the ping will have data
@ -43,7 +43,7 @@ fn set_up_basic_ping() -> (Glean, PingMaker, PingType, tempfile::TempDir) {
fn ping_info_must_contain_a_nonempty_start_and_end_time() {
let (glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let ping_info = content["ping_info"].as_object().unwrap();
let start_time_str = ping_info["start_time"].as_str().unwrap();
@ -59,10 +59,9 @@ fn ping_info_must_contain_a_nonempty_start_and_end_time() {
fn get_ping_info_must_report_all_the_required_fields() {
let (glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let ping_info = content["ping_info"].as_object().unwrap();
assert_eq!("store1", ping_info["ping_type"].as_str().unwrap());
assert!(ping_info.get("start_time").is_some());
assert!(ping_info.get("end_time").is_some());
assert!(ping_info.get("seq").is_some());
@ -72,7 +71,7 @@ fn get_ping_info_must_report_all_the_required_fields() {
fn get_client_info_must_report_all_the_available_data() {
let (glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let client_info = content["client_info"].as_object().unwrap();
client_info["telemetry_sdk_build"].as_str().unwrap();
@ -89,10 +88,12 @@ fn collect_must_report_none_when_no_data_is_stored() {
let (mut glean, ping_maker, ping_type, _t) = set_up_basic_ping();
let unknown_ping_type = PingType::new("unknown", true, false);
let unknown_ping_type = PingType::new("unknown", true, false, vec![]);
glean.register_ping_type(&ping_type);
assert!(ping_maker.collect(&glean, &unknown_ping_type).is_none());
assert!(ping_maker
.collect(&glean, &unknown_ping_type, None)
.is_none());
}
#[test]
@ -111,8 +112,8 @@ fn seq_number_must_be_sequential() {
for i in 0..=1 {
for ping_name in ["store1", "store2"].iter() {
let ping_type = PingType::new(*ping_name, true, false);
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let ping_type = PingType::new(*ping_name, true, false, vec![]);
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let seq_num = content["ping_info"]["seq"].as_i64().unwrap();
// Ensure sequence numbers in different stores are independent of
// each other
@ -122,33 +123,33 @@ fn seq_number_must_be_sequential() {
// Test that ping sequence numbers increase independently.
{
let ping_type = PingType::new("store1", true, false);
let ping_type = PingType::new("store1", true, false, vec![]);
// 3rd ping of store1
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let seq_num = content["ping_info"]["seq"].as_i64().unwrap();
assert_eq!(2, seq_num);
// 4th ping of store1
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let seq_num = content["ping_info"]["seq"].as_i64().unwrap();
assert_eq!(3, seq_num);
}
{
let ping_type = PingType::new("store2", true, false);
let ping_type = PingType::new("store2", true, false, vec![]);
// 3rd ping of store2
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let seq_num = content["ping_info"]["seq"].as_i64().unwrap();
assert_eq!(2, seq_num);
}
{
let ping_type = PingType::new("store1", true, false);
let ping_type = PingType::new("store1", true, false, vec![]);
// 5th ping of store1
let content = ping_maker.collect(&glean, &ping_type).unwrap();
let content = ping_maker.collect(&glean, &ping_type, None).unwrap();
let seq_num = content["ping_info"]["seq"].as_i64().unwrap();
assert_eq!(4, seq_num);
}
@ -158,7 +159,7 @@ fn seq_number_must_be_sequential() {
fn test_clear_pending_pings() {
let (mut glean, _) = new_glean(None);
let ping_maker = PingMaker::new();
let ping_type = PingType::new("store1", true, false);
let ping_type = PingType::new("store1", true, false, vec![]);
glean.register_ping_type(&ping_type);
// Record something, so the ping will have data
@ -172,7 +173,7 @@ fn test_clear_pending_pings() {
});
metric.set(&glean, true);
assert!(glean.submit_ping(&ping_type).is_ok());
assert!(glean.submit_ping(&ping_type, None).is_ok());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
assert!(ping_maker
@ -186,19 +187,19 @@ fn test_no_pings_submitted_if_upload_disabled() {
// Regression test, bug 1603571
let (mut glean, _) = new_glean(None);
let ping_type = PingType::new("store1", true, true);
let ping_type = PingType::new("store1", true, true, vec![]);
glean.register_ping_type(&ping_type);
assert!(glean.submit_ping(&ping_type).is_ok());
assert!(glean.submit_ping(&ping_type, None).is_ok());
assert_eq!(1, get_queued_pings(glean.get_data_path()).unwrap().len());
// Disable upload, then try to sumbit
glean.set_upload_enabled(false);
assert!(glean.submit_ping(&ping_type).is_ok());
assert!(glean.submit_ping(&ping_type, None).is_ok());
assert_eq!(0, get_queued_pings(glean.get_data_path()).unwrap().len());
// Test again through the direct call
assert!(ping_type.submit(&glean).is_ok());
assert!(ping_type.submit(&glean, None).is_ok());
assert_eq!(0, get_queued_pings(glean.get_data_path()).unwrap().len());
}

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

@ -314,3 +314,33 @@ fn large_nanoseconds_values() {
// Check that we got the right sum and number of samples.
assert_eq!(val.sum() as u64, time);
}
#[test]
fn stopping_non_existing_id_records_an_error() {
let (glean, _t) = new_glean(None);
let mut metric = TimingDistributionMetric::new(
CommonMetricData {
name: "non_existing_id".into(),
category: "test".into(),
send_in_pings: vec!["store1".into()],
disabled: false,
lifetime: Lifetime::Ping,
..Default::default()
},
TimeUnit::Nanosecond,
);
metric.set_stop_and_accumulate(&glean, 3785, 60);
// 1 error should be reported.
assert_eq!(
Ok(1),
test_get_num_recorded_errors(
&glean,
metric.meta(),
ErrorType::InvalidState,
Some("store1")
)
);
}

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

@ -1 +0,0 @@
{"files":{"CHANGELOG.md":"82c0aee7d1e503b71a31115208e303f6e689a4da91c98a95c8827bdc81080bf4","Cargo.toml":"b4dccc5d6540f08052daec134025c0510b8ea87f7d3a12d893616b56ba619efa","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"f234c25515132b7205fcf05545f1d5661bba6f2c189aca848290c7e32b832952","src/configuration.rs":"16e3ec9be802ac37b39d2ad4d1a4702d7e5b462071ef7f0265aea84de520641f","src/core_metrics.rs":"0490dfefaccdbb36ead40af02fa4aa75ebb98056884f2eef4340fe27a24f6cfd","src/lib.rs":"f8dc2468495e9c145bad61adad365e76cb99df3968c64f70ae2a77ec28010506","src/metrics/mod.rs":"3f0dc73758bc5836362742b4ab424032f4f398151c6e85ea879a4e7641614347","src/metrics/ping.rs":"27f5153b33060b817304e11ec58cb17184a6264f29fc45cd7042464c3a9263b5","src/system.rs":"7dbe5007bdaa3d4547c992757c26b7543e059f179078f06b946adad0a0bb4e34","src/test.rs":"c9870591227a849eaf52f914abdd310ec5e01ce6ddf9946a3ac3990b601f8fb6"},"package":"182218f42395f369a1a5372d334699458a606aa557dd2e23998ba25704964e2c"}

21
third_party/rust/glean-preview/CHANGELOG.md поставляемый
Просмотреть файл

@ -1,21 +0,0 @@
# v0.0.5 (2020-01-15)
* Upgraded Glean dependency
* See [full Glean changelog](https://github.com/mozilla/glean/blob/v24.0.0/CHANGELOG.md)
* Reset core client metrics when re-enabling upload ([#620](https://github.com/mozilla/glean/pull/620))
# v0.0.4 (2019-12-20)
* Set target architecture in `client_info` ([#603](https://github.com/mozilla/glean/pull/603))
# v0.0.3 (2019-12-19)
* **Breaking Change**: Stub out client info values and provide a way to set app version information ([#592](https://github.com/mozilla/glean/pull/592))
# v0.0.2 (2019-12-09)
* Removed glean-ffi dependency in favor of implementing state in this crate
# v0.0.1 (2019-12-05)
First release of the Glean Rust API preview.

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

@ -1,47 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
edition = "2018"
name = "glean-preview"
version = "0.0.5"
authors = ["Jan-Erik Rediger <jrediger@mozilla.com>", "The Glean Team <glean-team@mozilla.com>"]
include = ["README.md", "LICENSE", "CHANGELOG.md", "src/**/*", "tests/**/*", "Cargo.toml"]
description = "Nice Glean SDK Rust API"
readme = "README.md"
keywords = ["telemetry", "glean"]
license = "MPL-2.0"
repository = "https://github.com/mozilla/glean"
[dependencies.glean-core]
version = "24.0.0"
[dependencies.lazy_static]
version = "1.4.0"
[dependencies.once_cell]
version = "1.2.0"
[dev-dependencies.env_logger]
version = "0.7.1"
features = ["termcolor", "atty", "humantime"]
default-features = false
[dev-dependencies.log]
version = "0.4.8"
[dev-dependencies.tempfile]
version = "3.1.0"
[badges.circle-ci]
branch = "master"
repository = "mozilla/glean"
[badges.maintenance]
status = "actively-developed"

373
third_party/rust/glean-preview/LICENSE поставляемый
Просмотреть файл

@ -1,373 +0,0 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

47
third_party/rust/glean-preview/README.md поставляемый
Просмотреть файл

@ -1,47 +0,0 @@
# glean-preview
The `Glean SDK` is a modern approach for a Telemetry library and is part of the [Glean project](https://docs.telemetry.mozilla.org/concepts/glean/glean.html).
## `glean-preview`
This library provides a Rust API on top of Glean, targeted to Rust consumers.
**Note: `glean-preview` is currently under development and not yet ready for use.**
## Documentation
All documentation is available online:
* [The Glean SDK Book][book]
* [API documentation][apidocs]
[book]: https://mozilla.github.io/glean/
[apidocs]: https://mozilla.github.io/glean/docs/glean_preview/index.html
## Example
```rust,no_run
use glean_preview::{Configuration, Error, metrics::*};
let cfg = Configuration {
data_path: "/tmp/data".into(),
application_id: "org.mozilla.glean_core.example".into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
};
glean_preview::initialize(cfg)?;
let prototype_ping = PingType::new("prototype", true, true);
glean_preview::register_ping_type(&prototype_ping);
prototype_ping.submit();
```
## License
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/

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

@ -1,22 +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/.
/// The Glean configuration.
///
/// Optional values will be filled in with default values.
#[derive(Debug, Clone)]
pub struct Configuration {
/// Whether upload should be enabled.
pub upload_enabled: bool,
/// Path to a directory to store all data in.
pub data_path: String,
/// The application ID (will be sanitized during initialization).
pub application_id: String,
/// The maximum number of events to store before sending a ping containing events.
pub max_events: Option<usize>,
/// Whether Glean should delay persistence of data from metrics with ping lifetime.
pub delay_ping_lifetime_io: bool,
/// The release channel the application is on, if known.
pub channel: Option<String>,
}

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

@ -1,107 +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_core::{metrics::StringMetric, CommonMetricData, Lifetime};
/// Metrics included in every ping as `client_info`.
#[derive(Debug)]
pub struct ClientInfoMetrics {
/// 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,
}
impl ClientInfoMetrics {
/// Create the client info with dummy values for all.
pub fn unknown() -> Self {
ClientInfoMetrics {
app_build: "unknown".to_string(),
app_display_version: "unknown".to_string(),
}
}
}
#[derive(Debug)]
pub struct InternalMetrics {
pub app_build: StringMetric,
pub app_display_version: StringMetric,
pub app_channel: StringMetric,
pub os: StringMetric,
pub os_version: StringMetric,
pub architecture: StringMetric,
pub device_manufacturer: StringMetric,
pub device_model: 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: StringMetric::new(CommonMetricData {
name: "os".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,
}),
device_manufacturer: StringMetric::new(CommonMetricData {
name: "device_manufacturer".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
device_model: StringMetric::new(CommonMetricData {
name: "device_model".into(),
category: "".into(),
send_in_pings: vec!["glean_client_info".into()],
lifetime: Lifetime::Application,
disabled: false,
dynamic_label: None,
}),
}
}
}

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

@ -1,222 +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/.
#![deny(missing_docs)]
//! Glean is a modern approach for recording and sending Telemetry data.
//!
//! It's in use at Mozilla.
//!
//! All documentation can be found online:
//!
//! ## [The Glean SDK Book](https://mozilla.github.io/glean)
//!
//! ## Example
//!
//! Initialize Glean, register a ping and then send it.
//!
//! ```rust,no_run
//! # use glean_preview::{Configuration, ClientInfoMetrics, Error, metrics::*};
//! # fn main() -> Result<(), Error> {
//! let cfg = Configuration {
//! data_path: "/tmp/data".into(),
//! application_id: "org.mozilla.glean_core.example".into(),
//! upload_enabled: true,
//! max_events: None,
//! delay_ping_lifetime_io: false,
//! channel: None,
//! };
//! glean_preview::initialize(cfg, ClientInfoMetrics::unknown())?;
//!
//! let prototype_ping = PingType::new("prototype", true, true);
//!
//! glean_preview::register_ping_type(&prototype_ping);
//!
//! prototype_ping.submit();
//! # Ok(())
//! # }
//! ```
use once_cell::sync::OnceCell;
use std::sync::Mutex;
pub use configuration::Configuration;
pub use core_metrics::ClientInfoMetrics;
pub use glean_core::{CommonMetricData, Error, Glean, Lifetime, Result};
mod configuration;
mod core_metrics;
pub mod metrics;
mod system;
#[derive(Debug)]
struct GleanWrapper {
instance: Glean,
channel: Option<String>,
client_info: ClientInfoMetrics,
}
static GLEAN: OnceCell<Mutex<GleanWrapper>> = OnceCell::new();
/// Get a reference to the global Glean object.
///
/// Panics if no global Glean object was set.
fn global_glean() -> &'static Mutex<GleanWrapper> {
GLEAN.get().unwrap()
}
/// Set or replace the global Glean object.
fn setup_glean(glean: GleanWrapper) -> Result<()> {
if GLEAN.get().is_none() {
GLEAN.set(Mutex::new(glean)).unwrap();
} else {
let mut lock = GLEAN.get().unwrap().lock().unwrap();
*lock = glean;
}
Ok(())
}
fn with_glean<F, R>(f: F) -> R
where
F: Fn(&Glean) -> R,
{
let lock = global_glean().lock().unwrap();
f(&lock.instance)
}
fn with_glean_wrapper_mut<F, R>(f: F) -> R
where
F: Fn(&mut GleanWrapper) -> R,
{
let mut lock = global_glean().lock().unwrap();
f(&mut lock)
}
fn with_glean_mut<F, R>(f: F) -> R
where
F: Fn(&mut Glean) -> R,
{
let mut lock = global_glean().lock().unwrap();
f(&mut lock.instance)
}
/// Create and initialize a new Glean object.
///
/// See `glean_core::Glean::new`.
pub fn initialize(cfg: Configuration, client_info: ClientInfoMetrics) -> Result<()> {
let core_cfg = glean_core::Configuration {
upload_enabled: cfg.upload_enabled,
data_path: cfg.data_path.clone(),
application_id: cfg.application_id.clone(),
max_events: cfg.max_events,
delay_ping_lifetime_io: cfg.delay_ping_lifetime_io,
};
let glean = Glean::new(core_cfg)?;
// First initialize core metrics
initialize_core_metrics(&glean, &client_info, cfg.channel.clone());
// Now make this the global object available to others.
let wrapper = GleanWrapper {
instance: glean,
channel: cfg.channel,
client_info,
};
setup_glean(wrapper)?;
Ok(())
}
fn initialize_core_metrics(
glean: &Glean,
client_info: &ClientInfoMetrics,
channel: Option<String>,
) {
let core_metrics = 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) = channel {
core_metrics.app_channel.set(glean, app_channel);
}
core_metrics.os.set(glean, system::OS.to_string());
core_metrics.os_version.set(glean, "unknown".to_string());
core_metrics
.architecture
.set(glean, system::ARCH.to_string());
core_metrics
.device_manufacturer
.set(glean, "unknown".to_string());
core_metrics.device_model.set(glean, "unknown".to_string());
}
/// Set whether upload is enabled or not.
///
/// See `glean_core::Glean.set_upload_enabled`.
pub fn set_upload_enabled(enabled: bool) -> bool {
with_glean_wrapper_mut(|glean| {
let old_enabled = glean.instance.is_upload_enabled();
glean.instance.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.instance, &glean.client_info, glean.channel.clone());
}
enabled
})
}
/// 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())
}
/// Register a new [`PingType`](metrics/struct.PingType.html).
pub fn register_ping_type(ping: &metrics::PingType) {
with_glean_mut(|glean| {
glean.register_ping_type(&ping.ping_type);
})
}
/// Collect and submit a ping for eventual uploading.
///
/// See `glean_core::Glean.submit_ping`.
///
/// ## Return value
///
/// Returns true if a ping was assembled and queued, false otherwise.
pub fn submit_ping(ping: &metrics::PingType) -> bool {
submit_ping_by_name(&ping.name)
}
/// Collect and submit a ping for eventual uploading by name.
///
/// See `glean_core::Glean.submit_ping_by_name`.
///
/// ## Return value
///
/// Returns true if a ping was assembled and queued, false otherwise.
pub fn submit_ping_by_name(ping: &str) -> bool {
submit_pings_by_name(&[ping.to_string()])
}
/// Collect and submit multiple pings by name for eventual uploading.
///
/// ## Return value
///
/// Returns true if at least one ping was assembled and queued, false otherwise.
pub fn submit_pings_by_name(pings: &[String]) -> bool {
with_glean(|glean| glean.submit_pings_by_name(pings))
}
#[cfg(test)]
mod test;

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

@ -1,39 +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/.
/// Stores information about a ping.
///
/// This is required so that given metric data queued on disk we can send
/// pings with the correct settings, e.g. whether it has a client_id.
#[derive(Clone, Debug)]
pub struct PingType {
pub(crate) name: String,
pub(crate) ping_type: glean_core::metrics::PingType,
}
impl PingType {
/// Create a new ping type for the given name, whether to include the client ID and whether to
/// send this ping empty.
///
/// ## Arguments
///
/// * `name` - The name of the ping.
/// * `include_client_id` - Whether to include the client ID in the assembled ping when.
/// * `send_if_empty` - Whether the ping should be sent empty or not.
pub fn new<A: Into<String>>(name: A, include_client_id: bool, send_if_empty: bool) -> Self {
let name = name.into();
let ping_type =
glean_core::metrics::PingType::new(name.clone(), include_client_id, send_if_empty);
Self { name, ping_type }
}
/// Submit the ping.
///
/// ## Return value
///
/// Returns true if a ping was assembled and queued, false otherwise.
pub fn submit(&self) -> bool {
crate::submit_ping(self)
}
}

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

@ -1,65 +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/.
// Detect and expose `target_os` as a constant.
// Whether this is a good idea is somewhat debatable.
//
// Code adopted from the "platforms" crate: <https://github.com/RustSec/platforms-crate>.
#[cfg(target_os = "android")]
/// `target_os` when building this crate: `android`
pub const OS: &str = "Android";
#[cfg(target_os = "ios")]
/// `target_os` when building this crate: `ios`
pub const OS: &str = "iOS";
#[cfg(target_os = "linux")]
/// `target_os` when building this crate: `linux`
pub const OS: &str = "Linux";
#[cfg(target_os = "macos")]
/// `target_os` when building this crate: `macos`
pub const OS: &str = "MacOS";
#[cfg(target_os = "windows")]
/// `target_os` when building this crate: `windows`
pub const OS: &str = "Windows";
#[cfg(not(any(
target_os = "android",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "windows",
)))]
pub const OS: &str = "unknown";
// Detect and expose `target_arch` as a constant
// Whether this is a good idea is somewhat debatable
#[cfg(target_arch = "aarch64")]
/// `target_arch` when building this crate: `aarch64`
pub const ARCH: &str = "aarch64";
#[cfg(target_arch = "arm")]
/// `target_arch` when building this crate: `arm`
pub const ARCH: &str = "arm";
#[cfg(target_arch = "x86")]
/// `target_arch` when building this crate: `x86`
pub const ARCH: &str = "x86";
#[cfg(target_arch = "x86_64")]
/// `target_arch` when building this crate: `x86_64`
pub const ARCH: &str = "x86_64";
#[cfg(not(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "x86",
target_arch = "x86_64"
)))]
/// `target_arch` when building this crate: unknown!
pub const ARCH: &str = "unknown";

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

@ -1,77 +0,0 @@
use super::*;
const GLOBAL_APPLICATION_ID: &str = "org.mozilla.fogotype.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() -> tempfile::TempDir {
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()),
};
initialize(cfg, ClientInfoMetrics::unknown()).unwrap();
dir
}
#[test]
fn it_initializes() {
env_logger::try_init().ok();
let _ = new_glean();
}
#[test]
fn it_toggles_upload() {
env_logger::try_init().ok();
let _t = new_glean();
assert!(crate::is_upload_enabled());
crate::set_upload_enabled(false);
assert!(!crate::is_upload_enabled());
}
#[test]
fn client_info_reset_after_toggle() {
env_logger::try_init().ok();
let _t = new_glean();
assert!(crate::is_upload_enabled());
// Metrics are identified by category.name, so it's safe to recreate the objects here.
let core_metrics = core_metrics::InternalMetrics::new();
// At start we should have a value.
with_glean(|glean| {
assert!(core_metrics
.os
.test_get_value(glean, "glean_client_info")
.is_some());
});
// Disabling upload clears everything.
crate::set_upload_enabled(false);
with_glean(|glean| {
assert!(!core_metrics
.os
.test_get_value(glean, "glean_client_info")
.is_some());
});
// Re-enabling upload should reset the values.
crate::set_upload_enabled(true);
with_glean(|glean| {
assert!(core_metrics
.os
.test_get_value(glean, "glean_client_info")
.is_some());
});
}

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

@ -0,0 +1,14 @@
[package]
name = "fog"
version = "0.1.0"
authors = ["The Mozilla Project Developers"]
edition = "2018"
license = "MPL-2.0"
[dependencies]
glean-core = "25.1.0"
log = "0.4"
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
static_prefs = { path = "../../../modules/libpref/init/static_prefs" }
xpcom = { path = "../../../xpcom/rust/xpcom" }

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

@ -2,8 +2,10 @@
// 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 different metric types supported by the Glean SDK to handle data.
use nserror::{nsresult, NS_OK};
use nsstring::nsAString;
mod ping;
pub use ping::PingType;
#[no_mangle]
pub unsafe extern "C" fn fog_init(_data_dir: &nsAString, _pingsender_path: &nsAString) -> nsresult {
NS_OK
}

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

@ -1,17 +0,0 @@
[package]
name = "fog"
version = "0.1.0"
authors = ["The Mozilla Project Developers"]
edition = "2018"
license = "MPL-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cstr = "0.1"
glean-preview = "0.0.5"
log = "0.4"
nserror = { path = "../../../../xpcom/rust/nserror" }
nsstring = { path = "../../../../xpcom/rust/nsstring" }
static_prefs = { path = "../../../../modules/libpref/init/static_prefs" }
xpcom = { path = "../../../../xpcom/rust/xpcom" }

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

@ -1,24 +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 http://mozilla.org/MPL/2.0/.
# This file defines the "prototype" ping used by the FOGotype.
---
$schema: moz://mozilla.org/schemas/glean/pings/1-0-0
prototype:
description: >
A ping to show that ping sending works in the FOGotype.
Sent hourly, it has no payload.
The `client_id` it carries is not guaranteed to be stable.
Also, the `client_id` is not the Telemetry `client_id`.
include_client_id: true
send_if_empty: true
notification_emails:
- chutten@mozilla.com
- glean-team@mozilla.com
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1591564
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1591564#c12

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

@ -1,167 +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 http://mozilla.org/MPL/2.0/. */
#[macro_use]
extern crate cstr;
use glean_preview::metrics::PingType;
use glean_preview::{ClientInfoMetrics, Configuration};
use log::error;
use nserror::{nsresult, NS_ERROR_FAILURE, NS_OK};
use nsstring::{nsAString, nsString};
use std::ffi::CString;
use std::fs::{self, File};
use std::io::{self, BufRead, BufReader, Error, Write};
use std::path::{Path, PathBuf};
use std::thread::JoinHandle;
use std::{thread, time};
use xpcom::interfaces::{nsIFile, nsIProcess};
use xpcom::RefPtr;
#[no_mangle]
pub unsafe extern "C" fn fog_init(data_dir: &nsAString, pingsender_path: &nsAString) -> nsresult {
let upload_enabled = static_prefs::pref!("datareporting.healthreport.uploadEnabled");
let pingsender_path = pingsender_path.to_string();
let data_dir = data_dir.to_string();
if thread::Builder::new()
.name("fogotype_init".to_owned())
.spawn(move || {
let cfg = Configuration {
data_path: data_dir.clone(),
application_id: "org.mozilla.fogotype".into(),
upload_enabled,
max_events: None,
delay_ping_lifetime_io: false, // We will want this eventually.
channel: Some("nightly".into()),
};
// TODO: Build our own ClientInfoMetrics instead of using unknown().
if let Err(e) = glean_preview::initialize(cfg, ClientInfoMetrics::unknown()) {
error!("Failed to init glean_preview due to {:?}", e);
return;
}
let mut data_path = PathBuf::from(data_dir);
data_path.push("pending_pings");
// We ignore the returned JoinHandle for the nonce.
// The detached thread will live until this process (the main process) dies.
if let Err(e) = prototype_ping_init(data_path, pingsender_path) {
error!("Failed to init fogtotype prototype ping due to {:?}", e);
}
})
.is_err()
{
return NS_ERROR_FAILURE;
}
NS_OK
}
fn prototype_ping_init(
ping_dir: PathBuf,
pingsender_path: String,
) -> Result<JoinHandle<()>, Error> {
thread::Builder::new()
.name("fogotype_ping".to_owned())
.spawn(move || {
let prototype_ping = PingType::new("prototype", true, true);
glean_preview::register_ping_type(&prototype_ping);
let an_hour = time::Duration::from_secs(60 * 60);
loop {
thread::sleep(an_hour);
let upload_enabled =
static_prefs::pref!("datareporting.healthreport.uploadEnabled");
glean_preview::set_upload_enabled(upload_enabled);
if !upload_enabled {
continue;
}
prototype_ping.submit();
if let Err(e) = send_all_pings(&ping_dir, &pingsender_path) {
error!("Failed to send all pings due to {:?}", e);
}
}
})
}
fn send_all_pings(
ping_dir: &Path,
pingsender_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
assert!(ping_dir.is_dir());
// This will be a multi-step process:
// 1. Ensure we have an (empty) subdirectory in ping_dir called "telemetry" we can work within.
// 2. Split the endpoint out of the glean-format ping in ping_dir, writing the rest to telemetry/.
// 3. Invoke pingsender{.exe} for the ping in telemetry to the endpoint from the glean-format ping file we most timely ripp'd.
// 4. Return to 2 while pings remain in ping_dir
let telemetry_dir = ping_dir.join("telemetry");
let _ = fs::remove_dir_all(&telemetry_dir);
fs::create_dir(&telemetry_dir)?;
for entry in fs::read_dir(ping_dir)? {
let entry = entry?;
let path = entry.path();
if !path.is_file() {
continue;
}
// Do the things.
let file = File::open(&path)?;
let reader = BufReader::new(file);
let lines: Vec<String> = reader.lines().filter_map(io::Result::ok).collect();
// Sanity check: Glean SDK ping file format is two lines.
// First line is the path of the ingestion endpoint.
// Second line is the payload.
if lines.len() != 2 {
// Doesn't look like a Glean SDK-format ping. Get rid of it.
fs::remove_file(path)?;
continue;
}
let telemetry_ping_path =
telemetry_dir.join(path.file_name().ok_or("ping dir file name invalid")?);
let mut telemetry_ping_file = File::create(&telemetry_ping_path)?;
write!(telemetry_ping_file, "{}", lines[1])?;
fs::remove_file(path)?;
let pingsender_file: RefPtr<nsIFile> =
xpcom::create_instance(&cstr!("@mozilla.org/file/local;1"))
.ok_or("couldn't create nsIFile")?;
let process: RefPtr<nsIProcess> =
xpcom::create_instance(&cstr!("@mozilla.org/process/util;1"))
.ok_or("couldn't create nsIProcess")?;
unsafe {
pingsender_file
.InitWithPath(&*nsString::from(pingsender_path) as &nsAString)
.to_result()?;
process.Init(&*pingsender_file).to_result()?;
process.SetStartHidden(true).to_result()?;
process.SetNoShell(true).to_result()?;
};
let server_url = CString::new(format!(
"https://incoming.telemetry.mozilla.org{}",
lines[0]
))?;
let telemetry_ping_path_cstr = CString::new(
telemetry_ping_path
.to_str()
.expect("non-unicode ping path character"),
)?;
let mut args = [server_url.as_ptr(), telemetry_ping_path_cstr.as_ptr()];
let args_length = 2;
// Block while running the process.
// We should feel free to do this because we're on our own thread.
// Also, if we run async, nsIProcess tries to get the ObserverService on this thread, and asserts.
unsafe {
process
.Run(true /* blocking */, args.as_mut_ptr(), args_length)
.to_result()?;
};
}
Ok(())
}

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

@ -31,7 +31,7 @@ webrtc = ["gkrust-shared/webrtc"]
wasm_library_sandboxing = ["gkrust-shared/wasm_library_sandboxing"]
webgpu = ["gkrust-shared/webgpu"]
remote_agent = ["gkrust-shared/remote"]
fogotype = ["gkrust-shared/fogotype"]
glean = ["gkrust-shared/glean"]
[dependencies]
bench-collections-gtest = { path = "../../../../xpcom/rust/gtest/bench-collections" }

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

@ -32,7 +32,7 @@ webrtc = ["gkrust-shared/webrtc"]
wasm_library_sandboxing = ["gkrust-shared/wasm_library_sandboxing"]
webgpu = ["gkrust-shared/webgpu"]
remote_agent = ["gkrust-shared/remote"]
fogotype = ["gkrust-shared/fogotype"]
glean = ["gkrust-shared/glean"]
[dependencies]
gkrust-shared = { path = "shared" }

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

@ -74,8 +74,8 @@ if CONFIG['MOZ_WEBRTC']:
if CONFIG['ENABLE_REMOTE_AGENT']:
gkrust_features += ['remote_agent']
if CONFIG['MOZ_FOGOTYPE']:
gkrust_features += ['fogotype']
if CONFIG['MOZ_GLEAN']:
gkrust_features += ['glean']
if CONFIG['MOZ_USING_WASM_SANDBOXING']:
gkrust_features += ['wasm_library_sandboxing']

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

@ -47,7 +47,7 @@ rlbox_lucet_sandbox = { version = "0.1.0", optional = true }
wgpu-remote = { path = "../../../../gfx/wgpu/wgpu-remote", optional = true }
mapped_hyph = { git = "https://github.com/jfkthame/mapped_hyph.git", tag = "v0.3.0" }
remote = { path = "../../../../remote", optional = true }
fog = { path = "../../../components/telemetry/fog", optional = true }
fog = { path = "../../../components/glean", optional = true }
unic-langid = { version = "0.8", features = ["likelysubtags"] }
unic-langid-ffi = { path = "../../../../intl/locale/rust/unic-langid-ffi" }
@ -87,7 +87,7 @@ webrtc = ["mdns_service"]
wasm_library_sandboxing = ["rlbox_lucet_sandbox"]
webgpu = ["wgpu-remote"]
remote_agent = ["remote"]
fogotype = ["fog"]
glean = ["fog"]
[lib]
path = "lib.rs"

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

@ -25,7 +25,7 @@ extern crate cubeb_coreaudio;
extern crate cubeb_pulse;
extern crate encoding_glue;
extern crate env_logger;
#[cfg(feature = "fogotype")]
#[cfg(feature = "glean")]
extern crate fog;
extern crate gkrust_utils;
extern crate jsrust_shared;

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

@ -1978,16 +1978,16 @@ set_config('MOZ_NEW_NOTIFICATION_STORE', True, when=new_notification_store)
set_define('MOZ_NEW_NOTIFICATION_STORE', True, when=new_notification_store)
# FOGotype prototype Glean SDK Integration Crate
# Glean SDK Integration Crate
# ==============================================================
@depends(milestone)
def fogotype(milestone):
def glean(milestone):
if milestone.is_nightly:
return True
set_config('MOZ_FOGOTYPE', True, when=fogotype)
set_define('MOZ_FOGOTYPE', True, when=fogotype)
set_config('MOZ_GLEAN', True, when=glean)
set_define('MOZ_GLEAN', True, when=glean)
# dump_syms
# ==============================================================

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

@ -40,7 +40,7 @@ clippy:
- testing/mozbase/rust/mozversion/
- testing/webdriver/
- toolkit/components/kvstore/
- toolkit/components/telemetry/fog/
- toolkit/components/glean/
- toolkit/components/xulstore/tests/gtest/
- toolkit/library/rust/
- tools/fuzzing/rust/