anvil_zksync_core/
observability.rs1use anvil_zksync_types::LogLevel;
2use std::sync::{Arc, RwLock};
3use std::{fs::File, sync::Mutex};
4use tracing_subscriber::{
5 filter::LevelFilter, layer::SubscriberExt, reload, util::SubscriberInitExt, EnvFilter, Registry,
6};
7
8#[derive(Debug, Clone)]
10pub struct Observability {
11 binary_names: Vec<String>,
12 reload_handle: reload::Handle<EnvFilter, Registry>,
13 last_directives: Arc<RwLock<String>>,
15}
16
17impl Observability {
18 pub fn init(
20 binary_names: Vec<String>,
21 log_level_filter: LevelFilter,
22 log_file: File,
23 disabled: bool,
24 ) -> Result<Self, anyhow::Error> {
25 let directives = binary_names
26 .iter()
27 .map(|x| format!("{}={}", x, log_level_filter.to_string().to_lowercase()))
28 .collect::<Vec<String>>()
29 .join(",");
30 let filter = if disabled {
31 EnvFilter::new("off")
32 } else {
33 Self::parse_filter(&directives)?
34 };
35 let (filter, reload_handle) = reload::Layer::<EnvFilter, Registry>::new(filter);
36
37 tracing_subscriber::registry()
38 .with(filter)
39 .with(
40 tracing_subscriber::fmt::layer().event_format(
41 tracing_subscriber::fmt::format()
42 .compact()
43 .without_time()
44 .with_target(false),
45 ),
46 )
47 .with(
48 tracing_subscriber::fmt::layer()
49 .event_format(
50 tracing_subscriber::fmt::format()
51 .compact()
52 .without_time()
53 .with_target(false),
54 )
55 .with_writer(Mutex::new(log_file))
56 .with_ansi(false),
57 )
58 .init();
59
60 Ok(Self {
61 binary_names,
62 reload_handle,
63 last_directives: Arc::new(RwLock::new(directives)),
64 })
65 }
66
67 pub fn set_log_level(&self, level: LogLevel) -> anyhow::Result<()> {
69 let level = LevelFilter::from(level);
70 let directives = self
71 .binary_names
72 .join(&format!("={},", level.to_string().to_lowercase()));
73 let new_filter = Self::parse_filter(&directives)?;
74 self.reload_handle.reload(new_filter)?;
75 *self
76 .last_directives
77 .write()
78 .expect("Observability lock is poisoned") = directives;
79
80 Ok(())
81 }
82
83 pub fn set_logging(&self, directives: String) -> Result<(), anyhow::Error> {
89 let new_filter = Self::parse_filter(&directives)?;
90 self.reload_handle.reload(new_filter)?;
91 *self
92 .last_directives
93 .write()
94 .expect("Observability lock is poisoned") = directives;
95
96 Ok(())
97 }
98
99 fn parse_filter(directives: &str) -> Result<EnvFilter, anyhow::Error> {
105 let mut filter = EnvFilter::from_default_env();
106 for directive in directives.split(',') {
107 filter = filter.add_directive(directive.parse()?);
108 }
109
110 Ok(filter)
111 }
112
113 pub fn enable_logging(&self) -> Result<(), anyhow::Error> {
115 let last_directives = &*self
116 .last_directives
117 .read()
118 .expect("Observability lock is poisoned");
119 let new_filter = Self::parse_filter(last_directives)?;
120 self.reload_handle.reload(new_filter)?;
121
122 Ok(())
123 }
124
125 pub fn disable_logging(&self) -> Result<(), anyhow::Error> {
127 let new_filter = EnvFilter::new("off");
128 self.reload_handle.reload(new_filter)?;
129
130 Ok(())
131 }
132}