use std::any::Any;
use std::borrow::Cow;
macro_rules! used_in_docs {
($($item:ident),* $(,)?) => {
const _: () = {
#[allow(unused_imports)]
mod _docs {
$( use super::$item; )*
}
};
};
}
pub mod dynmetrics;
mod formatter;
mod metadata;
mod metrics;
mod null;
mod provide;
mod traits;
mod wrapper;
pub use crate::formatter::{default_formatter, Format};
pub use crate::metadata::{Metadata, MetadataIter};
pub use crate::metrics::{metrics, DynMetricsIter, Metrics, MetricsIter};
pub use crate::provide::{request_ref, request_value, Request};
pub use crate::traits::{
CounterGroupMetric, GaugeGroupMetric, HistogramGroupMetric, HistogramMetric,
};
pub trait Metric: Send + Sync + 'static {
fn is_enabled(&self) -> bool {
self.as_any().is_some()
}
fn as_any(&self) -> Option<&dyn Any>;
fn value(&self) -> Option<Value<'_>>;
fn provide<'a>(&'a self, request: &mut Request<'a>) {
let _ = request;
}
}
#[non_exhaustive]
pub enum Value<'a> {
Counter(u64),
Gauge(i64),
Histogram(&'a dyn HistogramMetric),
CounterGroup(&'a dyn CounterGroupMetric),
GaugeGroup(&'a dyn GaugeGroupMetric),
HistogramGroup(&'a dyn HistogramGroupMetric),
Other(&'a dyn Any),
}
pub struct MetricEntry {
metric: *const dyn Metric,
name: Cow<'static, str>,
description: Option<Cow<'static, str>>,
}
impl MetricEntry {
pub fn metric(&self) -> &dyn Metric {
unsafe { &*self.metric }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn metadata(&self) -> &Metadata {
static EMPTY: Metadata = Metadata::default_const();
self.request_ref::<Metadata>().unwrap_or(&EMPTY)
}
pub fn formatted(&self, format: Format) -> String {
let formatter = self
.request_value::<crate::wrapper::FormattingFn>()
.map(|func| func.0)
.unwrap_or(crate::default_formatter);
formatter(self, format)
}
pub fn is(&self, metric: &dyn Metric) -> bool {
if self.metric().type_id() != metric.type_id() {
return false;
}
let a = self.metric() as *const _ as *const ();
let b = metric as *const _ as *const ();
a == b
}
pub fn request_value<T>(&self) -> Option<T>
where
T: 'static,
{
crate::request_value(self.metric())
}
pub fn request_ref<T>(&self) -> Option<&T>
where
T: ?Sized + 'static,
{
crate::request_ref(self.metric())
}
}
unsafe impl Send for MetricEntry {}
unsafe impl Sync for MetricEntry {}
impl std::ops::Deref for MetricEntry {
type Target = dyn Metric;
#[inline]
fn deref(&self) -> &Self::Target {
self.metric()
}
}
impl std::fmt::Debug for MetricEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MetricEntry")
.field("name", &self.name())
.field("metric", &"<dyn Metric>")
.finish()
}
}
#[doc(hidden)]
pub mod export {
use crate::{Metadata, Metric};
pub extern crate linkme;
pub extern crate phf;
pub use crate::wrapper::*;
#[linkme::distributed_slice]
pub static METRICS: [crate::MetricEntry] = [..];
pub const fn entry_v1(
metric: &'static dyn Metric,
name: &'static str,
description: Option<&'static str>,
) -> crate::MetricEntry {
use std::borrow::Cow;
crate::MetricEntry {
metric,
name: Cow::Borrowed(name),
description: match description {
Some(desc) => Some(Cow::Borrowed(desc)),
None => None,
},
}
}
pub const fn metadata(metadata: &'static phf::Map<&'static str, &'static str>) -> Metadata {
Metadata::new_static(metadata)
}
}
#[macro_export]
macro_rules! declare_metric_v1 {
{
metric: $metric:expr,
name: $name:expr,
description: $description:expr,
metadata: { $( $key:expr => $value:expr ),* $(,)? },
formatter: $formatter:expr $(,)?
} => {
const _: () = {
use $crate::export::phf;
static __METADATA_MAP: $crate::export::phf::Map<&'static str, &'static str> =
$crate::export::phf::phf_map! { $( $key => $value, )* };
static __METADATA: $crate::Metadata = $crate::export::metadata(&__METADATA_MAP);
struct MetricProvider;
impl $crate::export::InjectedProvider for MetricProvider {
fn provide(request: &mut $crate::Request<'_>) {
request
.provide_ref(&__METADATA)
.provide_value($crate::export::FormattingFn($formatter));
}
}
#[$crate::export::linkme::distributed_slice($crate::export::METRICS)]
#[linkme(crate = $crate::export::linkme)]
static __ENTRY: $crate::MetricEntry = $crate::export::entry_v1(
$crate::export::MetricWrapper::<_, MetricProvider>::from_ref(&$metric),
$name,
$description,
);
};
}
}