diff --git a/Cargo.lock b/Cargo.lock index 51264d8..a70acbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,6 +156,16 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "ctor" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +dependencies = [ + "quote", + "syn 2.0.58", +] + [[package]] name = "deranged" version = "0.3.11" @@ -542,26 +552,6 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "linkme" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2cfee0de9bd869589fb9a015e155946d1be5ff415cb844c2caccc6cc4b5db9" -dependencies = [ - "linkme-impl", -] - -[[package]] -name = "linkme-impl" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf157a4dc5a29b7b464aa8fe7edeff30076e07e13646a1c3874f58477dc99f8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.58", -] - [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -1705,10 +1695,10 @@ version = "0.1.0" dependencies = [ "assert_matches", "compile-fmt", + "ctor", "derive_more", "doc-comment", "elsa", - "linkme", "once_cell", "prometheus-client", "rand", diff --git a/Cargo.toml b/Cargo.toml index 4f26ce4..e6f84a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ derive_more = "0.99.17" doc-comment = "0.3.3" elsa = "1.9.0" hyper = { version = "0.14", features = ["client", "server", "http1", "tcp"] } -linkme = "0.3.15" +ctor = "0.2.8" metrics = "0.21" metrics-exporter-prometheus = { version = "0.12", default-features = false } once_cell = "1.17" diff --git a/crates/vise-macros/src/register.rs b/crates/vise-macros/src/register.rs index 9b49d07..134f713 100644 --- a/crates/vise-macros/src/register.rs +++ b/crates/vise-macros/src/register.rs @@ -53,9 +53,10 @@ fn register_static(input: &mut ItemStatic) -> syn::Result bool> MetricsCollection { /// Creates a registry with all [`register`](crate::register)ed [`Global`] metrics /// and [`Collector`]s. If a filtering predicate [was provided](MetricsCollection::filter()), /// only metrics satisfying this function will be collected. + #[allow(clippy::missing_panics_doc)] pub fn collect(mut self) -> Registry { let mut registry = Registry::empty(); registry.is_lazy = self.is_lazy; - for metric in METRICS_REGISTRATIONS { + for metric in METRICS_REGISTRATIONS.get() { if (self.filter_fn)(metric.descriptor()) { metric.collect_to_registry(&mut registry); } @@ -353,6 +354,43 @@ pub trait CollectToRegistry: 'static + Send + Sync { fn collect_to_registry(&'static self, registry: &mut Registry); } +// Intentionally not re-exported; used by the proc macros +pub struct MetricsRegistrations { + inner: Mutex>, +} + +impl fmt::Debug for MetricsRegistrations { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Ok(metrics) = self.inner.lock() { + let descriptors = metrics.iter().map(|metrics| metrics.descriptor()); + formatter.debug_list().entries(descriptors).finish() + } else { + formatter + .debug_tuple("MetricsRegistrations") + .field(&"poisoned") + .finish() + } + } +} + +impl MetricsRegistrations { + const fn new() -> Self { + Self { + inner: Mutex::new(Vec::new()), + } + } + + // Only called by the `register` proc macro before main. `unwrap()` isn't expected to panic (panicking before main could lead to UB) + // since it's just pushing a value into a `Vec`. If this becomes a concern, we could rework `MetricsRegistrations` + // to use a lock-free linked list as in `inventory`: https://github.com/dtolnay/inventory/blob/f15e000224ca5d873097d406287bf79905f12c35/src/lib.rs#L190 + pub fn push(&self, metrics: &'static dyn CollectToRegistry) { + self.inner.lock().unwrap().push(metrics); + } + + fn get(&self) -> Vec<&'static dyn CollectToRegistry> { + self.inner.lock().unwrap().clone() + } +} + #[doc(hidden)] // only used by the proc macros -#[distributed_slice] -pub static METRICS_REGISTRATIONS: [&'static dyn CollectToRegistry] = [..]; +pub static METRICS_REGISTRATIONS: MetricsRegistrations = MetricsRegistrations::new();