Add a crate for the nice control API

For now this only supports a minimal interface on top of Glean
This commit is contained in:
Jan-Erik Rediger 2019-12-02 18:36:46 +01:00
Родитель 1833a119f8
Коммит d78b3041c7
9 изменённых файлов: 315 добавлений и 8 удалений

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

@ -331,6 +331,20 @@ dependencies = [
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glean-preview"
version = "0.0.1"
dependencies = [
"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)",
"glean-core 21.3.0",
"glean-ffi 21.3.0",
"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)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "goblin"
version = "0.0.24"

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

@ -3,6 +3,7 @@
members = [
"glean-core",
"glean-core/ffi",
"glean-core/preview",
]
[profile.release]

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

@ -22,7 +22,7 @@ mod from_raw;
mod handlemap_ext;
mod labeled;
mod memory_distribution;
mod ping_type;
pub mod ping_type;
mod quantity;
mod string;
mod string_list;
@ -97,11 +97,11 @@ pub extern "C" fn glean_enable_logging() {
/// If this side is changed, the Kotlin side need to be changed, too.
#[repr(C)]
pub struct FfiConfiguration<'a> {
data_dir: FfiStr<'a>,
package_name: FfiStr<'a>,
upload_enabled: u8,
max_events: Option<&'a i32>,
delay_ping_lifetime_io: u8,
pub data_dir: FfiStr<'a>,
pub package_name: FfiStr<'a>,
pub upload_enabled: u8,
pub max_events: Option<&'a i32>,
pub delay_ping_lifetime_io: u8,
}
/// Convert the FFI-compatible configuration object into the proper Rust configuration object.

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

@ -0,0 +1,39 @@
[package]
name = "glean-preview"
version = "0.0.1"
authors = ["Jan-Erik Rediger <jrediger@mozilla.com>", "The Glean Team <glean-team@mozilla.com>"]
description = "Nice Glean SDK Rust API"
repository = "https://github.com/mozilla/glean"
readme = "README.md"
license = "MPL-2.0"
edition = "2018"
keywords = ["telemetry", "glean"]
include = [
"README.md",
"LICENSE",
"src/**/*",
"tests/**/*",
"Cargo.toml",
]
[badges]
circle-ci = { repository = "mozilla/glean", branch = "master" }
maintenance = { status = "actively-developed" }
[dependencies.glean-ffi]
path = "../ffi"
version = "21.3.0"
[dependencies.glean-core]
path = ".."
version = "21.3.0"
[dependencies]
ffi-support = "0.3.5"
lazy_static = "1.4.0"
[dev-dependencies]
once_cell = "1.2.0"
env_logger = { version = "0.7.1", default-features = false, features = ["termcolor", "atty", "humantime"] }
tempfile = "3.0.7"
log = "0.4.8"

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

@ -0,0 +1,45 @@
// 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 std::env;
use once_cell::sync::Lazy;
use tempfile::Builder;
use glean_preview as glean;
use glean_preview::{metrics::PingType, Configuration, Error};
#[allow(non_upper_case_globals)]
pub static PrototypePing: Lazy<PingType> = Lazy::new(|| PingType::new("prototype", true, true));
fn main() -> Result<(), Error> {
env_logger::init();
let mut args = env::args().skip(1);
let data_path = if let Some(path) = args.next() {
path
} else {
let root = Builder::new().prefix("simple-db").tempdir().unwrap();
root.path().display().to_string()
};
let cfg = Configuration {
data_path,
application_id: "org.mozilla.glean_core.example".into(),
upload_enabled: true,
max_events: None,
delay_ping_lifetime_io: false,
};
glean::initialize(cfg)?;
glean::register_ping_type(&PrototypePing);
if glean::send_ping_by_name("prototype") {
log::info!("Successfully collected a prototype ping");
} else {
log::info!("Prototype ping failed");
}
Ok(())
}

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

@ -0,0 +1,153 @@
// 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, 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,
//! };
//! glean_preview::initialize(cfg)?;
//!
//! let prototype_ping = PingType::new("prototype", true, true);
//!
//! glean_preview::register_ping_type(&prototype_ping);
//!
//! prototype_ping.send();
//! # Ok(())
//! # }
//! ```
use ffi_support::FfiStr;
use std::ffi::CString;
use std::sync::Mutex;
pub use glean_core::{Configuration, Error, Result};
pub mod metrics;
lazy_static::lazy_static! {
static ref GLEAN_HANDLE: Mutex<u64> = Mutex::new(0);
}
fn with_glean<F, R>(f: F) -> R
where
F: Fn(u64) -> R,
{
let lock = GLEAN_HANDLE.lock().unwrap();
debug_assert!(*lock != 0);
f(*lock)
}
/// Create and initialize a new Glean object.
///
/// See `glean_core::Glean::new`.
pub fn initialize(cfg: Configuration) -> Result<()> {
unsafe {
let data_dir = CString::new(cfg.data_path).unwrap();
let package_name = CString::new(cfg.application_id).unwrap();
let upload_enabled = cfg.upload_enabled;
let max_events = cfg.max_events.map(|m| m as i32);
let ffi_cfg = glean_ffi::FfiConfiguration {
data_dir: FfiStr::from_cstr(&data_dir),
package_name: FfiStr::from_cstr(&package_name),
upload_enabled: upload_enabled as u8,
max_events: max_events.as_ref(),
delay_ping_lifetime_io: false as u8,
};
let handle = glean_ffi::glean_initialize(&ffi_cfg);
if handle == 0 {
return Err(glean_core::Error::utf8_error());
}
let mut lock = GLEAN_HANDLE.lock().unwrap();
*lock = handle;
Ok(())
}
}
/// Set whether upload is enabled or not.
///
/// See `glean_core::Glean.set_upload_enabled`.
pub fn set_upload_enabled(flag: bool) -> bool {
with_glean(|glean_handle| {
glean_ffi::glean_set_upload_enabled(glean_handle, flag as u8);
glean_ffi::glean_is_upload_enabled(glean_handle) != 0
})
}
/// Determine whether upload is enabled.
///
/// See `glean_core::Glean.is_upload_enabled`.
pub fn is_upload_enabled() -> bool {
with_glean(|glean_handle| glean_ffi::glean_is_upload_enabled(glean_handle) != 0)
}
/// Register a new [`PingType`](metrics/struct.PingType.html).
pub fn register_ping_type(ping: &metrics::PingType) {
with_glean(|glean_handle| {
glean_ffi::ping_type::glean_register_ping_type(glean_handle, ping.handle);
})
}
/// Send a ping.
///
/// See `glean_core::Glean.send_ping`.
///
/// ## Return value
///
/// Returns true if a ping was assembled and queued, false otherwise.
pub fn send_ping(ping: &metrics::PingType) -> bool {
send_ping_by_name(&ping.name)
}
/// Send a ping by name.
///
/// See `glean_core::Glean.send_ping_by_name`.
///
/// ## Return value
///
/// Returns true if a ping was assembled and queued, false otherwise.
pub fn send_ping_by_name(ping: &str) -> bool {
send_pings_by_name(&[ping])
}
/// Send multiple pings by name
///
/// ## Return value
///
/// Returns true if at least one ping was assembled and queued, false otherwise.
pub fn send_pings_by_name(pings: &[&str]) -> bool {
let array: Vec<CString> = pings.iter().map(|s| CString::new(*s).unwrap()).collect();
let ptr_array: Vec<*const _> = array.iter().map(|s| s.as_ptr()).collect();
with_glean(|glean_handle| {
let res = glean_ffi::glean_send_pings_by_name(
glean_handle,
ptr_array.as_ptr(),
array.len() as i32,
);
res != 0
})
}

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

@ -0,0 +1,9 @@
// 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 different metric types supported by the Glean SDK to handle data.
mod ping;
pub use ping::PingType;

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

@ -0,0 +1,46 @@
// 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 ffi_support::FfiStr;
use std::ffi::CString;
/// 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) handle: u64,
}
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 ffi_name = CString::new(name.clone()).unwrap();
let handle = glean_ffi::ping_type::glean_new_ping_type(
FfiStr::from_cstr(&ffi_name),
include_client_id as u8,
send_if_empty as u8,
);
Self { name, handle }
}
/// Send the ping.
///
/// ## Return value
///
/// Returns true if a ping was assembled and queued, false otherwise.
pub fn send(&self) -> bool {
crate::send_ping(self)
}
}

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

@ -20,8 +20,8 @@ pub struct PingType {
}
impl PingType {
/// Create a new ping type for the given name and whether to include the client ID when
/// sending.
/// Create a new ping type for the given name, whether to include the client ID and whether to
/// send this ping empty.
///
/// ## Arguments
///