glean/lib.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5#![allow(clippy::uninlined_format_args)]
6#![deny(rustdoc::broken_intra_doc_links)]
7#![deny(missing_docs)]
8
9//! Glean is a modern approach for recording and sending Telemetry data.
10//!
11//! It's in use at Mozilla.
12//!
13//! All documentation can be found online:
14//!
15//! ## [The Glean SDK Book](https://mozilla.github.io/glean)
16//!
17//! ## Example
18//!
19//! Initialize Glean, register a ping and then send it.
20//!
21//! ```rust,no_run
22//! # use glean::{ConfigurationBuilder, ClientInfoMetrics, Error, private::*};
23//! let cfg = ConfigurationBuilder::new(true, "/tmp/data", "org.mozilla.glean_core.example").build();
24//! glean::initialize(cfg, ClientInfoMetrics::unknown());
25//!
26//! let prototype_ping = PingType::new("prototype", true, true, true, true, true, vec!(), vec!(), true, vec![]);
27//!
28//! prototype_ping.submit(None);
29//! ```
30
31use std::collections::HashMap;
32use std::path::Path;
33
34use configuration::DEFAULT_GLEAN_ENDPOINT;
35pub use configuration::{Builder as ConfigurationBuilder, Configuration};
36pub use core_metrics::ClientInfoMetrics;
37pub use glean_core::{
38 metrics::{
39 Datetime, DistributionData, MemoryUnit, MetricIdentifier, Rate, RecordedEvent,
40 TestGetValue, TimeUnit, TimerId,
41 },
42 traits, AttributionMetrics, CommonMetricData, DistributionMetrics, Error, ErrorType, Glean,
43 HistogramType, LabeledMetricData, Lifetime, PingRateLimit, RecordedExperiment, Result,
44};
45
46mod configuration;
47mod core_metrics;
48pub mod net;
49pub mod private;
50mod system;
51
52#[cfg(test)]
53mod common_test;
54
55const LANGUAGE_BINDING_NAME: &str = "Rust";
56
57/// Creates and initializes a new Glean object.
58///
59/// See [`glean_core::Glean::new`] for more information.
60///
61/// # Arguments
62///
63/// * `cfg` - the [`Configuration`] options to initialize with.
64/// * `client_info` - the [`ClientInfoMetrics`] values used to set Glean
65/// core metrics.
66pub fn initialize(cfg: Configuration, client_info: ClientInfoMetrics) {
67 initialize_internal(cfg, client_info);
68}
69
70struct GleanEvents {
71 /// An instance of the upload manager
72 upload_manager: net::UploadManager,
73}
74
75impl glean_core::OnGleanEvents for GleanEvents {
76 fn initialize_finished(&self) {
77 // intentionally left empty
78 }
79
80 fn trigger_upload(&self) -> Result<(), glean_core::CallbackError> {
81 self.upload_manager.trigger_upload();
82 Ok(())
83 }
84
85 fn start_metrics_ping_scheduler(&self) -> bool {
86 // We rely on the glean-core MPS.
87 // We always trigger an upload as it might have submitted a ping.
88 true
89 }
90
91 fn cancel_uploads(&self) -> Result<(), glean_core::CallbackError> {
92 // intentionally left empty
93 Ok(())
94 }
95
96 fn shutdown(&self) -> Result<(), glean_core::CallbackError> {
97 self.upload_manager.shutdown();
98 Ok(())
99 }
100}
101
102fn initialize_internal(cfg: Configuration, client_info: ClientInfoMetrics) -> Option<()> {
103 // Initialize the ping uploader.
104 let upload_manager = net::UploadManager::new(
105 cfg.server_endpoint
106 .unwrap_or_else(|| DEFAULT_GLEAN_ENDPOINT.to_string()),
107 cfg.uploader
108 .unwrap_or_else(|| Box::new(net::HttpUploader) as Box<dyn net::PingUploader>),
109 );
110
111 // Now make this the global object available to others.
112 let callbacks = Box::new(GleanEvents { upload_manager });
113
114 let core_cfg = glean_core::InternalConfiguration {
115 upload_enabled: cfg.upload_enabled,
116 data_path: cfg.data_path.display().to_string(),
117 application_id: cfg.application_id.clone(),
118 language_binding_name: LANGUAGE_BINDING_NAME.into(),
119 max_events: cfg.max_events.map(|m| m as u32),
120 delay_ping_lifetime_io: cfg.delay_ping_lifetime_io,
121 app_build: client_info.app_build.clone(),
122 use_core_mps: cfg.use_core_mps,
123 trim_data_to_registered_pings: cfg.trim_data_to_registered_pings,
124 log_level: cfg.log_level,
125 rate_limit: cfg.rate_limit,
126 enable_event_timestamps: cfg.enable_event_timestamps,
127 experimentation_id: cfg.experimentation_id,
128 enable_internal_pings: cfg.enable_internal_pings,
129 ping_schedule: cfg.ping_schedule,
130 ping_lifetime_threshold: cfg.ping_lifetime_threshold as u64,
131 ping_lifetime_max_time: cfg.ping_lifetime_max_time.as_millis() as u64,
132 };
133
134 glean_core::glean_initialize(core_cfg, client_info.into(), callbacks);
135 Some(())
136}
137
138/// Shuts down Glean in an orderly fashion.
139pub fn shutdown() {
140 glean_core::shutdown()
141}
142
143/// **DEPRECATED** Sets whether upload is enabled or not.
144///
145/// **DEPRECATION NOTICE**:
146/// This API is deprecated. Use `set_collection_enabled` instead.
147///
148/// See [`glean_core::Glean::set_upload_enabled`].
149pub fn set_upload_enabled(enabled: bool) {
150 glean_core::glean_set_upload_enabled(enabled)
151}
152
153/// Sets whether upload is enabled or not.
154///
155/// See [`glean_core::Glean::set_upload_enabled`].
156pub fn set_collection_enabled(enabled: bool) {
157 glean_core::glean_set_collection_enabled(enabled)
158}
159
160/// Collects and submits a ping for eventual uploading by name.
161///
162/// Note that this needs to be public in order for RLB consumers to
163/// use Glean debugging facilities.
164///
165/// See [`glean_core::Glean.submit_ping_by_name`].
166pub fn submit_ping_by_name(ping: &str, reason: Option<&str>) {
167 let ping = ping.to_string();
168 let reason = reason.map(|s| s.to_string());
169 glean_core::glean_submit_ping_by_name(ping, reason)
170}
171
172/// Indicate that an experiment is running. Glean will then add an
173/// experiment annotation to the environment which is sent with pings. This
174/// infomration is not persisted between runs.
175///
176/// See [`glean_core::Glean::set_experiment_active`].
177pub fn set_experiment_active(
178 experiment_id: String,
179 branch: String,
180 extra: Option<HashMap<String, String>>,
181) {
182 glean_core::glean_set_experiment_active(experiment_id, branch, extra.unwrap_or_default())
183}
184
185/// Indicate that an experiment is no longer running.
186///
187/// See [`glean_core::Glean::set_experiment_inactive`].
188pub fn set_experiment_inactive(experiment_id: String) {
189 glean_core::glean_set_experiment_inactive(experiment_id)
190}
191
192/// Dynamically set the experimentation identifier, as opposed to setting it through the configuration
193/// during initialization.
194pub fn set_experimentation_id(experimentation_id: String) {
195 glean_core::glean_set_experimentation_id(experimentation_id);
196}
197
198/// TEST ONLY FUNCTION.
199/// Gets stored experimentation id.
200pub fn test_get_experimentation_id() -> Option<String> {
201 glean_core::glean_test_get_experimentation_id()
202}
203
204/// Set the remote configuration values for the metrics' disabled property
205///
206/// See [`glean_core::Glean::apply_server_knobs_config`].
207pub fn glean_apply_server_knobs_config(json: String) {
208 glean_core::glean_apply_server_knobs_config(json)
209}
210
211/// Performs the collection/cleanup operations required by becoming active.
212///
213/// This functions generates a baseline ping with reason `active`
214/// and then sets the dirty bit.
215/// This should be called whenever the consuming product becomes active (e.g.
216/// getting to foreground).
217pub fn handle_client_active() {
218 glean_core::glean_handle_client_active()
219}
220
221/// Performs the collection/cleanup operations required by becoming inactive.
222///
223/// This functions generates a baseline and an events ping with reason
224/// `inactive` and then clears the dirty bit.
225/// This should be called whenever the consuming product becomes inactive (e.g.
226/// getting to background).
227pub fn handle_client_inactive() {
228 glean_core::glean_handle_client_inactive()
229}
230
231/// TEST ONLY FUNCTION.
232/// Checks if an experiment is currently active.
233pub fn test_is_experiment_active(experiment_id: String) -> bool {
234 glean_core::glean_test_get_experiment_data(experiment_id).is_some()
235}
236
237/// TEST ONLY FUNCTION.
238/// Returns the [`RecordedExperiment`] for the given `experiment_id` or panics if
239/// the id isn't found.
240pub fn test_get_experiment_data(experiment_id: String) -> Option<RecordedExperiment> {
241 glean_core::glean_test_get_experiment_data(experiment_id)
242}
243
244/// Destroy the global Glean state.
245pub(crate) fn destroy_glean(clear_stores: bool, data_path: &Path) {
246 let data_path = data_path.display().to_string();
247 glean_core::glean_test_destroy_glean(clear_stores, Some(data_path))
248}
249
250/// TEST ONLY FUNCTION.
251/// Resets the Glean state and triggers init again.
252pub fn test_reset_glean(cfg: Configuration, client_info: ClientInfoMetrics, clear_stores: bool) {
253 destroy_glean(clear_stores, &cfg.data_path);
254 initialize_internal(cfg, client_info);
255 glean_core::join_init();
256}
257
258/// Sets a debug view tag.
259///
260/// When the debug view tag is set, pings are sent with a `X-Debug-ID` header with the
261/// value of the tag and are sent to the ["Ping Debug Viewer"](https://mozilla.github.io/glean/book/dev/core/internal/debug-pings.html).
262///
263/// # Arguments
264///
265/// * `tag` - A valid HTTP header value. Must match the regex: "[a-zA-Z0-9-]{1,20}".
266///
267/// # Returns
268///
269/// This will return `false` in case `tag` is not a valid tag and `true` otherwise.
270/// If called before Glean is initialized it will always return `true`.
271pub fn set_debug_view_tag(tag: &str) -> bool {
272 glean_core::glean_set_debug_view_tag(tag.to_string())
273}
274
275/// Gets the currently set debug view tag.
276///
277/// The `debug_view_tag` may be set from an environment variable
278/// (`GLEAN_DEBUG_VIEW_TAG`) or through the [`set_debug_view_tag`] function.
279///
280/// **WARNING** This function will block if Glean hasn't been initialized and
281/// should only be used for debug purposes.
282///
283/// # Returns
284///
285/// Return the value for the debug view tag or [`None`] if it hasn't been set.
286pub fn glean_get_debug_view_tag() -> Option<String> {
287 glean_core::glean_get_debug_view_tag()
288}
289
290/// Sets the log pings debug option.
291///
292/// When the log pings debug option is `true`,
293/// we log the payload of all succesfully assembled pings.
294///
295/// # Arguments
296///
297/// * `value` - The value of the log pings option
298pub fn set_log_pings(value: bool) {
299 glean_core::glean_set_log_pings(value)
300}
301
302/// Gets the current log pings value.
303///
304/// The `log_pings` option may be set from an environment variable (`GLEAN_LOG_PINGS`)
305/// or through the [`set_log_pings`] function.
306///
307/// **WARNING** This function will block if Glean hasn't been initialized and
308/// should only be used for debug purposes.
309///
310/// # Returns
311///
312/// Return the value for the log pings debug option.
313pub fn glean_get_log_pings() -> bool {
314 glean_core::glean_get_log_pings()
315}
316
317/// Sets source tags.
318///
319/// Overrides any existing source tags.
320/// Source tags will show in the destination datasets, after ingestion.
321///
322/// **Note** If one or more tags are invalid, all tags are ignored.
323///
324/// # Arguments
325///
326/// * `tags` - A vector of at most 5 valid HTTP header values. Individual
327/// tags must match the regex: "[a-zA-Z0-9-]{1,20}".
328pub fn set_source_tags(tags: Vec<String>) {
329 glean_core::glean_set_source_tags(tags);
330}
331
332/// Returns a timestamp corresponding to "now" with millisecond precision.
333pub fn get_timestamp_ms() -> u64 {
334 glean_core::get_timestamp_ms()
335}
336
337/// Asks the database to persist ping-lifetime data to disk.
338///
339/// Probably expensive to call.
340/// Only has effect when Glean is configured with `delay_ping_lifetime_io: true`.
341/// If Glean hasn't been initialized this will dispatch and return Ok(()),
342/// otherwise it will block until the persist is done and return its Result.
343pub fn persist_ping_lifetime_data() {
344 glean_core::glean_persist_ping_lifetime_data();
345}
346
347/// Gets a list of currently registered ping names.
348///
349/// **WARNING** This function will block if Glean hasn't been initialized and
350/// should only be used for debug purposes.
351///
352/// # Returns
353///
354/// The list of ping names that are currently registered.
355pub fn get_registered_ping_names() -> Vec<String> {
356 glean_core::glean_get_registered_ping_names()
357}
358
359/// Updates attribution fields with new values.
360/// AttributionMetrics fields with `None` values will not overwrite older values.
361pub fn update_attribution(attribution: AttributionMetrics) {
362 glean_core::glean_update_attribution(attribution);
363}
364
365/// **TEST-ONLY Method**
366///
367/// Returns the current attribution metrics.
368pub fn test_get_attribution() -> AttributionMetrics {
369 glean_core::glean_test_get_attribution()
370}
371
372/// Updates distribution fields with new values.
373/// DistributionMetrics fields with `None` values will not overwrite older values.
374pub fn update_distribution(distribution: DistributionMetrics) {
375 glean_core::glean_update_distribution(distribution);
376}
377
378/// **TEST-ONLY Method**
379///
380/// Returns the current distribution metrics.
381pub fn test_get_distribution() -> DistributionMetrics {
382 glean_core::glean_test_get_distribution()
383}
384
385/// Return the heap usage of the `Glean` object and all descendant heap-allocated structures.
386///
387/// Value is in bytes.
388pub fn alloc_size(ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
389 glean_core::alloc_size(ops)
390}
391
392#[cfg(test)]
393mod test;