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::write_eof};
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 self.metrics.push(metrics_group);
78 }
79
80 pub fn register_all(&mut self, metrics_group_set: &impl MetricsGroupSet) {
82 for group in metrics_group_set.groups_cloned() {
83 self.register(group)
84 }
85 }
86
87 pub fn register_all_prefixed(&mut self, metrics_group_set: &impl MetricsGroupSet) {
89 let registry = self.sub_registry_with_prefix(metrics_group_set.name());
90 registry.register_all(metrics_group_set)
91 }
92
93 pub fn encode_openmetrics_to_writer(&self, writer: &mut impl Write) -> fmt::Result {
100 for group in &self.metrics {
101 group.encode_openmetrics(writer, self.prefix.as_deref(), &self.labels)?;
102 }
103
104 for sub in self.sub_registries.iter() {
105 sub.encode_openmetrics_to_writer(writer)?;
106 }
107 Ok(())
108 }
109
110 pub fn schema_version(&self) -> u64 {
112 self.schema_version.load(Ordering::Relaxed)
113 }
114
115 pub fn encode_schema(&self, schema: &mut crate::encoding::Schema) {
117 for group in &self.metrics {
118 group.encode_schema(schema, self.prefix.as_deref(), &self.labels);
119 }
120
121 for sub in self.sub_registries.iter() {
122 sub.encode_schema(schema);
123 }
124 }
125
126 pub fn encode_values(&self, values: &mut crate::encoding::Values) {
128 for group in &self.metrics {
129 group.encode_values(values);
130 }
131
132 for sub in self.sub_registries.iter() {
133 sub.encode_values(values);
134 }
135 }
136}
137
138pub trait MetricsSource: Send + 'static {
140 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error>;
145
146 fn encode_openmetrics_to_string(&self) -> Result<String, Error> {
150 let mut s = String::new();
151 self.encode_openmetrics(&mut s)?;
152 Ok(s)
153 }
154}
155
156impl MetricsSource for Registry {
157 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
158 self.encode_openmetrics_to_writer(writer)?;
159 write_eof(writer)?;
160 Ok(())
161 }
162}
163
164pub type RwLockRegistry = Arc<RwLock<Registry>>;
169
170impl MetricsSource for RwLockRegistry {
171 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
172 let inner = self.read().expect("poisoned");
173 inner.encode_openmetrics(writer)
174 }
175}
176
177impl MetricsSource for Arc<Registry> {
178 fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
179 Arc::deref(self).encode_openmetrics(writer)
180 }
181}