1
0
Fork 0
forked from wry/wry

compositor: add LogLevel enum

This commit is contained in:
Julian Orth 2026-03-07 11:40:45 +01:00
parent be0782f5d2
commit 042070ee99
26 changed files with 131 additions and 106 deletions

View file

@ -27,12 +27,11 @@ use {
damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs,
reexec::ReexecArgs, run_tagged::RunTaggedArgs, tree::TreeArgs, xwayland::XwaylandArgs,
},
compositor::start_compositor,
compositor::{LogLevel, start_compositor},
format::{Format, ref_formats},
portal,
pr_caps::drop_all_pr_caps,
},
::log::Level,
clap::{Args, Parser, Subcommand, ValueEnum, ValueHint, builder::PossibleValue},
clap_complete::Shell,
};
@ -50,7 +49,7 @@ struct Jay {
pub struct GlobalArgs {
/// The log level.
#[clap(value_enum, long, default_value_t)]
pub log_level: CliLogLevel,
pub log_level: LogLevel,
}
#[derive(Subcommand, Debug)]
@ -176,7 +175,7 @@ pub struct LogArgs {
pub struct SetLogArgs {
/// The new log level.
#[clap(value_enum)]
level: CliLogLevel,
level: LogLevel,
}
#[derive(Args, Debug)]
@ -194,28 +193,6 @@ pub enum CliBackend {
Metal,
}
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default)]
pub enum CliLogLevel {
Trace,
Debug,
#[default]
Info,
Warn,
Error,
}
impl Into<Level> for CliLogLevel {
fn into(self) -> Level {
match self {
CliLogLevel::Trace => Level::Trace,
CliLogLevel::Debug => Level::Debug,
CliLogLevel::Info => Level::Info,
CliLogLevel::Warn => Level::Warn,
CliLogLevel::Error => Level::Error,
}
}
}
#[derive(Args, Debug)]
pub struct GenerateArgs {
/// The shell to generate completions for

View file

@ -67,7 +67,7 @@ struct KillIdArgs {
}
pub fn main(global: GlobalArgs, clients_args: ClientsArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let clients = Rc::new(Clients { tc: tc.clone() });
clients.run(clients_args).await;
});

View file

@ -26,7 +26,7 @@ pub enum ColorManagementCmd {
}
pub fn main(global: GlobalArgs, args: ColorManagementArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let cm = ColorManagement { tc: tc.clone() };
cm.run(args).await;
});

View file

@ -55,7 +55,7 @@ pub struct DecayArgs {
}
pub fn main(global: GlobalArgs, damage_tracking_args: DamageTrackingArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let damage_tracking = Rc::new(DamageTracking { tc: tc.clone() });
damage_tracking.run(damage_tracking_args).await;
});

View file

@ -51,7 +51,7 @@ pub struct IdleSetGracePeriodArgs {
}
pub fn main(global: GlobalArgs, args: IdleArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let idle = Idle { tc: tc.clone() };
idle.run(args).await;
});

View file

@ -324,7 +324,7 @@ pub struct UseHardwareCursorArgs {
}
pub fn main(global: GlobalArgs, args: InputArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let idle = Rc::new(Input { tc: tc.clone() });
idle.run(args).await;
});

View file

@ -18,7 +18,7 @@ use {
};
pub fn main(global: GlobalArgs, args: LogArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let logger = Rc::new(Log {
tc: tc.clone(),
path: RefCell::new(None),

View file

@ -8,7 +8,7 @@ use {
};
pub fn main(global: GlobalArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
run(tc).await;
});
}

View file

@ -466,7 +466,7 @@ fn blend_space_possible_values() -> Vec<PossibleValue> {
}
pub fn main(global: GlobalArgs, args: RandrArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let idle = Rc::new(Randr { tc: tc.clone() });
idle.run(args).await;
});

View file

@ -20,7 +20,7 @@ pub struct ReexecArgs {
}
pub fn main(global: GlobalArgs, reexec_args: ReexecArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let rexec = Rc::new(Reexec { tc: tc.clone() });
rexec.run(reexec_args).await;
});

View file

@ -10,7 +10,7 @@ use {
};
pub fn main(global: GlobalArgs, args: RunPrivilegedArgs) {
Logger::install_stderr(global.log_level.into());
Logger::install_stderr(global.log_level);
if let Some(xrd) = xrd() {
let mut wd = match std::env::var(WAYLAND_DISPLAY) {
Ok(v) => v,

View file

@ -21,7 +21,7 @@ pub struct RunTaggedArgs {
}
pub fn main(global: GlobalArgs, run_tagged_args: RunTaggedArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let run_tagged = Rc::new(RunTagged { tc: tc.clone() });
run_tagged.run(run_tagged_args).await;
});

View file

@ -30,7 +30,7 @@ use {
};
pub fn main(global: GlobalArgs, args: ScreenshotArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let screenshot = Rc::new(Screenshot {
tc: tc.clone(),
args,

View file

@ -27,7 +27,7 @@ use {
};
pub fn main(global: GlobalArgs, args: SeatTestArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let screenshot = Rc::new(SeatTest {
tc: tc.clone(),
args,

View file

@ -4,11 +4,12 @@ use {
tools::tool_client::{ToolClient, with_tool_client},
wire::jay_compositor::SetLogLevel,
},
linearize::Linearize,
std::rc::Rc,
};
pub fn main(global: GlobalArgs, args: SetLogArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let logger = Rc::new(Log {
tc: tc.clone(),
args,
@ -27,7 +28,7 @@ async fn run(log: Rc<Log>) {
let comp = tc.jay_compositor().await;
tc.send(SetLogLevel {
self_id: comp,
level: log.args.level as u32,
level: log.args.level.linearize() as u32,
});
tc.round_trip().await;
}

View file

@ -62,7 +62,7 @@ struct QueryWorkspaceNameArgs {
}
pub fn main(global: GlobalArgs, tree_args: TreeArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let comp = tc.jay_compositor().await;
let tree = Rc::new(Tree {
tc: tc.clone(),

View file

@ -8,7 +8,7 @@ use {
};
pub fn main(global: GlobalArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let logger = Rc::new(Unlocker { tc: tc.clone() });
run(logger).await;
});

View file

@ -39,7 +39,7 @@ pub enum CliScalingMode {
}
pub fn main(global: GlobalArgs, args: XwaylandArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
with_tool_client(global.log_level, |tc| async move {
let xwayland = Xwayland { tc: tc.clone() };
xwayland.run(args).await;
});

View file

@ -84,8 +84,11 @@ use {
wheel::{Wheel, WheelError},
},
ahash::AHashSet,
clap::ValueEnum,
forker::ForkerProxy,
jay_config::_private::DEFAULT_SEAT_NAME,
jay_config::{_private::DEFAULT_SEAT_NAME, logging::LogLevel as ConfigLogLevel},
linearize::Linearize,
log::LevelFilter,
std::{
cell::{Cell, RefCell},
env,
@ -113,9 +116,9 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
None
};
let forker = create_forker(reaper_pid);
let portal = portal::run_from_compositor(global.log_level.into());
let portal = portal::run_from_compositor(global.log_level);
enable_profiler();
let logger = Logger::install_compositor(global.log_level.into());
let logger = Logger::install_compositor(global.log_level);
let portal = match portal {
Ok(p) => Some(p),
Err(e) => {
@ -804,3 +807,52 @@ pub fn config_dir() -> Option<String> {
None
}
}
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default, Eq, PartialEq, Linearize)]
pub enum LogLevel {
Trace,
Debug,
#[default]
Info,
Warn,
Error,
Off,
}
impl Into<LevelFilter> for LogLevel {
fn into(self) -> LevelFilter {
match self {
LogLevel::Trace => LevelFilter::Trace,
LogLevel::Debug => LevelFilter::Debug,
LogLevel::Info => LevelFilter::Info,
LogLevel::Warn => LevelFilter::Warn,
LogLevel::Error => LevelFilter::Error,
LogLevel::Off => LevelFilter::Off,
}
}
}
impl From<LevelFilter> for LogLevel {
fn from(value: LevelFilter) -> Self {
match value {
LevelFilter::Trace => LogLevel::Trace,
LevelFilter::Debug => LogLevel::Debug,
LevelFilter::Info => LogLevel::Info,
LevelFilter::Warn => LogLevel::Warn,
LevelFilter::Error => LogLevel::Error,
LevelFilter::Off => LogLevel::Off,
}
}
}
impl From<ConfigLogLevel> for LogLevel {
fn from(value: ConfigLogLevel) -> Self {
match value {
ConfigLogLevel::Trace => LogLevel::Trace,
ConfigLogLevel::Debug => LogLevel::Debug,
ConfigLogLevel::Info => LogLevel::Info,
ConfigLogLevel::Warn => LogLevel::Warn,
ConfigLogLevel::Error => LogLevel::Error,
}
}
}

View file

@ -66,7 +66,7 @@ use {
},
},
keyboard::{Group, Keymap, mods::Modifiers, syms::KeySym},
logging::LogLevel,
logging::LogLevel as ConfigLogLevel,
theme::{BarPosition, colors::Colorable, sized::Resizable},
timer::Timer as JayTimer,
video::{
@ -263,17 +263,17 @@ impl ConfigProxyHandler {
fn handle_log_request(
&self,
level: LogLevel,
level: ConfigLogLevel,
msg: &str,
file: Option<&str>,
line: Option<u32>,
) {
let level = match level {
LogLevel::Error => Level::Error,
LogLevel::Warn => Level::Warn,
LogLevel::Info => Level::Info,
LogLevel::Debug => Level::Debug,
LogLevel::Trace => Level::Trace,
ConfigLogLevel::Error => Level::Error,
ConfigLogLevel::Warn => Level::Warn,
ConfigLogLevel::Info => Level::Info,
ConfigLogLevel::Debug => Level::Debug,
ConfigLogLevel::Trace => Level::Trace,
};
let debug = fmt::from_fn(|fmt| {
if let Some(file) = file {
@ -1849,17 +1849,8 @@ impl ConfigProxyHandler {
Ok(())
}
fn handle_set_log_level(&self, level: LogLevel) {
let level = match level {
LogLevel::Error => Level::Error,
LogLevel::Warn => Level::Warn,
LogLevel::Info => Level::Info,
LogLevel::Debug => Level::Debug,
LogLevel::Trace => Level::Trace,
};
if let Some(logger) = &self.state.logger {
logger.set_level(level);
}
fn handle_set_log_level(&self, level: ConfigLogLevel) {
self.state.set_log_level(level.into());
}
fn handle_grab(&self, kb: InputDevice, grab: bool) -> Result<(), CphError> {

View file

@ -1,7 +1,7 @@
use {
crate::{
cli::CliLogLevel,
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError, ClientId},
compositor::LogLevel,
globals::{Global, GlobalName},
ifs::{
jay_acceptor_request::JayAcceptorRequest,
@ -35,7 +35,7 @@ use {
},
},
bstr::ByteSlice,
log::Level,
linearize::LinearizeExt,
std::{cell::Cell, ops::Deref, rc::Rc, str::FromStr},
thiserror::Error,
};
@ -185,22 +185,10 @@ impl JayCompositorRequestHandler for JayCompositor {
}
fn set_log_level(&self, req: SetLogLevel, _slf: &Rc<Self>) -> Result<(), Self::Error> {
const ERROR: u32 = CliLogLevel::Error as u32;
const WARN: u32 = CliLogLevel::Warn as u32;
const INFO: u32 = CliLogLevel::Info as u32;
const DEBUG: u32 = CliLogLevel::Debug as u32;
const TRACE: u32 = CliLogLevel::Trace as u32;
let level = match req.level {
ERROR => Level::Error,
WARN => Level::Warn,
INFO => Level::Info,
DEBUG => Level::Debug,
TRACE => Level::Trace,
_ => return Err(JayCompositorError::UnknownLogLevel(req.level)),
let Some(level) = LogLevel::from_linear(req.level as usize) else {
return Err(JayCompositorError::UnknownLogLevel(req.level));
};
if let Some(logger) = &self.client.state.logger {
logger.set_level(level);
}
self.client.state.set_log_level(level);
Ok(())
}

View file

@ -1,8 +1,11 @@
use {
crate::utils::{errorfmt::ErrorFmt, oserror::OsError},
crate::{
compositor::LogLevel,
utils::{atomic_enum::AtomicEnum, errorfmt::ErrorFmt, oserror::OsError},
},
backtrace::Backtrace,
bstr::BString,
log::{Level, Log, Metadata, Record},
log::{LevelFilter, Log, Metadata, Record},
parking_lot::Mutex,
std::{
cell::Cell,
@ -24,14 +27,15 @@ thread_local! {
}
pub struct Logger {
level: AtomicU32,
level: AtomicEnum<LogLevel>,
filter: AtomicU32,
path: Mutex<Arc<BString>>,
_file: Mutex<OwnedFd>,
file_fd: AtomicI32,
}
impl Logger {
pub fn install_stderr(level: Level) -> Arc<Self> {
pub fn install_stderr(level: LogLevel) -> Arc<Self> {
let file = match uapi::fcntl_dupfd_cloexec(2, 0) {
Ok(fd) => fd,
Err(e) => {
@ -42,18 +46,20 @@ impl Logger {
Self::install(level, b"STDERR", file)
}
pub fn install_compositor(level: Level) -> Arc<Self> {
pub fn install_compositor(level: LogLevel) -> Arc<Self> {
let (path, file) = open_log_file("jay");
Self::install(level, path.as_bytes(), file)
}
pub fn install_pipe(file: OwnedFd, level: Level) -> Arc<Self> {
pub fn install_pipe(file: OwnedFd, level: LogLevel) -> Arc<Self> {
Self::install(level, b"PIPE", file)
}
fn install(level: Level, path: &[u8], file: OwnedFd) -> Arc<Self> {
fn install(level: LogLevel, path: &[u8], file: OwnedFd) -> Arc<Self> {
let filter: LevelFilter = level.into();
let slf = Arc::new(Self {
level: AtomicU32::new(level as _),
level: AtomicEnum::new(level),
filter: AtomicU32::new(filter as _),
path: Mutex::new(Arc::new(path.to_vec().into())),
file_fd: AtomicI32::new(file.raw()),
_file: Mutex::new(file),
@ -62,14 +68,21 @@ impl Logger {
logger: slf.clone(),
}))
.unwrap();
log::set_max_level(level.to_level_filter());
log::set_max_level(filter);
set_panic_hook();
slf
}
pub fn set_level(&self, level: Level) {
self.level.store(level as _, Relaxed);
log::set_max_level(level.to_level_filter());
pub fn set_level(&self, level: LogLevel) {
let filter: LevelFilter = level.into();
self.level.store(level, Relaxed);
self.filter.store(filter as _, Relaxed);
log::set_max_level(filter);
}
#[expect(dead_code)]
pub fn level(&self) -> LogLevel {
self.level.load(Relaxed)
}
pub fn path(&self) -> Arc<BString> {
@ -166,11 +179,11 @@ struct LogWrapper {
impl Log for LogWrapper {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() as u32 <= self.logger.level.load(Relaxed)
metadata.level() as u32 <= self.logger.filter.load(Relaxed)
}
fn log(&self, record: &Record) {
if record.level() as u32 > self.logger.level.load(Relaxed) {
if record.level() as u32 > self.logger.filter.load(Relaxed) {
return;
}
let mut buffer = BUFFER.get();

View file

@ -11,6 +11,7 @@ use {
async_engine::AsyncEngine,
cli::GlobalArgs,
cmm::cmm_manager::ColorManager,
compositor::LogLevel,
dbus::{
BUS_DEST, BUS_PATH, DBUS_NAME_FLAG_DO_NOT_QUEUE, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER,
Dbus, DbusSocket,
@ -44,7 +45,6 @@ use {
wheel::Wheel,
wire_dbus::org,
},
log::Level,
std::{
ffi::OsStr,
io::{BufReader, BufWriter},
@ -64,7 +64,7 @@ const PORTAL_CANCELLED: u32 = 1;
const PORTAL_ENDED: u32 = 2;
pub fn run_freestanding(global: GlobalArgs) {
let logger = Logger::install_stderr(global.log_level.into());
let logger = Logger::install_stderr(global.log_level);
run(logger, true);
}
@ -131,7 +131,7 @@ impl PortalStartup {
}
}
pub fn run_from_compositor(level: Level) -> Result<PortalStartup, PortalError> {
pub fn run_from_compositor(level: LogLevel) -> Result<PortalStartup, PortalError> {
let Pipe { read, write } = match pipe() {
Ok(p) => p,
Err(e) => return Err(PortalError::CreatePipe(e)),

View file

@ -13,7 +13,7 @@ use {
client::{Client, ClientCaps, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
clientmem::ClientMemOffset,
cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager},
compositor::LIBEI_SOCKET,
compositor::{LIBEI_SOCKET, LogLevel},
config::ConfigProxy,
copy_device::CopyDeviceRegistry,
cpu_worker::CpuWorker,
@ -1690,6 +1690,12 @@ impl State {
self.explicit_sync_enabled.set(enabled);
self.expose_new_singletons();
}
pub fn set_log_level(&self, level: LogLevel) {
if let Some(logger) = &self.logger {
logger.set_level(level);
}
}
}
#[derive(Debug, Error)]

View file

@ -2,7 +2,7 @@ use {
crate::{
async_engine::{AsyncEngine, SpawnedFuture},
client::{EventFormatter, RequestParser},
compositor::WAYLAND_DISPLAY,
compositor::{LogLevel, WAYLAND_DISPLAY},
io_uring::{IoUring, IoUringError},
logger::Logger,
object::{ObjectId, WL_DISPLAY_ID},
@ -30,7 +30,6 @@ use {
},
},
ahash::AHashMap,
log::Level,
std::{
cell::{Cell, RefCell},
collections::VecDeque,
@ -97,7 +96,7 @@ pub struct ToolClient {
jay_damage_tracking: Cell<Option<Option<JayDamageTrackingId>>>,
}
pub fn with_tool_client<T, F>(level: Level, f: F)
pub fn with_tool_client<T, F>(level: LogLevel, f: F)
where
F: FnOnce(Rc<ToolClient>) -> T + 'static,
T: Future<Output = ()> + 'static,
@ -111,7 +110,7 @@ fn handle_error(e: ToolClientError) -> ! {
fatal!("Could not create a tool client: {}", ErrorFmt(e));
}
fn with_tool_client_<T, F>(level: Level, f: F) -> Result<(), ToolClientError>
fn with_tool_client_<T, F>(level: LogLevel, f: F) -> Result<(), ToolClientError>
where
F: FnOnce(Rc<ToolClient>) -> T + 'static,
T: Future<Output = ()> + 'static,

View file

@ -31,12 +31,10 @@ where
}
}
#[expect(dead_code)]
pub fn load(&self, ordering: Ordering) -> T {
unsafe { T::from_linear_unchecked(self.v.load(ordering)) }
}
#[expect(dead_code)]
pub fn store(&self, t: T, ordering: Ordering) {
self.v.store(t.linearize(), ordering);
}