1use crate::layers::Layer;
2use metrics::{Counter, Gauge, Histogram, Key, KeyName, Metadata, Recorder, SharedString, Unit};
3
4pub struct Prefix<R> {
8 prefix: SharedString,
9 inner: R,
10}
11
12impl<R> Prefix<R> {
13 fn prefix_key(&self, key: &Key) -> Key {
14 let mut new_name = String::with_capacity(self.prefix.len() + 1 + key.name().len());
15 new_name.push_str(self.prefix.as_ref());
16 new_name.push('.');
17 new_name.push_str(key.name());
18
19 Key::from_parts(new_name, key.labels())
20 }
21
22 fn prefix_key_name(&self, key_name: KeyName) -> KeyName {
23 let mut new_name = String::with_capacity(self.prefix.len() + 1 + key_name.as_str().len());
24 new_name.push_str(self.prefix.as_ref());
25 new_name.push('.');
26 new_name.push_str(key_name.as_str());
27
28 KeyName::from(new_name)
29 }
30}
31
32impl<R: Recorder> Recorder for Prefix<R> {
33 fn describe_counter(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
34 let new_key_name = self.prefix_key_name(key_name);
35 self.inner.describe_counter(new_key_name, unit, description)
36 }
37
38 fn describe_gauge(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
39 let new_key_name = self.prefix_key_name(key_name);
40 self.inner.describe_gauge(new_key_name, unit, description)
41 }
42
43 fn describe_histogram(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
44 let new_key_name = self.prefix_key_name(key_name);
45 self.inner.describe_histogram(new_key_name, unit, description)
46 }
47
48 fn register_counter(&self, key: &Key, metadata: &Metadata<'_>) -> Counter {
49 let new_key = self.prefix_key(key);
50 self.inner.register_counter(&new_key, metadata)
51 }
52
53 fn register_gauge(&self, key: &Key, metadata: &Metadata<'_>) -> Gauge {
54 let new_key = self.prefix_key(key);
55 self.inner.register_gauge(&new_key, metadata)
56 }
57
58 fn register_histogram(&self, key: &Key, metadata: &Metadata<'_>) -> Histogram {
59 let new_key = self.prefix_key(key);
60 self.inner.register_histogram(&new_key, metadata)
61 }
62}
63
64pub struct PrefixLayer(&'static str);
68
69impl PrefixLayer {
70 pub fn new<S: Into<String>>(prefix: S) -> PrefixLayer {
72 PrefixLayer(Box::leak(prefix.into().into_boxed_str()))
73 }
74}
75
76impl<R> Layer<R> for PrefixLayer {
77 type Output = Prefix<R>;
78
79 fn layer(&self, inner: R) -> Self::Output {
80 Prefix { prefix: self.0.into(), inner }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::{Prefix, PrefixLayer};
87 use crate::layers::Layer;
88 use crate::test_util::*;
89 use metrics::{Counter, Gauge, Histogram, Key, KeyName, Unit};
90
91 static METADATA: metrics::Metadata =
92 metrics::Metadata::new(module_path!(), metrics::Level::INFO, Some(module_path!()));
93
94 #[test]
95 fn test_basic_functionality() {
96 let inputs = vec![
97 RecorderOperation::DescribeCounter(
98 "counter_key".into(),
99 Some(Unit::Count),
100 "counter desc".into(),
101 ),
102 RecorderOperation::DescribeGauge(
103 "gauge_key".into(),
104 Some(Unit::Bytes),
105 "gauge desc".into(),
106 ),
107 RecorderOperation::DescribeHistogram(
108 "histogram_key".into(),
109 Some(Unit::Nanoseconds),
110 "histogram desc".into(),
111 ),
112 RecorderOperation::RegisterCounter("counter_key".into(), Counter::noop(), &METADATA),
113 RecorderOperation::RegisterGauge("gauge_key".into(), Gauge::noop(), &METADATA),
114 RecorderOperation::RegisterHistogram(
115 "histogram_key".into(),
116 Histogram::noop(),
117 &METADATA,
118 ),
119 ];
120
121 let expectations = vec![
122 RecorderOperation::DescribeCounter(
123 "testing.counter_key".into(),
124 Some(Unit::Count),
125 "counter desc".into(),
126 ),
127 RecorderOperation::DescribeGauge(
128 "testing.gauge_key".into(),
129 Some(Unit::Bytes),
130 "gauge desc".into(),
131 ),
132 RecorderOperation::DescribeHistogram(
133 "testing.histogram_key".into(),
134 Some(Unit::Nanoseconds),
135 "histogram desc".into(),
136 ),
137 RecorderOperation::RegisterCounter(
138 "testing.counter_key".into(),
139 Counter::noop(),
140 &METADATA,
141 ),
142 RecorderOperation::RegisterGauge("testing.gauge_key".into(), Gauge::noop(), &METADATA),
143 RecorderOperation::RegisterHistogram(
144 "testing.histogram_key".into(),
145 Histogram::noop(),
146 &METADATA,
147 ),
148 ];
149
150 let recorder = MockBasicRecorder::from_operations(expectations);
151 let prefix = PrefixLayer::new("testing");
152 let prefix = prefix.layer(recorder);
153
154 for operation in inputs {
155 operation.apply_to_recorder(&prefix);
156 }
157 }
158
159 #[test]
160 fn test_key_vs_key_name() {
161 let prefix = Prefix { prefix: "foobar".into(), inner: () };
162
163 let key_name = KeyName::from("my_key");
164 let key = Key::from_name(key_name.clone());
165
166 let prefixed_key = prefix.prefix_key(&key);
167 let prefixed_key_name = prefix.prefix_key_name(key_name);
168
169 assert_eq!(
170 prefixed_key.name(),
171 prefixed_key_name.as_str(),
172 "prefixed key and prefixed key name should match"
173 );
174 }
175}