summaryrefslogtreecommitdiffstats
path: root/src/io/log.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/io/log.rs')
-rw-r--r--src/io/log.rs156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/io/log.rs b/src/io/log.rs
new file mode 100644
index 0000000..551f3d7
--- /dev/null
+++ b/src/io/log.rs
@@ -0,0 +1,156 @@
+use std::sync::RwLock;
+
+use anyhow::Result;
+use lazy_static::lazy_static;
+use log4rs;
+
+use crate::common::extract_lines;
+use crate::common::{ACTION_LOG_PATH, LOG_CONFIG_PATH};
+
+// static ENV_HOME: &str = "$ENV{HOME}";
+
+/// Set the logs.
+/// The configuration is read from a config file defined in `LOG_CONFIG_PATH`
+/// It's a YAML file which defines 2 logs:
+/// - a normal one used directly with the macros like `log::info!(...)`, used for debugging
+/// - a special one used with `log::info!(target: "special", ...)` to be displayed in the application
+pub fn set_loggers() -> Result<()> {
+ log4rs::init_file(
+ shellexpand::tilde(LOG_CONFIG_PATH).as_ref(),
+ Default::default(),
+ )?;
+ // clear_useless_env_home()?;
+
+ log::info!("fm is starting");
+ Ok(())
+}
+
+/// Delete useless $ENV{HOME} folder created by log4rs.
+/// This folder is created when a log file is big enough to proc a rolling
+/// Since the pattern can't be resolved, it's not created in the config folder but where the app is started...
+/// See [github issue](https://github.com/estk/log4rs/issues/314)
+/// The function log its results and delete nothing.
+// fn clear_useless_env_home() -> Result<()> {
+// let p = std::path::Path::new(&ENV_HOME);
+// let cwd = std::env::current_dir();
+// log::info!(
+// "looking from {ENV_HOME} - {p} CWD {cwd}",
+// p = p.display(),
+// cwd = cwd?.display()
+// );
+// if p.exists() && std::fs::metadata(ENV_HOME)?.is_dir()
+// // && std::path::Path::new(ENV_HOME).read_dir()?.next().is_none()
+// {
+// let z = std::path::Path::new(ENV_HOME).read_dir()?.next();
+// log::info!("z {z:?}");
+//
+// // std::fs::remove_dir_all(ENV_HOME)?;
+// log::info!("Removed {ENV_HOME} empty directory from CWD");
+// }
+// Ok(())
+// }
+
+/// Returns the last line of the log file.
+pub fn read_log() -> Result<Vec<String>> {
+ let log_path = shellexpand::tilde(ACTION_LOG_PATH).to_string();
+ let content = std::fs::read_to_string(log_path)?;
+ Ok(extract_lines(content))
+}
+
+lazy_static! {
+ static ref LAST_LOG_LINE: RwLock<String> = RwLock::new("".to_owned());
+}
+
+/// Read the last value of the "log line".
+/// It's a global string created with `lazy_static!(...)`
+/// Fail silently if the global variable can't be read and returns an empty string.
+pub fn read_last_log_line() -> String {
+ let Ok(last_log_line) = LAST_LOG_LINE.read() else {
+ return "".to_owned();
+ };
+ last_log_line.to_owned()
+}
+
+/// Write a new log line to the global variable `LAST_LOG_LINE`.
+/// It uses `lazy_static` to manipulate the global variable.
+/// Fail silently if the global variable can't be written.
+fn write_last_log_line<S>(log: S)
+where
+ S: Into<String> + std::fmt::Display,
+{
+ let Ok(mut new_log_line) = LAST_LOG_LINE.write() else {
+ return;
+ };
+ *new_log_line = log.to_string();
+}
+
+/// Write a line to both the global variable `LAST_LOG_LINE` and the special log
+/// which can be displayed with Alt+l
+pub fn write_log_line<S>(log_line: S)
+where
+ S: Into<String> + std::fmt::Display,
+{
+ log::info!(target: "special", "{log_line}");
+ write_last_log_line(log_line);
+}
+
+#[macro_export]
+macro_rules! log_line {
+ ($($arg:tt)+) => (
+ $crate::io::write_log_line(
+ format!($($arg)+)
+ )
+ );
+}
+
+lazy_static! {
+ static ref LAST_LOG_INFO: RwLock<String> = RwLock::new("".to_owned());
+}
+
+/// Read the last value of the "log info".
+/// It's a global string created with `lazy_static!(...)`
+/// Fail silently if the global variable can't be read and returns an empty string.
+fn read_last_log_info() -> String {
+ let Ok(last_log_line) = LAST_LOG_INFO.read() else {
+ return "".to_owned();
+ };
+ last_log_line.to_owned()
+}
+
+/// Write a new log info to the global variable `LAST_LOG_INFO`.
+/// It uses `lazy_static` to manipulate the global variable.
+/// Fail silently if the global variable can't be written.
+fn write_last_log_info<S>(log: &S)
+where
+ S: Into<String> + std::fmt::Display,
+{
+ let Ok(mut new_log_info) = LAST_LOG_INFO.write() else {
+ return;
+ };
+ *new_log_info = log.to_string();
+}
+
+/// Write a line to both the global variable `LAST_LOG_INFO` and the info log
+/// Won't write the same line multiple times during the same execution.
+pub fn write_log_info_once<S>(log_line: S)
+where
+ S: Into<String> + std::fmt::Display,
+{
+ if read_last_log_info() != log_line.to_string() {
+ write_last_log_info(&log_line);
+ log::info!("{log_line}");
+ }
+}
+
+/// Log a formated message to the default log.
+/// Won't write anything if the same message is sent multiple times.
+/// It uses `log::info!` internally.
+/// It accepts the same formatted messages as `format`.
+#[macro_export]
+macro_rules! log_info {
+ ($($arg:tt)+) => (
+ $crate::io::write_log_info_once(
+ format!($($arg)+)
+ )
+ );
+}