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}