zellij/zellij-utils/src/logging.rs
bjorn3 7d7848cddc
dependencies: switch from Wasmer to Wasmtime (#3349)
* Remove ForeignFunctionEnv wrapper around PluginEnv

This will enable PluginEnv to be the Store context when migrating to
Wasmtime.

* Pass PluginEnv by value to load_plugin_instance

This will allow removing the Clone impl from PluginEnv when migrating to
Wasmtime as required by the missing Clone impl on Wasmtime's WasiCtx.

* Avoid passing a Store around when an Engine is enough

* Pass PluginEnv to the wasi read/write functions

Wasmtime requires storing the read/write end of the pipe outside of the
WasiCtx. Passing PluginEnv to these functions allows storing them in the
PluginEnv.

* Migrate to Wasmtime

* Switch from wasi-common to wasmtime-wasi

* Reduce verbosity of wasmtime_wasi logs

* Increase startup delay

To wait for all plugins to be compiled.

* Disable some wasmtime features

* Update to Wasmtime 21.0.1
2024-06-28 16:47:43 +02:00

128 lines
4.2 KiB
Rust

//! Zellij logging utility functions.
use std::{
fs,
io::{self, prelude::*},
os::unix::io::RawFd,
path::{Path, PathBuf},
};
use log::LevelFilter;
use log4rs::append::rolling_file::{
policy::compound::{
roll::fixed_window::FixedWindowRoller, trigger::size::SizeTrigger, CompoundPolicy,
},
RollingFileAppender,
};
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use crate::consts::{ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE};
use crate::shared::set_permissions;
const LOG_MAX_BYTES: u64 = 1024 * 1024 * 16; // 16 MiB per log
pub fn configure_logger() {
atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
atomic_create_file(&*ZELLIJ_TMP_LOG_FILE).unwrap();
let trigger = SizeTrigger::new(LOG_MAX_BYTES);
let roller = FixedWindowRoller::builder()
.build(
ZELLIJ_TMP_LOG_DIR
.join("zellij.log.old.{}")
.to_str()
.unwrap(),
1,
)
.unwrap();
// {n} means platform dependent newline
// module is padded to exactly 25 bytes and thread is padded to be between 10 and 15 bytes.
let file_pattern = "{highlight({level:<6})} |{module:<25.25}| {date(%Y-%m-%d %H:%M:%S.%3f)} [{thread:<10.15}] [{file}:{line}]: {message} {n}";
// default zellij appender, should be used across most of the codebase.
let log_file = RollingFileAppender::builder()
.encoder(Box::new(PatternEncoder::new(file_pattern)))
.build(
&*ZELLIJ_TMP_LOG_FILE,
Box::new(CompoundPolicy::new(
Box::new(trigger),
Box::new(roller.clone()),
)),
)
.unwrap();
// plugin appender. To be used in logging_pipe to forward stderr output from plugins. We do some formatting
// in logging_pipe to print plugin name as 'module' and plugin_id instead of thread.
let log_plugin = RollingFileAppender::builder()
.encoder(Box::new(PatternEncoder::new(
"{highlight({level:<6})} {message} {n}",
)))
.build(
&*ZELLIJ_TMP_LOG_FILE,
Box::new(CompoundPolicy::new(Box::new(trigger), Box::new(roller))),
)
.unwrap();
// Set the default logging level to "info" and log it to zellij.log file
// Decrease verbosity for `wasmtime_wasi` module because it has a lot of useless info logs
// For `zellij_server::logging_pipe`, we use custom format as we use logging macros to forward stderr output from plugins
let config = Config::builder()
.appender(Appender::builder().build("logFile", Box::new(log_file)))
.appender(Appender::builder().build("logPlugin", Box::new(log_plugin)))
.logger(
Logger::builder()
.appender("logPlugin")
.build("wasmtime_wasi", LevelFilter::Warn),
)
.logger(
Logger::builder()
.appender("logPlugin")
.additive(false)
.build("zellij_server::logging_pipe", LevelFilter::Trace),
)
.build(Root::builder().appender("logFile").build(LevelFilter::Info))
.unwrap();
let _ = log4rs::init_config(config).unwrap();
}
pub fn atomic_create_file(file_name: &Path) -> io::Result<()> {
let _ = fs::OpenOptions::new()
.append(true)
.create(true)
.open(file_name)?;
set_permissions(file_name, 0o600)
}
pub fn atomic_create_dir(dir_name: &Path) -> io::Result<()> {
let result = if let Err(e) = fs::create_dir(dir_name) {
if e.kind() == std::io::ErrorKind::AlreadyExists {
Ok(())
} else {
Err(e)
}
} else {
Ok(())
};
if result.is_ok() {
set_permissions(dir_name, 0o700)?;
}
result
}
pub fn debug_to_file(message: &[u8], pid: RawFd) -> io::Result<()> {
let mut path = PathBuf::new();
path.push(&*ZELLIJ_TMP_LOG_DIR);
path.push(format!("zellij-{}.log", pid));
let mut file = fs::OpenOptions::new()
.append(true)
.create(true)
.open(&path)?;
set_permissions(&path, 0o600)?;
file.write_all(message)
}