Skip to content

Commit

Permalink
Replace linkme with ctor
Browse files Browse the repository at this point in the history
  • Loading branch information
slowli committed Aug 7, 2024
1 parent a5bb80c commit 12baecc
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 31 deletions.
32 changes: 11 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 4 additions & 3 deletions crates/vise-macros/src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ fn register_static(input: &mut ItemStatic) -> syn::Result<proc_macro2::TokenStre

Ok(quote! {
const _: () = {
#[#cr::_reexports::linkme::distributed_slice(#cr::METRICS_REGISTRATIONS)]
#[linkme(crate = #cr::_reexports::linkme)]
static __REGISTRATION: &'static dyn #cr::CollectToRegistry = &#name;
#[#cr::_reexports::ctor]
fn register_metric() {
#cr::METRICS_REGISTRATIONS.push(&#name);
}
};
})
}
Expand Down
2 changes: 1 addition & 1 deletion crates/vise/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ vise-macros = { version = "0.1.0", path = "../vise-macros" }

compile-fmt.workspace = true
elsa.workspace = true
linkme.workspace = true
ctor.workspace = true
once_cell.workspace = true
prometheus-client.workspace = true

Expand Down
2 changes: 1 addition & 1 deletion crates/vise/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ pub use vise_macros::register;

#[doc(hidden)] // only used by the proc macros
pub mod _reexports {
pub use linkme;
pub use ctor::ctor;
pub use prometheus_client::{encoding, metrics::TypedMetric};
}

Expand Down
46 changes: 42 additions & 4 deletions crates/vise/src/registry.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Wrapper around metrics registry.
use linkme::distributed_slice;
use prometheus_client::{
encoding::{text, DescriptorEncoder},
registry::{Metric, Registry as RegistryInner, Unit},
};

use std::sync::Mutex;
use std::{collections::HashMap, fmt};

use crate::{
Expand Down Expand Up @@ -129,10 +129,11 @@ impl<F: FnMut(&MetricGroupDescriptor) -> bool> MetricsCollection<F> {
/// 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);
}
Expand Down Expand Up @@ -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<Vec<&'static dyn CollectToRegistry>>,
}

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();

0 comments on commit 12baecc

Please sign in to comment.