stats/
lib.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under both the MIT license found in the
5 * LICENSE-MIT file in the root directory of this source tree and the Apache
6 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
7 * of this source tree.
8 */
9
10//! Provides a macro `define_stats!` for creation of stats. This crate requires the caller to
11//! schedule aggregation of stats by calling schedule_stats_aggregation and executing the returned
12//! future.
13
14#![deny(warnings, missing_docs, clippy::all, rustdoc::broken_intra_doc_links)]
15
16pub mod macros;
17mod noop_stats;
18pub mod thread_local_aggregator;
19
20pub mod prelude {
21    //! A "prelude" of `stats` crate.
22    //!
23    //! This prelude is similar to the standard library's prelude in that you'll
24    //! almost always want to import its entire contents, but unlike the standard
25    //! library's prelude you'll have to do so manually:
26    //!
27    //! ```
28    //! # #![allow(unused)]
29    //! use stats::prelude::*;
30    //! ```
31    pub use stats_traits::dynamic_stat_types::DynamicCounter;
32    pub use stats_traits::dynamic_stat_types::DynamicHistogram;
33    pub use stats_traits::dynamic_stat_types::DynamicSingletonCounter;
34    pub use stats_traits::dynamic_stat_types::DynamicTimeseries;
35    pub use stats_traits::stat_types::Counter;
36    pub use stats_traits::stat_types::CounterStatic;
37    pub use stats_traits::stat_types::Histogram;
38    pub use stats_traits::stat_types::HistogramStatic;
39    pub use stats_traits::stat_types::Timeseries;
40    pub use stats_traits::stat_types::TimeseriesStatic;
41
42    pub use crate::define_stats;
43    pub use crate::define_stats_struct;
44}
45
46use std::sync::RwLock;
47
48use stats_traits::stat_types::BoxSingletonCounter;
49use stats_traits::stats_manager::BoxStatsManager;
50use stats_traits::stats_manager::StatsManagerFactory;
51
52pub use self::thread_local_aggregator::schedule_stats_aggregation_preview;
53
54static STATS_MANAGER_FACTORY: RwLock<Option<Box<dyn StatsManagerFactory + Send + Sync>>> =
55    RwLock::new(None);
56
57/// This function must be called exactly once before accessing any of the stats,
58/// otherwise it will panic.
59/// If it won't be called a default stats manager factory will be assumed that
60/// does nothing. (Facebook only: the default will use fb303 counters)
61pub fn register_stats_manager_factory(factory: impl StatsManagerFactory + Send + Sync + 'static) {
62    let mut global_factory = STATS_MANAGER_FACTORY.write().expect("poisoned lock");
63    assert!(
64        global_factory.is_none(),
65        "Called stats::stats_manager::register_stats_manager_factory more than once"
66    );
67    global_factory.replace(Box::new(factory));
68}
69
70#[doc(hidden)]
71/// You probably don't have to use this function, it is made public so that it
72/// might be used by the macros in this crate. It reads the globally registered
73/// StatsManagerFactory and creates a new instance of StatsManager.
74pub fn create_stats_manager() -> BoxStatsManager {
75    if let Some(factory) = STATS_MANAGER_FACTORY
76        .read()
77        .expect("poisoned lock")
78        .as_ref()
79    {
80        return factory.create();
81    }
82    // We get here only if register_stats_manager_factory was not called yet
83    // but we have to keep in mind this is a race so first get hold of write
84    // lock and check if the factory is still unset.
85    let mut write_lock = STATS_MANAGER_FACTORY.write().expect("poisoned lock");
86    let factory = write_lock.get_or_insert_with(get_default_stats_manager_factory);
87    factory.create()
88}
89
90fn get_default_stats_manager_factory() -> Box<dyn StatsManagerFactory + Send + Sync> {
91    #[cfg(fbcode_build)]
92    {
93        Box::new(::stats_facebook::ThreadLocalStatsFactory)
94    }
95    #[cfg(not(fbcode_build))]
96    {
97        Box::new(crate::noop_stats::NoopStatsFactory)
98    }
99}
100
101#[doc(hidden)]
102/// You probably don't have to use this function, it is made public so that it
103/// might be used by the macros in this crate. It creates a new SingletonCounter.
104pub fn create_singleton_counter(name: String) -> BoxSingletonCounter {
105    #[cfg(fbcode_build)]
106    {
107        Box::new(::stats_facebook::singleton_counter::ServiceDataSingletonCounter::new(name))
108    }
109
110    #[cfg(not(fbcode_build))]
111    {
112        let _ = name;
113        Box::new(crate::noop_stats::Noop)
114    }
115}