* work * moar work * notes * work * separate to terminal and control channels * stdin working * serve html web client initial * serve static assets loaded with include_dir * merge * enable_web_server config parameter * compile time flag to disable web server capability * rustfmt * add license to all xterm.js assets * mouse working except copy/paste * helpful comment * web client improvements - move script to js file - add favicon - add nerd font - change title TODO: investigate if font license embedded in otf is sufficient * get mouse to work properly * kitty keyboard support initial * fix wrong type in preload link * wip axum websocket handlers - upgrade axum to v0.8.1, enable ws feature - begin setup of websocket handlers - tidy up imports * replace control listener * handle terminal websocket with axum * cleanup Cargo.toml * kitty fixes and bracketed paste * fix(mouse): pane not found crash * initial session switching infra * add `web_client_font` option * session switching, creation and resurrection working through the session manager * move session module to zellij-utils and share logic with web-client * some cleanups * require restart for enable-web-server * use session name from router * write config to disk and watch for config changes * rename session name to ipc path * add basic panic handler, make render_to_client exit on channel close * use while let instead of loop * handle websocket close * add mouse motions * make clipboard work * add weblink handling and webgl rendering * add todo * fix: use session name instead of patch on session switch * use "default" layout for new sessions * ui indication for session being shared * share this session ui * plugin assets * Fix process crash on mac with notify watcher. Use poll watcher instead of recommended as a workaround. * make url session switching and creation work * start welcome screen on root url * scaffold control messages, set font from config * set dimensions on session start * bring back session name from url * send bytes on terminal websocket instead of json - create web client os input and id before websocket connection * draft ui * work * refactor ui * remove otf font, remove margins to avoid scrollbar * version query endpoint for server status * web session info query endpoint * refactor: move stuff around * add web client info to session metadata * make tests pass * populate real data in session list * remove unnecessary endpoint * add web_client node to config, add font option * remove web_client_font * allow disabling the web session through the config - WIP * formalize sharing/not-sharing configuration * fix tests * allow shutting down web server * display error when web clients are forbidden to attach * only show sessions that allow web clients if this is a web client * style(fmt): rustfmt * fix: query web server from Zellij rather than from each plugin * remove log spam * handle some error paths better in the web client * allow controlling the web server through the cli * allow configuring the web server's ip/port * fix tests and format code * use direct WebServerStatus event instead of piggy-backing on SessionInfo * plugin revamp initial * make plugin responsive * adjust plugin title * refactor: share plugin * refactor: share plugin * add cors middleware * some fixes for running without a compiled web server capability * display error when starting the share plugin without web server support * clarify config * add pipelines to compile zellij without web support * display error when unable to start web server * only query web server when share plugin is running * refactor(web-client): connection table * give zellij_server_listener access to the control channel * fixes and clarifications * refactor: consolidate generate_unique_session_name * give proper error when trying to attach to a forbidden session * change browser URL when switching sessions * add keyboard shortcut * enforce https when bound to non-loopback ip * initial authentication token implementation * background color from theme * initial web client theme config * basic token generation ui * refactor set config message creation * also set body background * allow editing scrollback for plugins too * set scrollback to 0 * properly parse colors in config * generate token from plugin * nice login modals * initial token management screen * implement token authentication * refactor(share): token management screen * style(fmt): rustfmt * fix(plugin): some minor bugs * refactor(share): main screen * refactor(share): token screen * refactor(share): main * refactor(share): ui components * fix(responsiveness): properly send usage_width to the render function * fix cli commands and add some verbosity * add support for settings ansi and selection colors * add cursor and cursor accent * basic web client tests * fix tests * refactor: web client * use session tokens for authentication * improve modals * move shutdown to ipc * refactor: ipc logic * serialize theme config for web client * update tests * refactor: move some stuff around to prepare for config hot reload * config live reloading for the web clients * change remember-me UI wording * improve xterm.js link handling * make sure terminal is focused on mousemove * remove deprecated sharing indication from compact-bar * gate deps and functionality behind the web_server_compatibility feature * feat(build): add --no-web flag in all the places * fix some other build flows * add new assets * update CI for no-web (untested) * make more dependencies optional * update axum-extra * add web client configuration options * gracefully close connections on server exit * tests for graceful connection closing * handle client-side reconnect when server is down * fix: make sure ipc bus folder exists before starting * add commands to manage login tokens from the cli * style(fmt): rustfmt * some cleanups * fix(ux): allow alt-right-click on the web client without opening the context menu * fix: prevent attaching to welcome screen * fix: reload config issues * fix long socket path on macos * normalize config conversion and fix color gap in browser * revoke session_token cookie if it is not valid * fix: visual bug with multiple clients in extremely small screen sizes * fix: only include rusqlite for the web server capability builds * update e2e snapshots * refactor(web): client side js * some cleanups * moar cleanups * fix(tests): wait for server instead of using a fixed timeout * debug CI * fix(tests): use spawn_blocking for running the test web server * fix(tests): wait for http rather than tcp port * fix(tests): properly pass config path - hopefully this is the issue... * success! bring back the rest of the tests * attempt to fix the macos CI issue * docs(changelog): add PR --------- Co-authored-by: Thomas Linford <linford.t@gmail.com>
134 lines
4.4 KiB
Rust
134 lines
4.4 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)))
|
|
// reduce the verbosity of isahc, otherwise it logs on every failed web request
|
|
.logger(
|
|
Logger::builder()
|
|
.appender("logFile")
|
|
.build("isahc", LevelFilter::Error),
|
|
)
|
|
.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)
|
|
}
|