tuwunel_core/log/
reload.rs1use std::{
2 collections::HashMap,
3 sync::{Arc, Mutex},
4};
5
6use tracing_subscriber::{EnvFilter, reload};
7
8use crate::{Result, error};
9
10pub trait ReloadHandle<L> {
25 fn current(&self) -> Option<L>;
26
27 fn reload(&self, new_value: L) -> Result<(), reload::Error>;
28}
29
30impl<L: Clone, S> ReloadHandle<L> for reload::Handle<L, S> {
31 fn current(&self) -> Option<L> { Self::clone_current(self) }
32
33 fn reload(&self, new_value: L) -> Result<(), reload::Error> { Self::reload(self, new_value) }
34}
35
36#[derive(Clone)]
37pub struct LogLevelReloadHandles {
38 handles: Arc<Mutex<HandleMap>>,
39}
40
41type HandleMap = HashMap<String, Handle>;
42type Handle = Box<dyn ReloadHandle<EnvFilter> + Send + Sync>;
43
44impl LogLevelReloadHandles {
45 pub fn add(&self, name: &str, handle: Handle) {
46 self.handles
47 .lock()
48 .expect("locked")
49 .insert(name.into(), handle);
50 }
51
52 pub fn reload(&self, new_value: &EnvFilter, names: Option<&[&str]>) -> Result {
53 self.handles
54 .lock()
55 .expect("locked")
56 .iter()
57 .filter(|(name, _)| names.is_some_and(|names| names.contains(&name.as_str())))
58 .for_each(|(_, handle)| {
59 _ = handle
60 .reload(new_value.clone())
61 .or_else(error::else_log);
62 });
63
64 Ok(())
65 }
66
67 #[must_use]
68 pub fn current(&self, name: &str) -> Option<EnvFilter> {
69 self.handles
70 .lock()
71 .expect("locked")
72 .get(name)
73 .map(|handle| handle.current())?
74 }
75}
76
77impl Default for LogLevelReloadHandles {
78 fn default() -> Self {
79 Self {
80 handles: Arc::new(HandleMap::new().into()),
81 }
82 }
83}