use std::marker::PhantomData; use measured::label::NoLabels; use measured::metric::gauge::GaugeState; use measured::metric::group::Encoding; use measured::metric::name::MetricNameEncoder; use measured::metric::{MetricEncoding, MetricFamilyEncoding, MetricType}; use measured::text::TextEncoder; use measured::{LabelGroup, MetricGroup}; use tikv_jemalloc_ctl::{config, epoch, epoch_mib, stats, version}; pub struct MetricRecorder { epoch: epoch_mib, inner: Metrics, } #[derive(MetricGroup)] struct Metrics { active_bytes: JemallocGaugeFamily, allocated_bytes: JemallocGaugeFamily, mapped_bytes: JemallocGaugeFamily, metadata_bytes: JemallocGaugeFamily, resident_bytes: JemallocGaugeFamily, retained_bytes: JemallocGaugeFamily, } impl MetricGroup for MetricRecorder where Metrics: MetricGroup, { fn collect_group_into(&self, enc: &mut Enc) -> Result<(), Enc::Err> { if self.epoch.advance().is_ok() { self.inner.collect_group_into(enc)?; } Ok(()) } } impl MetricRecorder { pub fn new() -> Result { tracing::debug!( config = config::malloc_conf::read()?, version = version::read()?, "starting jemalloc recorder" ); Ok(Self { epoch: epoch::mib()?, inner: Metrics { active_bytes: JemallocGaugeFamily(stats::active::mib()?), allocated_bytes: JemallocGaugeFamily(stats::allocated::mib()?), mapped_bytes: JemallocGaugeFamily(stats::mapped::mib()?), metadata_bytes: JemallocGaugeFamily(stats::metadata::mib()?), resident_bytes: JemallocGaugeFamily(stats::resident::mib()?), retained_bytes: JemallocGaugeFamily(stats::retained::mib()?), }, }) } } struct JemallocGauge(PhantomData); impl Default for JemallocGauge { fn default() -> Self { JemallocGauge(PhantomData) } } impl MetricType for JemallocGauge { type Metadata = T; } struct JemallocGaugeFamily(T); impl MetricFamilyEncoding for JemallocGaugeFamily where JemallocGauge: MetricEncoding, { fn collect_family_into(&self, name: impl MetricNameEncoder, enc: &mut T) -> Result<(), T::Err> { JemallocGauge::write_type(&name, enc)?; JemallocGauge(PhantomData).collect_into(&self.0, NoLabels, name, enc) } } macro_rules! jemalloc_gauge { ($stat:ident, $mib:ident) => { impl MetricEncoding> for JemallocGauge { fn write_type( name: impl MetricNameEncoder, enc: &mut TextEncoder, ) -> Result<(), std::io::Error> { GaugeState::write_type(name, enc) } fn collect_into( &self, mib: &stats::$mib, labels: impl LabelGroup, name: impl MetricNameEncoder, enc: &mut TextEncoder, ) -> Result<(), std::io::Error> { if let Ok(v) = mib.read() { GaugeState::new(v as i64).collect_into(&(), labels, name, enc)?; } Ok(()) } } }; } jemalloc_gauge!(active, active_mib); jemalloc_gauge!(allocated, allocated_mib); jemalloc_gauge!(mapped, mapped_mib); jemalloc_gauge!(metadata, metadata_mib); jemalloc_gauge!(resident, resident_mib); jemalloc_gauge!(retained, retained_mib);