1use std::time::{Duration, Instant};
2
3use crate::snapshot::{ItemKind, Snapshot};
4use crate::util;
5use crate::{Descriptive, HandlesObservations, Observation, PutsSnapshot};
6
7use super::*;
8
9pub struct Panel<L> {
51 label_filter: LabelFilter<L>,
52 name: Option<String>,
53 title: Option<String>,
54 description: Option<String>,
55 counter: Option<InstrumentAdapter<L, Counter>>,
56 gauge: Option<GaugeAdapter<L>>,
57 meter: Option<InstrumentAdapter<L, Meter>>,
58 histogram: Option<InstrumentAdapter<L, Histogram>>,
59 panels: Vec<Panel<L>>,
60 handlers: Vec<Box<dyn HandlesObservations<Label = L>>>,
61 snapshooters: Vec<Box<dyn PutsSnapshot>>,
62 last_update: Instant,
63 max_inactivity_duration: Option<Duration>,
64 show_activity_state: bool,
65}
66
67impl<L> Panel<L>
68where
69 L: Eq + Send + 'static,
70{
71 pub fn new<F: Into<LabelFilter<L>>>(accept: F) -> Panel<L> {
74 Panel {
75 label_filter: accept.into(),
76 name: None,
77 title: None,
78 description: None,
79 counter: None,
80 gauge: None,
81 meter: None,
82 histogram: None,
83 panels: Vec::new(),
84 handlers: Vec::new(),
85 snapshooters: Vec::new(),
86 last_update: Instant::now(),
87 max_inactivity_duration: None,
88 show_activity_state: true,
89 }
90 }
91
92 pub fn named<T: Into<String>, F: Into<LabelFilter<L>>>(accept: F, name: T) -> Panel<L> {
95 let mut panel = Self::new(accept);
96 panel.name = Some(name.into());
97 panel
98 }
99
100 pub fn accept<F: Into<LabelFilter<L>>>(accept: F) -> Self {
103 Self::new(accept)
104 }
105
106 pub fn accept_named<T: Into<String>, F: Into<LabelFilter<L>>>(accept: F, name: T) -> Self {
109 Self::named(accept, name)
110 }
111
112 pub fn accept_all_named<T: Into<String>>(name: T) -> Panel<L> {
115 Self::named(AcceptAllLabels, name)
116 }
117
118 pub fn accept_all() -> Panel<L> {
121 Self::new(AcceptAllLabels)
122 }
123
124 pub fn add_counter<I: Into<InstrumentAdapter<L, Counter>>>(&mut self, counter: I) {
125 if self.counter.is_none() {
126 self.counter = Some(counter.into());
127 } else {
128 self.add_handler(counter.into())
129 }
130 }
131
132 pub fn counter<I: Into<InstrumentAdapter<L, Counter>>>(mut self, counter: I) -> Self {
133 self.add_counter(counter);
134 self
135 }
136
137 pub fn gauge<I: Into<GaugeAdapter<L>>>(mut self, gauge: I) -> Self {
138 self.add_gauge(gauge);
139 self
140 }
141
142 pub fn add_gauge<I: Into<GaugeAdapter<L>>>(&mut self, gauge: I) {
143 if self.gauge.is_none() {
144 self.gauge = Some(gauge.into());
145 } else {
146 self.add_handler(gauge.into())
147 }
148 }
149
150 pub fn meter<I: Into<InstrumentAdapter<L, Meter>>>(mut self, meter: I) -> Self {
151 self.add_meter(meter);
152 self
153 }
154
155 pub fn add_meter<I: Into<InstrumentAdapter<L, Meter>>>(&mut self, meter: I) {
156 if self.meter.is_none() {
157 self.meter = Some(meter.into());
158 } else {
159 self.add_handler(meter.into())
160 }
161 }
162
163 pub fn add_histogram<I: Into<InstrumentAdapter<L, Histogram>>>(&mut self, histogram: I) {
164 if self.histogram.is_none() {
165 self.histogram = Some(histogram.into());
166 } else {
167 self.add_handler(histogram.into())
168 }
169 }
170
171 pub fn histogram<I: Into<InstrumentAdapter<L, Histogram>>>(mut self, histogram: I) -> Self {
172 self.add_histogram(histogram);
173 self
174 }
175
176 pub fn add_snapshooter<T: PutsSnapshot>(&mut self, snapshooter: T) {
177 self.snapshooters.push(Box::new(snapshooter));
178 }
179
180 pub fn snapshooter<T: PutsSnapshot>(mut self, snapshooter: T) -> Self {
181 self.add_snapshooter(snapshooter);
182 self
183 }
184
185 pub fn add_instrument<I: Instrument>(&mut self, instrument: I) {
186 self.handlers
187 .push(Box::new(InstrumentAdapter::new(instrument)));
188 }
189
190 pub fn instrument<T: Instrument>(mut self, instrument: T) -> Self {
191 self.add_instrument(instrument);
192 self
193 }
194
195 pub fn add_panel(&mut self, panel: Panel<L>) {
196 self.panels.push(panel);
197 }
198
199 pub fn panel(mut self, panel: Panel<L>) -> Self {
200 self.add_panel(panel);
201 self
202 }
203
204 pub fn add_handler<H: HandlesObservations<Label = L>>(&mut self, handler: H) {
205 self.handlers.push(Box::new(handler));
206 }
207
208 pub fn handler<H: HandlesObservations<Label = L>>(mut self, handler: H) -> Self {
209 self.add_handler(handler);
210 self
211 }
212
213 pub fn name(&self) -> Option<&str> {
215 self.name.as_deref()
216 }
217
218 pub fn set_name<T: Into<String>>(&mut self, name: T) {
222 self.name = Some(name.into());
223 }
224
225 pub fn set_title<T: Into<String>>(&mut self, title: T) {
229 self.title = Some(title.into())
230 }
231
232 pub fn set_description<T: Into<String>>(&mut self, description: T) {
236 self.description = Some(description.into())
237 }
238
239 pub fn inactivity_limit(mut self, limit: Duration) -> Self {
244 self.set_inactivity_limit(limit);
245 self
246 }
247
248 pub fn set_inactivity_limit(&mut self, limit: Duration) {
254 self.max_inactivity_duration = Some(limit);
255 }
256
257 pub fn set_show_activity_state(&mut self, show: bool) {
263 self.show_activity_state = show;
264 }
265
266 pub fn show_activity_state(mut self, show: bool) -> Self {
272 self.set_show_activity_state(show);
273 self
274 }
275
276 pub fn accepts_label(&self, label: &L) -> bool {
277 self.label_filter.accepts(label)
278 }
279
280 fn put_values_into_snapshot(&self, into: &mut Snapshot, descriptive: bool) {
281 util::put_default_descriptives(self, into, descriptive);
282 if let Some(d) = self.max_inactivity_duration {
283 if self.show_activity_state {
284 if self.last_update.elapsed() > d {
285 into.items
286 .push(("_inactive".to_string(), ItemKind::Boolean(true)));
287 into.items
288 .push(("_active".to_string(), ItemKind::Boolean(false)));
289 return;
290 } else {
291 into.items
292 .push(("_inactive".to_string(), ItemKind::Boolean(false)));
293 into.items
294 .push(("_active".to_string(), ItemKind::Boolean(true)));
295 }
296 }
297 };
298 self.counter
299 .as_ref()
300 .iter()
301 .for_each(|x| x.put_snapshot(into, descriptive));
302 self.gauge
303 .as_ref()
304 .iter()
305 .for_each(|x| x.put_snapshot(into, descriptive));
306 self.meter
307 .as_ref()
308 .iter()
309 .for_each(|x| x.put_snapshot(into, descriptive));
310 self.histogram
311 .as_ref()
312 .iter()
313 .for_each(|x| x.put_snapshot(into, descriptive));
314 self.panels
315 .iter()
316 .for_each(|p| p.put_snapshot(into, descriptive));
317 self.snapshooters
318 .iter()
319 .for_each(|p| p.put_snapshot(into, descriptive));
320 self.handlers
321 .iter()
322 .for_each(|p| p.put_snapshot(into, descriptive));
323 }
324}
325
326impl<L> PutsSnapshot for Panel<L>
327where
328 L: Eq + Send + 'static,
329{
330 fn put_snapshot(&self, into: &mut Snapshot, descriptive: bool) {
331 if let Some(ref name) = self.name {
332 let mut new_level = Snapshot::default();
333 self.put_values_into_snapshot(&mut new_level, descriptive);
334 into.items
335 .push((name.clone(), ItemKind::Snapshot(new_level)));
336 } else {
337 self.put_values_into_snapshot(into, descriptive);
338 }
339 }
340}
341
342impl<L> HandlesObservations for Panel<L>
343where
344 L: Eq + Send + 'static,
345{
346 type Label = L;
347
348 fn handle_observation(&mut self, observation: &Observation<Self::Label>) -> usize {
349 if !self.label_filter.accepts(observation.label()) {
350 return 0;
351 }
352
353 let mut instruments_updated = 0;
354
355 self.counter
356 .iter_mut()
357 .for_each(|x| instruments_updated += x.handle_observation(&observation));
358 self.gauge
359 .iter_mut()
360 .for_each(|x| instruments_updated += x.handle_observation(&observation));
361 self.meter
362 .iter_mut()
363 .for_each(|x| instruments_updated += x.handle_observation(&observation));
364 self.histogram
365 .iter_mut()
366 .for_each(|x| instruments_updated += x.handle_observation(&observation));
367 self.panels
368 .iter_mut()
369 .for_each(|x| instruments_updated += x.handle_observation(&observation));
370 self.handlers
371 .iter_mut()
372 .for_each(|x| instruments_updated += x.handle_observation(&observation));
373
374 instruments_updated
375 }
376}
377
378impl<L> Descriptive for Panel<L> {
379 fn title(&self) -> Option<&str> {
380 self.title.as_deref()
381 }
382
383 fn description(&self) -> Option<&str> {
384 self.description.as_deref()
385 }
386}