feat: proper logging framework
Some checks are pending
/ cargo-fmtcheck (push) Waiting to run
/ cargo-clippy (push) Waiting to run
/ cargo-test (push) Waiting to run
/ appimage (push) Waiting to run

This commit is contained in:
Gabriele Musco 2024-12-02 15:11:38 +01:00
parent c78b844b60
commit 61f13dbd8f
17 changed files with 182 additions and 48 deletions

105
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
@ -576,6 +576,8 @@ dependencies = [
"serde_json",
"sha2",
"tokio",
"tracing",
"tracing-subscriber",
"tracker",
"uuid",
"vte4",
@ -1698,6 +1700,15 @@ dependencies = [
"libc",
]
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata 0.1.10",
]
[[package]]
name = "memchr"
version = "2.7.4"
@ -1820,6 +1831,16 @@ dependencies = [
"zbus 4.4.0",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num-conv"
version = "0.1.0"
@ -1945,6 +1966,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "pango"
version = "0.20.6"
@ -2180,8 +2207,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
"regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
]
[[package]]
@ -2192,9 +2228,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.5"
@ -2525,6 +2567,15 @@ dependencies = [
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.3.0"
@ -2713,6 +2764,16 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "time"
version = "0.3.36"
@ -2862,6 +2923,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
@ -2964,6 +3055,12 @@ dependencies = [
"rand",
]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"

View file

@ -31,3 +31,5 @@ sha2 = "0.10.8"
tokio = { version = "1.39.3", features = ["process"] }
notify-rust = "4.11.3"
zbus = { version = "5.1.1", features = ["tokio"] }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
tracing = "0.1.41"

View file

@ -60,6 +60,10 @@ cd envision
</details>
# Debugging
To view all the logs you need to run envision with the env var `RUST_LOG=trace`.
# Common issues
## NOSUID with systemd-homed

View file

@ -5,6 +5,7 @@ use file_builders::{
openvrpaths_vrpath::{get_current_openvrpaths, set_current_openvrpaths_to_steam},
};
use gettextrs::LocaleCategory;
use tracing::warn;
use relm4::{
adw,
gtk::{self, gdk, gio, glib, prelude::*},
@ -12,6 +13,7 @@ use relm4::{
};
use std::env;
use steam_linux_runtime_injector::restore_runtime_entrypoint;
use tracing_subscriber::{filter::LevelFilter, EnvFilter};
use ui::{
app::{App, AppInit, Msg},
cmdline_opts::CmdLineOpts,
@ -51,14 +53,14 @@ fn restore_steam_xr_files() {
if let Some(ar) = active_runtime {
if !file_builders::active_runtime_json::is_steam(&ar) {
if let Err(e) = set_current_active_runtime_to_steam() {
eprintln!("Warning: failed to restore active runtime to steam: {e}");
warn!("failed to restore active runtime to steam: {e}");
}
}
}
if let Some(ovrp) = openvrpaths {
if !file_builders::openvrpaths_vrpath::is_steam(&ovrp) {
if let Err(e) = set_current_openvrpaths_to_steam() {
eprintln!("Warning: failed to restore openvrpaths to steam: {e}");
warn!("failed to restore openvrpaths to steam: {e}");
}
}
}
@ -71,6 +73,15 @@ fn main() -> Result<()> {
}
restore_steam_xr_files();
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.pretty()
.init();
// Prepare i18n
gettextrs::setlocale(LocaleCategory::LcAll, "");
gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR).expect("Unable to bind the text domain");

View file

@ -5,6 +5,7 @@ use crate::{
};
use anyhow::bail;
use lazy_static::lazy_static;
use tracing::error;
use serde::Deserialize;
use std::{
collections::HashMap,
@ -46,7 +47,7 @@ fn get_runtime_entrypoint_path() -> Option<PathBuf> {
let steam_libraryfolders_path = steam_root.join("steamapps/libraryfolders.vdf");
if !steam_libraryfolders_path.is_file() {
eprintln!(
error!(
"Steam libraryfolders.vdf does not exist in its canonical location {}",
steam_libraryfolders_path.to_string_lossy()
);
@ -69,7 +70,7 @@ fn get_runtime_entrypoint_path() -> Option<PathBuf> {
})
}
Err(e) => {
eprintln!("Error getting steam root path: {e}");
error!("Error getting steam root path: {e}");
None
}
}

View file

@ -47,6 +47,7 @@ use crate::{
};
use adw::{prelude::*, ResponseAppearance};
use gtk::glib::{self, clone};
use tracing::error;
use notify_rust::NotificationHandle;
use relm4::{
actions::{AccelsPlus, ActionGroupName, RelmAction, RelmActionGroup},
@ -147,7 +148,7 @@ impl App {
} {
Ok(n) => Some(n),
Err(e) => {
eprintln!("Failed to send desktop notification: {e:?}");
error!("failed to send desktop notification: {e:?}");
None
}
}
@ -196,9 +197,13 @@ impl App {
};
self.debug_view.sender().emit(DebugViewMsg::ClearLog);
self.xr_devices = vec![];
remove_file(prof.xrservice_type.ipc_file_path())
.is_err()
.then(|| println!("Failed to remove xrservice IPC file"));
{
let ipc_file = prof.xrservice_type.ipc_file_path();
if ipc_file.is_file() {
remove_file(ipc_file)
.unwrap_or_else(|e| error!("failed to remove xrservice IPC file: {e}"));
};
}
let worker = JobWorker::xrservice_worker_wrap_from_profile(
&prof,
sender.input_sender(),
@ -409,7 +414,7 @@ impl AsyncComponent for App {
.emit(MainViewMsg::SetWivrnSupportsPairing(true));
}
Err(e) => {
eprintln!("Error: failed to get wivrn pairing mode: {e:?}");
error!("failed to get wivrn pairing mode: {e:?}");
self.main_view
.sender()
.emit(MainViewMsg::SetWivrnSupportsPairing(false));
@ -633,7 +638,7 @@ impl AsyncComponent for App {
}
Msg::RunSetCap => {
if !dep_pkexec().check() {
println!("pkexec not found, skipping setcap");
error!("pkexec not found, skipping setcap");
} else {
let profile = self.get_selected_profile();
setcap_cap_sys_nice_eip(&profile).await;
@ -878,7 +883,7 @@ impl AsyncComponent for App {
match VulkanInfo::get() {
Ok(info) => Some(info),
Err(e) => {
eprintln!("Failed to get Vulkan info: {e:#?}");
error!("failed to get Vulkan info: {e:#?}");
None
}
}

View file

@ -6,6 +6,7 @@ use gtk::{
},
glib::{self, prelude::IsA},
};
use tracing::error;
#[derive(Debug, Clone)]
pub struct CmdLineOpts {
@ -88,7 +89,7 @@ impl CmdLineOpts {
}
return Some(1);
} else {
eprintln!("No profile found for uuid: `{prof_id}`");
error!("No profile found for uuid: `{prof_id}`");
return Some(404);
}
}

View file

@ -6,6 +6,7 @@ use crate::{
profile::{Profile, XRServiceType},
};
use gtk::prelude::*;
use tracing::error;
use relm4::{new_action_group, new_stateless_action, prelude::*};
use std::fs::remove_file;
@ -172,7 +173,7 @@ impl AsyncComponent for InstallWivrnBox {
match get_wivrn_apk_ref(&self.selected_profile) {
Err(GetWivrnApkRefErr::NotWivrn) => {
eprintln!("This is not a WiVRn profile, how did you get here?");
error!("this is not a WiVRn profile, how did you get here?");
}
Err(GetWivrnApkRefErr::RepoDirNotFound) => {
self.set_install_wivrn_status(InstallWivrnStatus::Done(Some(
@ -180,12 +181,12 @@ impl AsyncComponent for InstallWivrnBox {
)));
}
Err(GetWivrnApkRefErr::RepoManipulationFailed(giterr)) => {
eprintln!("Error: failed to manipulate WiVRn repo: {giterr}, falling back to latest release APK");
error!("failed to manipulate WiVRn repo: {giterr}, falling back to latest release APK");
let existing = cache_file_path(WIVRN_LATEST_RELEASE_APK_URL, Some("apk"));
if existing.is_file() {
if let Err(e) = remove_file(&existing) {
eprintln!(
"Failed to remove file {}: {e}",
error!(
"failed to remove file {}: {e}",
existing.to_string_lossy()
);
}
@ -208,7 +209,7 @@ impl AsyncComponent for InstallWivrnBox {
// TODO: we gonna cache or just download async every time?
match cache_file(&url, Some("apk")).await {
Err(e) => {
eprintln!("Failed to download apk: {e}");
error!("failed to download apk: {e}");
self.set_install_wivrn_status(InstallWivrnStatus::Done(Some(
"Error downloading WiVRn client APK".into(),
)));
@ -236,14 +237,14 @@ impl AsyncComponent for InstallWivrnBox {
.into(),
))
} else {
eprintln!("Error: ADB failed with code {}.\nstdout:\n{}\n======\nstderr:\n{}", out.exit_code, out.stdout, out.stderr);
error!("ADB failed with code {}.\nstdout:\n{}\n======\nstderr:\n{}", out.exit_code, out.stdout, out.stderr);
InstallWivrnStatus::Done(Some(
format!("ADB exited with code \"{}\"", out.exit_code)
))
}
}
Err(e) => {
eprintln!("Error: failed to run ADB: {e}");
error!("failed to run ADB: {e}");
InstallWivrnStatus::Done(Some(
"Failed to run ADB".into()
))

View file

@ -4,6 +4,7 @@ use self::{
state::JobWorkerState,
};
use crate::profile::Profile;
use tracing::{error, warn};
use nix::sys::signal::{
kill,
Signal::{SIGKILL, SIGTERM},
@ -97,7 +98,7 @@ impl JobWorker {
self.state.lock().unwrap().stop_requested = true;
if let Some(pid) = self.state.lock().unwrap().current_pid {
if let Err(e) = kill(pid, SIGTERM) {
eprintln!("Failed to send SIGTERM: {e:#?}");
error!("Failed to send SIGTERM: {e}");
}
let state = self.state.clone();
thread::spawn(move || {
@ -105,9 +106,9 @@ impl JobWorker {
if let Ok(s) = state.lock() {
if !s.exited {
// process is still alive
eprintln!("Process is still alive 2 seconds after SIGTERM, proceeding to send SIGKILL...");
warn!("process is still alive 2 seconds after SIGTERM, proceeding to send SIGKILL...");
if let Err(e) = kill(pid, SIGKILL) {
eprintln!("Failed to send SIGKILL: {e:#?}");
error!("failed to send SIGKILL: {e}");
};
}
}

View file

@ -30,6 +30,7 @@ use crate::{
};
use adw::{prelude::*, ResponseAppearance};
use gtk::glib::clone;
use tracing::{error, warn};
use relm4::{
actions::{ActionGroupName, RelmAction, RelmActionGroup},
new_action_group, new_stateless_action,
@ -389,8 +390,8 @@ impl AsyncComponent for MainView {
set_visible: match mount_has_nosuid(&model.selected_profile.prefix) {
Ok(b) => b,
Err(_) => {
eprintln!(
"Warning (nosuid detection): could not get stat on path {}",
warn!(
"nosuid detection: could not get stat on path {}",
model.selected_profile.prefix.to_string_lossy());
false
},
@ -627,7 +628,7 @@ impl AsyncComponent for MainView {
self.set_wivrn_pin(Some(pin));
}
Err(e) => {
eprintln!("Error: failed to get wivrn pairing pin: {e:?}");
error!("failed to get wivrn pairing pin: {e}");
}
};
} else {
@ -637,12 +638,12 @@ impl AsyncComponent for MainView {
}
Self::Input::StopWivrnPairingMode => {
if let Err(e) = wivrn_dbus::disable_pairing().await {
eprintln!("Error: failed to stop wivrn pairing mode: {e:?}");
error!("failed to stop wivrn pairing mode: {e}");
}
}
Self::Input::StartWivrnPairingMode => {
if let Err(e) = wivrn_dbus::enable_pairing().await {
eprintln!("Error: failed to start wivrn pairing mode: {e:?}");
error!("failed to start wivrn pairing mode: {e}");
}
}
Self::Input::StartStopClicked => {

View file

@ -1,4 +1,5 @@
use crate::{constants::APP_NAME, xdg::XDG};
use tracing::{debug, error};
use relm4::{
gtk::{self, prelude::*},
ComponentParts, ComponentSender, SimpleComponent,
@ -59,10 +60,10 @@ impl SimpleComponent for OpenHmdCalibrationBox {
let target = XDG.get_config_home().join("openhmd/rift-room-config.json");
if target.is_file() {
if let Err(e) = std::fs::remove_file(target) {
eprintln!("Failed to remove openhmd config: {e}");
error!("Failed to remove openhmd config: {e}");
}
} else {
println!("info: trying to delete openhmd calibration config, but file is missing")
debug!("trying to delete openhmd calibration config, but file is missing")
}
}
},

View file

@ -4,6 +4,7 @@ use super::job_worker::{
JobWorker,
};
use crate::paths::get_steamvr_bin_dir_path;
use tracing::error;
use relm4::{
gtk::{self, prelude::*},
ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent,
@ -192,7 +193,7 @@ impl SimpleComponent for SteamVrCalibrationBox {
}
Self::Input::OnServerWorkerExit(code) => {
if code != 0 {
eprintln!("Calibration exited with code {code}");
error!("calibration exited with code {code}");
}
self.calibration_running = false;
}

View file

@ -1,4 +1,5 @@
use gtk::{gdk, gio, glib::clone, prelude::*};
use tracing::{error, warn};
pub fn limit_dropdown_width(dd: &gtk::DropDown) {
let mut dd_child = dd
@ -46,14 +47,14 @@ pub fn warning_heading() -> gtk::Box {
pub fn open_with_default_handler(uri: &str) {
if let Err(e) = gio::AppInfo::launch_default_for_uri(uri, gio::AppLaunchContext::NONE) {
eprintln!("Error opening uri {}: {}", uri, e)
error!("opening uri {uri}: {e}")
};
}
pub fn copy_text(txt: &str) {
match gdk::Display::default() {
None => {
eprintln!("Warning: could not get default gdk display")
warn!("could not get default gdk display")
}
Some(d) => {
d.clipboard().set_text(txt);

View file

@ -20,6 +20,7 @@ use crate::{
};
use adw::prelude::*;
use gtk::glib::clone;
use tracing::error;
use relm4::{factory::AsyncFactoryVecDeque, prelude::*};
#[tracker::track]
@ -255,7 +256,7 @@ impl SimpleComponent for WivrnConfEditor {
if let Some(idx) = idx_opt {
self.encoder_models.as_mut().unwrap().guard().remove(idx);
} else {
eprintln!("Couldn't find encoder model with id {id}");
error!("couldn't find encoder model with id {id}");
}
}
}

View file

@ -6,6 +6,7 @@ use crate::{
profile::{Profile, XRServiceType},
};
use gtk::prelude::*;
use tracing::error;
use relm4::prelude::*;
#[derive(PartialEq, Eq, Debug, Clone)]
@ -153,14 +154,14 @@ impl AsyncComponent for WivrnWiredStartBox {
.into(),
))
} else {
eprintln!("Error: ADB failed with code {}.\nstdout:\n{}\n======\nstderr:\n{}", out.exit_code, out.stdout, out.stderr);
error!("ADB failed with code {}.\nstdout:\n{}\n======\nstderr:\n{}", out.exit_code, out.stdout, out.stderr);
StartClientStatus::Done(Some(
format!("ADB exited with code \"{}\"", out.exit_code)
))
}
},
Err(e) => {
eprintln!("Error: failed to run ADB: {e}");
error!("failed to run ADB: {e}");
StartClientStatus::Done(Some(
"Failed to run ADB".into()
))

View file

@ -1,5 +1,6 @@
use crate::{async_process::async_process, profile::Profile};
use anyhow::bail;
use tracing::{debug, error};
use nix::{
errno::Errno,
sys::statvfs::{statvfs, FsFlags},
@ -36,7 +37,7 @@ pub fn get_reader(path: &Path) -> Option<BufReader<File>> {
}
match File::open(path) {
Err(e) => {
eprintln!("Error opening {}: {}", path.to_string_lossy(), e);
error!("Error opening {}: {}", path.to_string_lossy(), e);
None
}
Ok(fd) => Some(BufReader::new(fd)),
@ -48,7 +49,7 @@ pub fn deserialize_file<T: serde::de::DeserializeOwned>(path: &Path) -> Option<T
None => None,
Some(reader) => match serde_json::from_reader(reader) {
Err(e) => {
eprintln!("Failed to deserialize {}: {}", path.to_string_lossy(), e);
error!("Failed to deserialize {}: {}", path.to_string_lossy(), e);
None
}
Ok(res) => Some(res),
@ -58,7 +59,10 @@ pub fn deserialize_file<T: serde::de::DeserializeOwned>(path: &Path) -> Option<T
pub fn set_file_readonly(path: &Path, readonly: bool) -> Result<(), std::io::Error> {
if !path.is_file() {
eprintln!("WARN: trying to set readonly on a file that does not exist");
debug!(
"trying to set readonly on a file that does not exist: {}",
path.to_string_lossy()
);
return Ok(());
}
let mut perms = fs::metadata(path)
@ -83,13 +87,13 @@ pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec<String> {
pub async fn setcap_cap_sys_nice_eip(profile: &Profile) {
if let Err(e) = async_process("pkexec", Some(&setcap_cap_sys_nice_eip_cmd(profile)), None).await
{
eprintln!("Error: failed running setcap: {e}");
error!("failed running setcap: {e}");
}
}
pub fn rm_rf(path: &Path) {
if remove_dir_all(path).is_err() {
eprintln!("Failed to remove path {}", path.to_string_lossy());
error!("failed to remove path {}", path.to_string_lossy());
}
}
@ -102,9 +106,9 @@ pub fn copy_file(source: &Path, dest: &Path) {
}
set_file_readonly(dest, false)
.unwrap_or_else(|_| panic!("Failed to set file {} as rw", dest.to_string_lossy()));
copy(source, dest).unwrap_or_else(|_| {
copy(source, dest).unwrap_or_else(|e| {
panic!(
"Failed to copy {} to {}",
"Failed to copy {} to {}: {e}",
source.to_string_lossy(),
dest.to_string_lossy()
)

View file

@ -1,4 +1,5 @@
use libmonado::{self, BatteryStatus, DeviceRole};
use tracing::error;
use std::{collections::HashMap, fmt::Display, slice::Iter};
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
@ -280,8 +281,8 @@ impl XRDevice {
if let Some(target) = devs.get_mut(&index) {
target.roles.push(role.into());
} else {
eprintln!(
"Could not find device index {index} for role {}",
error!(
"could not find device index {index} for role {}",
XRDeviceRole::from(role)
)
}