1use std::sync::Arc;
22
23#[doc(hidden)]
27pub use prometheus;
28pub use prometheus::{
30 DEFAULT_BUCKETS, Encoder, Error, HistogramOpts, Opts, PROTOBUF_FORMAT, ProtobufEncoder, Result,
31 TextEncoder, exponential_buckets, gather, histogram_opts, linear_buckets, opts, proto,
32};
33use tracing::warn;
34
35pub mod core {
47 use std::mem::ManuallyDrop;
48
49 pub use prometheus::core::{
50 Atomic, AtomicF64, AtomicI64, AtomicU64, Collector, Desc, Describer, Metric,
51 MetricVecBuilder, Number,
52 };
53
54 macro_rules! impl_generic_metric_traits {
55 ($T:ident) => {
56 impl<P: Atomic> Clone for $T<P> {
57 fn clone(&self) -> Self {
58 Self(self.0.clone())
59 }
60 }
61
62 impl<P: Atomic> std::fmt::Debug for $T<P> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(f, "{}", stringify!($T))?;
65 if self.0.is_none() {
66 write!(f, "(disabled)")?;
67 }
68 Ok(())
69 }
70 }
71
72 impl<P: Atomic> prometheus::core::Collector for $T<P> {
73 fn desc(&self) -> Vec<&Desc> {
74 self.0
75 .as_ref()
76 .map(|inner| inner.desc())
77 .unwrap_or_default()
78 }
79
80 fn collect(&self) -> Vec<prometheus::proto::MetricFamily> {
81 self.0
82 .as_ref()
83 .map(|inner| inner.collect())
84 .unwrap_or_default()
85 }
86 }
87 };
88 }
89
90 macro_rules! impl_metric_traits {
91 ($T:ident) => {
92 impl Clone for $T {
93 fn clone(&self) -> Self {
94 Self(self.0.clone())
95 }
96 }
97
98 impl std::fmt::Debug for $T {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 write!(f, "{}", stringify!($T))?;
101 if self.0.is_none() {
102 write!(f, "(disabled)")?;
103 }
104 Ok(())
105 }
106 }
107
108 impl prometheus::core::Collector for $T {
109 fn desc(&self) -> Vec<&Desc> {
110 self.0
111 .as_ref()
112 .map(|inner| inner.desc())
113 .unwrap_or_default()
114 }
115
116 fn collect(&self) -> Vec<prometheus::proto::MetricFamily> {
117 self.0
118 .as_ref()
119 .map(|inner| inner.collect())
120 .unwrap_or_default()
121 }
122 }
123 };
124 }
125
126 macro_rules! impl_generic_metric_vec {
127 ($T:ident, $M:ident) => {
128 impl<P: Atomic> $T<P> {
129 pub fn new_some(inner: prometheus::core::$T<P>) -> Self {
130 Self(Some(inner))
131 }
132
133 pub fn new_none() -> Self {
134 Self(None)
135 }
136
137 #[inline]
138 pub fn with_label_values<V>(&self, vals: &[V]) -> $M<P>
139 where
140 V: AsRef<str> + std::fmt::Debug,
141 {
142 $M::<P>(self.0.as_ref().map(|inner| inner.with_label_values(vals)))
143 }
144
145 #[inline]
146 pub fn remove_label_values<V>(&self, vals: &[V]) -> super::Result<()>
147 where
148 V: AsRef<str> + std::fmt::Debug,
149 {
150 self.0
151 .as_ref()
152 .map(|inner| inner.remove_label_values(vals))
153 .unwrap_or(Ok(()))
154 }
155
156 #[inline]
157 pub fn get_metric_with<V, S: std::hash::BuildHasher>(
158 &self,
159 labels: &std::collections::HashMap<&str, V, S>,
160 ) -> super::Result<$M<P>>
161 where
162 V: AsRef<str> + std::fmt::Debug,
163 {
164 self.0
165 .as_ref()
166 .map(|inner| inner.get_metric_with(labels).map($M::<P>::new_some))
167 .unwrap_or(Ok($M::<P>::new_none()))
168 }
169
170 #[inline]
171 pub fn get_metric_with_label_values<V>(&self, vals: &[V]) -> super::Result<$M<P>>
172 where
173 V: AsRef<str> + std::fmt::Debug,
174 {
175 self.0
176 .as_ref()
177 .map(|inner| {
178 inner
179 .get_metric_with_label_values(vals)
180 .map($M::<P>::new_some)
181 })
182 .unwrap_or(Ok($M::<P>::new_none()))
183 }
184
185 #[inline]
186 pub fn reset(&self) {
187 if let Some(v) = &self.0 {
188 v.reset();
189 }
190 }
191 }
192 };
193 }
194
195 pub struct GenericCounter<P: Atomic>(Option<prometheus::core::GenericCounter<P>>);
196
197 impl<P: Atomic> GenericCounter<P> {
198 pub fn new_some(inner: prometheus::core::GenericCounter<P>) -> Self {
199 Self(Some(inner))
200 }
201
202 pub fn new_none() -> Self {
203 Self(None)
204 }
205
206 pub fn new(name: &str, help: &str) -> prometheus::Result<Self> {
207 prometheus::core::GenericCounter::new(name, help).map(Self::new_some)
208 }
209
210 pub fn with_opts(opts: super::Opts) -> super::Result<Self> {
211 prometheus::core::GenericCounter::with_opts(opts).map(Self::new_some)
212 }
213
214 #[inline]
215 pub fn get(&self) -> P::T {
216 self.0
217 .as_ref()
218 .map(|inner| inner.get())
219 .unwrap_or(<P::T>::from_i64(0))
220 }
221
222 #[inline]
223 pub fn inc(&self) {
224 if let Some(inner) = &self.0 {
225 inner.inc();
226 }
227 }
228
229 #[inline]
230 pub fn inc_by(&self, v: <P as Atomic>::T) {
231 if let Some(inner) = &self.0 {
232 inner.inc_by(v);
233 }
234 }
235
236 #[inline]
237 pub fn reset(&self) {
238 if let Some(inner) = &self.0 {
239 inner.reset();
240 }
241 }
242 }
243
244 impl_generic_metric_traits!(GenericCounter);
245
246 pub struct GenericGauge<P: Atomic>(Option<prometheus::core::GenericGauge<P>>);
247
248 impl<P: Atomic> GenericGauge<P> {
249 pub fn new_some(inner: prometheus::core::GenericGauge<P>) -> Self {
250 Self(Some(inner))
251 }
252
253 pub fn new_none() -> Self {
254 Self(None)
255 }
256
257 pub fn new(name: &str, help: &str) -> super::Result<Self> {
258 prometheus::core::GenericGauge::new(name, help).map(Self::new_some)
259 }
260
261 pub fn with_opts(opts: super::Opts) -> super::Result<Self> {
262 prometheus::core::GenericGauge::with_opts(opts).map(Self::new_some)
263 }
264
265 #[inline]
266 pub fn get(&self) -> P::T {
267 self.0
268 .as_ref()
269 .map(|inner| inner.get())
270 .unwrap_or(<P::T>::from_i64(0))
271 }
272
273 #[inline]
274 pub fn set(&self, v: P::T) {
275 if let Some(inner) = &self.0 {
276 inner.set(v);
277 }
278 }
279
280 #[inline]
281 pub fn inc(&self) {
282 if let Some(inner) = &self.0 {
283 inner.inc();
284 }
285 }
286
287 #[inline]
288 pub fn dec(&self) {
289 if let Some(inner) = &self.0 {
290 inner.dec();
291 }
292 }
293
294 #[inline]
295 pub fn add(&self, v: P::T) {
296 if let Some(inner) = &self.0 {
297 inner.add(v);
298 }
299 }
300
301 #[inline]
302 pub fn sub(&self, v: P::T) {
303 if let Some(inner) = &self.0 {
304 inner.sub(v);
305 }
306 }
307 }
308
309 impl_generic_metric_traits!(GenericGauge);
310
311 pub struct GenericCounterVec<P: Atomic>(Option<prometheus::core::GenericCounterVec<P>>);
312
313 impl_generic_metric_traits!(GenericCounterVec);
314 impl_generic_metric_vec!(GenericCounterVec, GenericCounter);
315
316 pub struct GenericGaugeVec<P: Atomic>(Option<prometheus::core::GenericGaugeVec<P>>);
317
318 impl_generic_metric_traits!(GenericGaugeVec);
319 impl_generic_metric_vec!(GenericGaugeVec, GenericGauge);
320
321 pub struct Histogram(Option<prometheus::Histogram>);
322
323 impl_metric_traits!(Histogram);
324
325 impl Histogram {
326 pub fn new_some(inner: prometheus::Histogram) -> Self {
327 Self(Some(inner))
328 }
329
330 pub fn new_none() -> Self {
331 Self(None)
332 }
333
334 pub fn with_opts(opts: prometheus::HistogramOpts) -> prometheus::Result<Self> {
335 prometheus::Histogram::with_opts(opts).map(|h| Self(Some(h)))
336 }
337
338 #[inline]
339 pub fn observe(&self, v: f64) {
340 if let Some(h) = &self.0 {
341 h.observe(v);
342 }
343 }
344
345 #[inline]
346 pub fn start_timer(&self) -> HistogramTimer {
347 HistogramTimer(self.0.as_ref().map(|h| h.start_timer()))
348 }
349
350 #[inline]
351 pub fn get_sample_count(&self) -> u64 {
352 self.0.as_ref().map_or(0, |h| h.get_sample_count())
353 }
354
355 #[inline]
356 pub fn get_sample_sum(&self) -> f64 {
357 self.0.as_ref().map_or(0.0, |h| h.get_sample_sum())
358 }
359 }
360
361 pub struct HistogramTimer(Option<prometheus::HistogramTimer>);
362
363 impl std::fmt::Debug for HistogramTimer {
364 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365 write!(f, "HistogramTimer")?;
366 if self.0.is_none() {
367 write!(f, "(disabled)")?;
368 }
369 Ok(())
370 }
371 }
372
373 impl Drop for HistogramTimer {
374 fn drop(&mut self) {
375 drop(self.0.take());
377 }
378 }
379
380 impl HistogramTimer {
381 #[inline]
384 pub fn stop_and_record(self) -> f64 {
385 let mut wrapper = ManuallyDrop::new(self);
388 wrapper
389 .0
390 .take()
391 .map(|t| t.stop_and_record())
392 .unwrap_or_default()
393 }
394
395 #[inline]
398 pub fn observe_duration(self) {
399 let _ = self.stop_and_record();
400 }
401
402 #[inline]
404 pub fn stop_and_discard(self) -> f64 {
405 let mut wrapper = ManuallyDrop::new(self);
406 wrapper
407 .0
408 .take()
409 .map(|t| t.stop_and_discard())
410 .unwrap_or_default()
411 }
412 }
413
414 pub struct HistogramVec(Option<prometheus::HistogramVec>);
415
416 impl_metric_traits!(HistogramVec);
417
418 impl HistogramVec {
419 pub fn new_some(inner: prometheus::HistogramVec) -> Self {
420 Self(Some(inner))
421 }
422
423 pub fn new_none() -> Self {
424 Self(None)
425 }
426
427 #[inline]
428 pub fn with_label_values(&self, vals: &[&str]) -> Histogram {
429 Histogram(self.0.as_ref().map(|v| v.with_label_values(vals)))
430 }
431
432 #[inline]
433 pub fn remove_label_values(&self, vals: &[&str]) -> prometheus::Result<()> {
434 match &self.0 {
435 Some(v) => v.remove_label_values(vals),
436 None => Ok(()),
437 }
438 }
439 }
440}
441
442pub type Counter = core::GenericCounter<prometheus::core::AtomicF64>;
443pub type IntCounter = core::GenericCounter<prometheus::core::AtomicU64>;
444pub type Gauge = core::GenericGauge<prometheus::core::AtomicF64>;
445pub type IntGauge = core::GenericGauge<prometheus::core::AtomicI64>;
446
447pub type CounterVec = core::GenericCounterVec<prometheus::core::AtomicF64>;
448pub type IntCounterVec = core::GenericCounterVec<prometheus::core::AtomicU64>;
449pub type GaugeVec = core::GenericGaugeVec<prometheus::core::AtomicF64>;
450pub type IntGaugeVec = core::GenericGaugeVec<prometheus::core::AtomicI64>;
451
452pub use core::{Histogram, HistogramTimer, HistogramVec};
453
454struct FilterDirective {
459 pattern: String,
461 enabled: bool,
462}
463
464#[derive(Default)]
471pub struct Filter {
472 directives: Vec<FilterDirective>,
473}
474
475impl Filter {
476 fn parse(s: &str) -> Self {
477 let directives = s
478 .split(',')
479 .filter_map(|part| {
480 let part = part.trim();
481 if part.is_empty() {
482 None
483 } else {
484 let (pattern, enabled) = if let Some(eq) = part.rfind('=') {
485 (part[..eq].trim().to_owned(), part[eq + 1..].trim())
486 } else {
487 (String::new(), part)
488 };
489 match enabled {
490 "on" | "true" | "1" => Some(true),
491 "off" | "false" | "0" => Some(false),
492 other => {
493 warn!("invalid prometheus filter value {other:?} in {part:?}");
494 None
495 }
496 }
497 .map(|enabled| FilterDirective { pattern, enabled })
498 }
499 })
500 .collect();
501 Self { directives }
502 }
503
504 fn from_env() -> Self {
505 std::env::var("METRICS_FILTER")
506 .ok()
507 .map(|s| Self::parse(&s))
508 .unwrap_or_default()
509 }
510
511 #[inline]
520 pub fn is_enabled(&self, name: &str, module: &str) -> bool {
521 let mut result = true;
522 for dir in &self.directives {
523 if dir.pattern.is_empty()
524 || name.starts_with(dir.pattern.as_str())
525 || module.starts_with(dir.pattern.as_str())
526 || module.contains(&format!("::{}", dir.pattern))
527 {
528 result = dir.enabled;
529 }
530 }
531 result
532 }
533}
534
535#[derive(Clone)]
543pub struct Registry {
544 inner: prometheus::Registry,
545 filter: Arc<Filter>,
546}
547
548impl Registry {
549 pub fn new() -> Self {
551 Self {
552 inner: prometheus::Registry::new(),
553 filter: Arc::new(Filter::from_env()),
554 }
555 }
556
557 pub fn new_custom(
560 prefix: Option<String>,
561 labels: Option<std::collections::HashMap<String, String>>,
562 ) -> prometheus::Result<Self> {
563 Ok(Self {
564 inner: prometheus::Registry::new_custom(prefix, labels)?,
565 filter: Arc::new(Filter::from_env()),
566 })
567 }
568
569 pub fn with_filter(filter_str: &str) -> Self {
571 Self {
572 inner: prometheus::Registry::new(),
573 filter: Arc::new(Filter::parse(filter_str)),
574 }
575 }
576
577 #[inline]
579 pub fn is_enabled(&self, name: &str, module: &str) -> bool {
580 self.filter.is_enabled(name, module)
581 }
582
583 #[inline]
586 pub fn inner(&self) -> &prometheus::Registry {
587 &self.inner
588 }
589
590 pub fn register(&self, c: Box<dyn prometheus::core::Collector>) -> prometheus::Result<()> {
591 self.inner.register(c)
592 }
593
594 pub fn unregister(&self, c: Box<dyn prometheus::core::Collector>) -> prometheus::Result<()> {
595 self.inner.unregister(c)
596 }
597
598 pub fn gather(&self) -> Vec<prometheus::proto::MetricFamily> {
599 self.inner.gather()
600 }
601}
602
603impl Default for Registry {
604 fn default() -> Self {
605 Self::new()
606 }
607}
608
609impl std::fmt::Debug for Registry {
610 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
611 f.debug_struct("Registry").finish_non_exhaustive()
612 }
613}
614
615pub fn default_filter() -> &'static Arc<Filter> {
621 use std::sync::OnceLock;
622 static INSTANCE: OnceLock<Arc<Filter>> = OnceLock::new();
623 INSTANCE.get_or_init(|| Arc::new(Filter::from_env()))
624}
625
626pub fn default_registry() -> &'static Registry {
630 use std::sync::OnceLock;
631 static INSTANCE: OnceLock<Registry> = OnceLock::new();
632 INSTANCE.get_or_init(|| Registry {
633 inner: prometheus::default_registry().clone(),
634 filter: default_filter().clone(),
635 })
636}
637
638#[macro_export]
657macro_rules! register_int_counter_with_registry {
658 ($name:expr, $help:expr, $registry:expr $(,)?) => {{
659 let _n = $name;
660 let name: &str = &*_n;
661 let module: &str = module_path!();
662 if ($registry).is_enabled(name, module) {
663 $crate::prometheus::register_int_counter_with_registry!(
664 name,
665 $help,
666 ($registry).inner()
667 )
668 .map($crate::core::GenericCounter::new_some)
669 } else {
670 ::std::result::Result::Ok($crate::core::GenericCounter::new_none())
671 }
672 }};
673}
674
675#[macro_export]
677macro_rules! register_int_counter_vec_with_registry {
678 ($name:expr, $help:expr, $labels:expr, $registry:expr $(,)?) => {{
679 let _n = $name;
680 let name: &str = &*_n;
681 let module: &str = module_path!();
682 if ($registry).is_enabled(name, module) {
683 $crate::prometheus::register_int_counter_vec_with_registry!(
684 name,
685 $help,
686 $labels,
687 ($registry).inner()
688 )
689 .map($crate::IntCounterVec::new_some)
690 } else {
691 ::std::result::Result::Ok($crate::IntCounterVec::new_none())
692 }
693 }};
694}
695
696#[macro_export]
698macro_rules! register_int_gauge_with_registry {
699 ($name:expr, $help:expr, $registry:expr $(,)?) => {{
700 let _n = $name;
701 let name: &str = &*_n;
702 let module: &str = module_path!();
703 if ($registry).is_enabled(name, module) {
704 $crate::prometheus::register_int_gauge_with_registry!(name, $help, ($registry).inner())
705 .map($crate::core::GenericGauge::new_some)
706 } else {
707 ::std::result::Result::Ok($crate::core::GenericGauge::new_none())
708 }
709 }};
710}
711
712#[macro_export]
714macro_rules! register_int_gauge_vec_with_registry {
715 ($name:expr, $help:expr, $labels:expr, $registry:expr $(,)?) => {{
716 let _n = $name;
717 let name: &str = &*_n;
718 let module: &str = module_path!();
719 if ($registry).is_enabled(name, module) {
720 $crate::prometheus::register_int_gauge_vec_with_registry!(
721 name,
722 $help,
723 $labels,
724 ($registry).inner()
725 )
726 .map($crate::IntGaugeVec::new_some)
727 } else {
728 ::std::result::Result::Ok($crate::IntGaugeVec::new_none())
729 }
730 }};
731}
732
733#[macro_export]
736macro_rules! register_histogram_with_registry {
737 ($name:expr, $help:expr, $registry:expr $(,)?) => {{
738 let _n = $name;
739 let name: &str = &*_n;
740 let module: &str = module_path!();
741 if ($registry).is_enabled(name, module) {
742 $crate::prometheus::register_histogram_with_registry!(name, $help, ($registry).inner())
743 .map($crate::Histogram::new_some)
744 } else {
745 ::std::result::Result::Ok($crate::Histogram::new_none())
746 }
747 }};
748 ($name:expr, $help:expr, $buckets:expr, $registry:expr $(,)?) => {{
749 let _n = $name;
750 let name: &str = &*_n;
751 let module: &str = module_path!();
752 if ($registry).is_enabled(name, module) {
753 $crate::prometheus::register_histogram_with_registry!(
754 name,
755 $help,
756 $buckets,
757 ($registry).inner()
758 )
759 .map($crate::Histogram::new_some)
760 } else {
761 ::std::result::Result::Ok($crate::Histogram::new_none())
762 }
763 }};
764}
765
766#[macro_export]
769macro_rules! register_histogram_vec_with_registry {
770 ($name:expr, $help:expr, $labels:expr, $registry:expr $(,)?) => {{
771 let _n = $name;
772 let name: &str = &*_n;
773 let module: &str = module_path!();
774 if ($registry).is_enabled(name, module) {
775 $crate::prometheus::register_histogram_vec_with_registry!(
776 name,
777 $help,
778 $labels,
779 ($registry).inner()
780 )
781 .map($crate::HistogramVec::new_some)
782 } else {
783 ::std::result::Result::Ok($crate::HistogramVec::new_none())
784 }
785 }};
786 ($name:expr, $help:expr, $labels:expr, $buckets:expr, $registry:expr $(,)?) => {{
787 let _n = $name;
788 let name: &str = &*_n;
789 let module: &str = module_path!();
790 if ($registry).is_enabled(name, module) {
791 $crate::prometheus::register_histogram_vec_with_registry!(
792 name,
793 $help,
794 $labels,
795 $buckets,
796 ($registry).inner()
797 )
798 .map($crate::HistogramVec::new_some)
799 } else {
800 ::std::result::Result::Ok($crate::HistogramVec::new_none())
801 }
802 }};
803}
804
805#[macro_export]
807macro_rules! register_gauge_vec_with_registry {
808 ($name:expr, $help:expr, $labels:expr, $registry:expr $(,)?) => {{
809 let _n = $name;
810 let name: &str = &*_n;
811 let module: &str = module_path!();
812 if ($registry).is_enabled(name, module) {
813 $crate::prometheus::register_gauge_vec_with_registry!(
814 name,
815 $help,
816 $labels,
817 ($registry).inner()
818 )
819 .map($crate::core::GenericGaugeVec::new_some)
820 } else {
821 ::std::result::Result::Ok($crate::core::GenericGaugeVec::new_none())
822 }
823 }};
824}
825
826#[macro_export]
828macro_rules! register_gauge_with_registry {
829 ($name:expr, $help:expr, $registry:expr $(,)?) => {{
830 let _n = $name;
831 let name: &str = &*_n;
832 let module: &str = module_path!();
833 if ($registry).is_enabled(name, module) {
834 $crate::prometheus::register_gauge_with_registry!(name, $help, ($registry).inner())
835 .map($crate::core::GenericGauge::new_some)
836 } else {
837 ::std::result::Result::Ok($crate::core::GenericGauge::new_none())
838 }
839 }};
840}
841
842#[macro_export]
844macro_rules! register_counter {
845 ($name:expr, $help:expr $(,)?) => {{
846 let _n = $name;
847 let name: &str = &*_n;
848 let module: &str = module_path!();
849 if $crate::default_filter().is_enabled(name, module) {
850 $crate::prometheus::register_counter!(name, $help)
851 .map($crate::core::GenericCounter::new_some)
852 } else {
853 ::std::result::Result::Ok($crate::core::GenericCounter::new_none())
854 }
855 }};
856}
857
858#[macro_export]
860macro_rules! register_counter_vec_with_registry {
861 ($name:expr, $help:expr, $labels:expr, $registry:expr $(,)?) => {{
862 let _n = $name;
863 let name: &str = &*_n;
864 let module: &str = module_path!();
865 if ($registry).is_enabled(name, module) {
866 $crate::prometheus::register_counter_vec_with_registry!(
867 name,
868 $help,
869 $labels,
870 ($registry).inner()
871 )
872 .map($crate::core::GenericCounterVec::new_some)
873 } else {
874 ::std::result::Result::Ok($crate::core::GenericCounterVec::new_none())
875 }
876 }};
877}
878
879#[macro_export]
881macro_rules! register_counter_vec {
882 ($name:expr, $help:expr, $labels:expr $(,)?) => {{
883 let _n = $name;
884 let name: &str = &*_n;
885 let module: &str = module_path!();
886 if $crate::default_filter().is_enabled(name, module) {
887 $crate::prometheus::register_counter_vec!(name, $help, $labels)
888 .map($crate::core::GenericCounterVec::new_some)
889 } else {
890 ::std::result::Result::Ok($crate::core::GenericCounterVec::new_none())
891 }
892 }};
893}
894
895#[macro_export]
898macro_rules! register_histogram_vec {
899 ($opts:expr, $labels:expr $(,)?) => {{
900 let opts = $opts;
901 let name: &str = &opts.common_opts.name;
902 let module: &str = module_path!();
903 if $crate::default_filter().is_enabled(name, module) {
904 $crate::prometheus::register_histogram_vec!(opts, $labels)
905 .map($crate::HistogramVec::new_some)
906 } else {
907 ::std::result::Result::Ok($crate::HistogramVec::new_none())
908 }
909 }};
910 ($name:expr, $help:expr, $labels:expr $(,)?) => {{
911 let _n = $name;
912 let name: &str = &*_n;
913 let module: &str = module_path!();
914 if $crate::default_filter().is_enabled(name, module) {
915 $crate::prometheus::register_histogram_vec!(name, $help, $labels)
916 .map($crate::HistogramVec::new_some)
917 } else {
918 ::std::result::Result::Ok($crate::HistogramVec::new_none())
919 }
920 }};
921 ($name:expr, $help:expr, $labels:expr, $buckets:expr $(,)?) => {{
922 let _n = $name;
923 let name: &str = &*_n;
924 let module: &str = module_path!();
925 if $crate::default_filter().is_enabled(name, module) {
926 $crate::prometheus::register_histogram_vec!(name, $help, $labels, $buckets)
927 .map($crate::HistogramVec::new_some)
928 } else {
929 ::std::result::Result::Ok($crate::HistogramVec::new_none())
930 }
931 }};
932}
933
934#[cfg(test)]
935mod tests {
936 #[test]
937 fn filter_matches_metric_or_module_name_prefix() {
938 let filter = super::Filter::parse("authority=off");
940 assert!(filter.is_enabled("some_authority", "iota_core::checkpoints"));
941 assert!(!filter.is_enabled("authority", "iota_core::checkpoints"));
942 assert!(!filter.is_enabled("authority_aggregator", "iota_core::checkpoints"));
943 assert!(filter.is_enabled("certs_total", "iota_core::some_authority"));
944 assert!(!filter.is_enabled("certs_total", "iota_core::authority"));
945 assert!(!filter.is_enabled("certs_total", "iota_core::authority_aggregator"));
946
947 let filter = super::Filter::parse("authority=off,authority_aggregator=on");
949 assert!(!filter.is_enabled("authority", "iota_core::checkpoints"));
950 assert!(filter.is_enabled("authority_aggregator", "iota_core::checkpoints"));
951 assert!(!filter.is_enabled("certs_total", "iota_core::authority"));
952 assert!(filter.is_enabled("certs_total", "iota_core::authority_aggregator"));
953
954 let filter = super::Filter::parse("off,authority_aggregator=on");
956 assert!(!filter.is_enabled("some_authority", "iota_core::checkpoints"));
957 assert!(!filter.is_enabled("authority", "iota_core::checkpoints"));
958 assert!(filter.is_enabled("authority_aggregator", "iota_core::checkpoints"));
959 assert!(!filter.is_enabled("certs_total", "iota_core::some_authority"));
960 assert!(!filter.is_enabled("certs_total", "iota_core::authority"));
961 assert!(filter.is_enabled("certs_total", "iota_core::authority_aggregator"));
962
963 let filter = super::Filter::parse("authority_aggregator=off");
965 assert!(filter.is_enabled("authority", "iota_core::checkpoints"));
966 assert!(!filter.is_enabled("authority_aggregator", "iota_core::checkpoints"));
967 assert!(filter.is_enabled("certs_total", "iota_core::authority"));
968 assert!(!filter.is_enabled("certs_total", "iota_core::authority_aggregator"));
969 }
970
971 #[test]
972 fn no_filter_enables_everything() {
973 assert!(super::Filter::parse("").is_enabled("anything", "any::module"));
976 assert!(super::Filter::default().is_enabled("anything", "any::module"));
977 assert!(super::Filter::parse(",,").is_enabled("anything", "any::module"));
979 }
980
981 #[test]
982 fn accepts_on_off_value_aliases() {
983 for off in ["off", "false", "0"] {
984 let filter = super::Filter::parse(&format!("authority={off}"));
985 assert!(!filter.is_enabled("authority", "m"), "{off} should disable");
986 }
987 for on in ["on", "true", "1"] {
989 let filter = super::Filter::parse(&format!("off,authority={on}"));
990 assert!(filter.is_enabled("authority", "m"), "{on} should enable");
991 assert!(!filter.is_enabled("other", "m"));
992 }
993 }
994
995 #[test]
996 fn invalid_directives_are_dropped() {
997 assert!(super::Filter::parse("authority=maybe").is_enabled("authority", "m"));
1000 assert!(super::Filter::parse("authority").is_enabled("authority", "m"));
1003 let filter = super::Filter::parse("authority=off,bogus=nope");
1005 assert!(!filter.is_enabled("authority", "m"));
1006 }
1007
1008 #[test]
1009 fn matches_module_path_prefix() {
1010 let filter = super::Filter::parse("iota_core=off");
1013 assert!(!filter.is_enabled("certs_total", "iota_core::authority"));
1014 assert!(filter.is_enabled("certs_total", "starfish::core"));
1015 }
1016
1017 #[test]
1018 fn global_on_default() {
1019 assert!(super::Filter::parse("off,on").is_enabled("authority", "m"));
1021 let filter = super::Filter::parse("on,authority=off");
1023 assert!(filter.is_enabled("certs_total", "m"));
1024 assert!(!filter.is_enabled("authority", "m"));
1025 }
1026
1027 #[test]
1028 fn whitespace_is_trimmed() {
1029 let filter = super::Filter::parse(" authority = off , authority_aggregator = on ");
1030 assert!(!filter.is_enabled("authority", "m"));
1031 assert!(filter.is_enabled("authority_aggregator", "m"));
1032 }
1033}