Skip to main content

flwrs_plugin/plugin/
logger.rs

1use crate::plugin::msg_client::MSG_CLIENT;
2use crate::schema::common::log_level::Enum;
3use crate::schema::common::{
4    log_level::Enum as LogLevel, plugin_type::Enum as PluginType, LogEvent,
5};
6use lazy_static::lazy_static;
7use log::{Level, Metadata, Record, SetLoggerError};
8use prost::Message;
9use std::sync::{Arc, RwLock};
10
11lazy_static! {
12    pub(crate) static ref LOGGER: Arc<RwLock<PluginLogger>> =
13        Arc::new(RwLock::new(PluginLogger::default()));
14    pub(crate) static ref LOG_WRAPPER: Arc<LogWrapper> = Arc::new(LogWrapper::default());
15}
16
17pub(crate) struct PluginLogger {
18    plugin_id: String,
19    plugin_type: PluginType,
20    level: Level,
21}
22
23impl PluginLogger {
24    pub(crate) fn set_plugin_id(&mut self, plugin_id: String) {
25        self.plugin_id = plugin_id;
26    }
27
28    pub(crate) fn set_plugin_type(&mut self, plugin_type: PluginType) {
29        self.plugin_type = plugin_type;
30    }
31
32    pub(crate) fn set_level(&mut self, level: Level) {
33        self.level = level;
34    }
35
36    pub(crate) fn initialize(id: &str, log_level: Level) -> Result<(), SetLoggerError> {
37        let mut logger = LOGGER.write().expect("Was expecting to lock");
38        logger.set_plugin_id(id.into());
39        logger.set_plugin_type(PluginType::Sink);
40        logger.set_level(log_level.into());
41        log::set_logger(LOG_WRAPPER.as_ref())?;
42        Ok(())
43    }
44}
45
46impl log::Log for PluginLogger {
47    fn enabled(&self, metadata: &Metadata) -> bool {
48        metadata.level() <= self.level
49    }
50
51    fn log(&self, record: &Record) {
52        let log_level: LogLevel = self.level.into();
53        let msg = LogEvent {
54            plugin_id: self.plugin_id.to_string(),
55            plugin_type: self.plugin_type as i32,
56            log_level: log_level as i32,
57            message: record.args().as_str().unwrap_or("<no message>").to_string(),
58            details: vec![],
59        };
60
61        tokio::task::spawn(async move {
62            match MSG_CLIENT
63                .read()
64                .await
65                .send(msg.encode_to_vec().as_slice())
66                .await
67            {
68                Ok(_) => {}
69                Err(e) => {
70                    println!("Failed to send log message: {}", e); // TODO handle this better
71                    println!("Message: {}", msg.message);
72                    println!("Details: {:?}", msg.details);
73                    println!("Log level: {:?}", log_level);
74                    println!("Plugin type: {:?}", msg.plugin_type);
75                    println!("Plugin ID: {:?}", msg.plugin_id);
76                }
77            };
78        });
79    }
80
81    fn flush(&self) {
82        // noop, we flush immediately
83    }
84}
85
86impl Default for PluginLogger {
87    fn default() -> Self {
88        Self {
89            plugin_id: "<no-ID>".to_string(),
90            level: Level::Warn,
91            plugin_type: PluginType::Undefined,
92        }
93    }
94}
95
96impl Into<LogLevel> for Level {
97    fn into(self) -> LogLevel {
98        match self {
99            Level::Error => LogLevel::Error,
100            Level::Warn => LogLevel::Warn,
101            Level::Info => LogLevel::Info,
102            Level::Debug => LogLevel::Debug,
103            Level::Trace => LogLevel::Trace,
104        }
105    }
106}
107
108impl From<LogLevel> for Level {
109    fn from(value: LogLevel) -> Self {
110        match value {
111            Enum::Undefined => Self::Warn,
112            Enum::Trace => Self::Trace,
113            Enum::Debug => Self::Debug,
114            Enum::Info => Self::Info,
115            Enum::Warn => Self::Warn,
116            Enum::Error => Self::Error,
117        }
118    }
119}
120
121#[derive(Default)]
122pub(crate) struct LogWrapper;
123
124impl log::Log for LogWrapper {
125    fn enabled(&self, metadata: &Metadata) -> bool {
126        let logger = LOGGER.read();
127        match logger {
128            Ok(logger) => logger.enabled(metadata),
129            Err(err) => {
130                println!("Failed to read logger: {}", err);
131                false
132            }
133        }
134    }
135
136    fn log(&self, record: &Record) {
137        let logger = LOGGER.read();
138        match logger {
139            Ok(logger) => logger.log(record),
140            Err(err) => {
141                println!("Failed to read logger: {}", err);
142            }
143        };
144    }
145
146    fn flush(&self) {
147        let logger = LOGGER.read();
148        match logger {
149            Ok(logger) => logger.flush(),
150            Err(err) => {
151                println!("Failed to read logger: {}", err);
152            }
153        };
154    }
155}