1use std::{
4 borrow::Cow,
5 fmt::{self, Write},
6 ops::Deref,
7 sync::{Arc, RwLock},
8};
9
10use portable_atomic::{AtomicU64, Ordering};
11
12use crate::{Error, MetricsGroup, MetricsGroupSet, encoding::encode_eof, iterable::IntoIterable};
13
14#[derive(Debug, Default)]
16pub struct Registry {
17 schema_version: Arc<AtomicU64>,
18 metrics: Vec<Arc<dyn MetricsGroup>>,
19 prefix: Option<Cow<'static, str>>,
20 labels: Vec<(Cow<'static, str>, Cow<'static, str>)>,
21 sub_registries: Vec<Registry>,
22}
23
24impl Registry {
25 pub fn sub_registry_with_prefix(&mut self, prefix: impl Into<Cow<'static, str>>) -> &mut Self {
29 let prefix = self.prefix.to_owned().map(|p| p + "_").unwrap_or_default() + prefix.into();
30 self.schema_version.fetch_add(1, Ordering::Relaxed);
31 let sub_registry = Registry {
32 schema_version: self.schema_version.clone(),
33 metrics: Default::default(),
34 prefix: Some(prefix),
35 labels: self.labels.clone(),
36 sub_registries: Default::default(),
37 };
38 self.sub_registries.push(sub_registry);
39 self.sub_registries.last_mut().unwrap()
40 }
41
42 pub fn sub_registry_with_labels(
46 &mut self,
47 labels: impl IntoIterator<Item = (impl Into<Cow<'static, str>>, impl Into<Cow<'static, str>>)>,
48 ) -> &mut Self {
49 let mut all_labels = self.labels.clone();
50 all_labels.extend(labels.into_iter().map(|(k, v)| (k.into(), v.into())));
51 self.schema_version.fetch_add(1, Ordering::Relaxed);
52 let sub_registry = Registry {
53 schema_version: self.schema_version.clone(),
54 prefix: self.prefix.clone(),
55 labels: all_labels,
56 metrics: Default::default(),
57 sub_registries: Default::default(),
58 };
59 self.sub_registries.push(sub_registry);
60 self.sub_registries.last_mut().unwrap()
61 }
62
63 pub fn sub_registry_with_label(
67 &mut self,
68 key: impl Into<Cow<'static, str>>,
69 value: impl Into<Cow<'static, str>>,
70 ) -> &mut Self {
71 self.sub_registry_with_labels([(key, value)])
72 }
73
74 pub fn register(&mut self, metrics_group: Arc<dyn MetricsGroup>) {
76 self.schema_version.fetch_add(1, Ordering::Relaxed);
77 for family in IntoIterable::family_iter(&*metrics_group) {
78 family.attach_schema_version(Arc::clone(&self.schema_version));
79 }
80 self.metrics.push(metrics_group);
81 }
82
83 pub fn register_all(&mut self, metrics_group_set: &impl MetricsGroupSet) {
85 for group in metrics_group_set.groups_cloned() {
86 self.register(group)
87 }
88 }
89
90 pub fn register_all_prefixed(&mut self, metrics_group_set: &impl MetricsGroupSet) {
92 let registry = self.sub_registry_with_prefix(metrics_group_set.name());
93 registry.register_all(metrics_group_set)
94 }
95
96 pub fn encode_openmetrics_to_writer(&self, writer: &mut impl Write) -> fmt::Result {
103 for group in &self.metrics {
104 group.encode_openmetrics(writer, self.prefix.as_deref(), &self.labels)?;
105 }
106
107 for sub in self.sub_registries.iter() {
108 sub.encode_openmetrics_to_writer(writer)?;
109 }
110 Ok(())
111 }
112
113 pub fn schema_version(&self) -> u64 {
115 self.schema_version.load(Ordering::Relaxed)
116 }
117
118 pub fn encode_schema(
126 &self,
127 mut schema: Option<&mut crate::encoding::Schema>,
128 values: &mut crate::encoding::Values,
129 ) {
130 for group in &self.metrics {
131 group.encode_schema(
132 schema.as_deref_mut(),
133 values,
134 self.prefix.as_deref(),
135 &self.labels,
136 );
137 }
138
139 for sub in self.sub_registries.iter() {
140 sub.encode_schema(schema.as_deref_mut(), values);
141 }
142 }
143}
144
145pub trait MetricsSource: Send + 'static {
147 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error>;
152
153 fn encode_openmetrics_to_string(&self) -> Result<String, Error> {
157 let mut s = String::new();
158 self.encode_openmetrics(&mut s)?;
159 Ok(s)
160 }
161}
162
163impl MetricsSource for Registry {
164 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
165 self.encode_openmetrics_to_writer(writer)?;
166 encode_eof(writer)?;
167 Ok(())
168 }
169}
170
171pub type RwLockRegistry = Arc<RwLock<Registry>>;
176
177impl MetricsSource for RwLockRegistry {
178 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
179 let inner = self.read().expect("poisoned");
180 inner.encode_openmetrics(writer)
181 }
182}
183
184impl MetricsSource for Arc<Registry> {
185 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
186 Arc::deref(self).encode_openmetrics(writer)
187 }
188}