1use std::{
4 fs,
5 io::{self, prelude::*},
6 os::unix::io::RawFd,
7 path::{Path, PathBuf},
8};
9
10use log::LevelFilter;
11
12use log4rs::append::rolling_file::{
13 policy::compound::{
14 roll::fixed_window::FixedWindowRoller, trigger::size::SizeTrigger, CompoundPolicy,
15 },
16 RollingFileAppender,
17};
18use log4rs::config::{Appender, Config, Logger, Root};
19use log4rs::encode::pattern::PatternEncoder;
20
21use crate::consts::{ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE};
22use crate::shared::set_permissions;
23
24const LOG_MAX_BYTES: u64 = 1024 * 1024 * 16; pub fn configure_logger() {
27 atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
28 atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
29 atomic_create_file(&*ZELLIJ_TMP_LOG_FILE).unwrap();
30
31 let trigger = SizeTrigger::new(LOG_MAX_BYTES);
32 let roller = FixedWindowRoller::builder()
33 .build(
34 ZELLIJ_TMP_LOG_DIR
35 .join("zellij.log.old.{}")
36 .to_str()
37 .unwrap(),
38 1,
39 )
40 .unwrap();
41
42 let file_pattern = "{highlight({level:<6})} |{module:<25.25}| {date(%Y-%m-%d %H:%M:%S.%3f)} [{thread:<10.15}] [{file}:{line}]: {message} {n}";
45
46 let log_file = RollingFileAppender::builder()
48 .encoder(Box::new(PatternEncoder::new(file_pattern)))
49 .build(
50 &*ZELLIJ_TMP_LOG_FILE,
51 Box::new(CompoundPolicy::new(
52 Box::new(trigger),
53 Box::new(roller.clone()),
54 )),
55 )
56 .unwrap();
57
58 let log_plugin = RollingFileAppender::builder()
61 .encoder(Box::new(PatternEncoder::new(
62 "{highlight({level:<6})} {message} {n}",
63 )))
64 .build(
65 &*ZELLIJ_TMP_LOG_FILE,
66 Box::new(CompoundPolicy::new(Box::new(trigger), Box::new(roller))),
67 )
68 .unwrap();
69
70 let config = Config::builder()
74 .appender(Appender::builder().build("logFile", Box::new(log_file)))
75 .appender(Appender::builder().build("logPlugin", Box::new(log_plugin)))
76 .logger(
78 Logger::builder()
79 .appender("logFile")
80 .build("isahc", LevelFilter::Error),
81 )
82 .logger(
83 Logger::builder()
84 .appender("logPlugin")
85 .build("wasmtime_wasi", LevelFilter::Warn),
86 )
87 .logger(
88 Logger::builder()
89 .appender("logPlugin")
90 .additive(false)
91 .build("zellij_server::logging_pipe", LevelFilter::Trace),
92 )
93 .build(Root::builder().appender("logFile").build(LevelFilter::Info))
94 .unwrap();
95
96 let _ = log4rs::init_config(config).unwrap();
97}
98
99pub fn atomic_create_file(file_name: &Path) -> io::Result<()> {
100 let _ = fs::OpenOptions::new()
101 .append(true)
102 .create(true)
103 .open(file_name)?;
104 set_permissions(file_name, 0o600)
105}
106
107pub fn atomic_create_dir(dir_name: &Path) -> io::Result<()> {
108 let result = if let Err(e) = fs::create_dir(dir_name) {
109 if e.kind() == std::io::ErrorKind::AlreadyExists {
110 Ok(())
111 } else {
112 Err(e)
113 }
114 } else {
115 Ok(())
116 };
117 if result.is_ok() {
118 set_permissions(dir_name, 0o700)?;
119 }
120 result
121}
122
123pub fn debug_to_file(message: &[u8], pid: RawFd) -> io::Result<()> {
124 let mut path = PathBuf::new();
125 path.push(&*ZELLIJ_TMP_LOG_DIR);
126 path.push(format!("zellij-{}.log", pid));
127
128 let mut file = fs::OpenOptions::new()
129 .append(true)
130 .create(true)
131 .open(&path)?;
132 set_permissions(&path, 0o600)?;
133 file.write_all(message)
134}