Improve logging #106
5 changed files with 77 additions and 9 deletions
|
@ -9,7 +9,7 @@ use druid::im::Vector;
|
||||||
use druid::{FileInfo, ImageBuf};
|
use druid::{FileInfo, ImageBuf};
|
||||||
use dtmt_shared::ModConfig;
|
use dtmt_shared::ModConfig;
|
||||||
use nexusmods::Api as NexusApi;
|
use nexusmods::Api as NexusApi;
|
||||||
use tokio::fs::{self, DirEntry};
|
use tokio::fs::{self, DirEntry, File};
|
||||||
use tokio_stream::wrappers::ReadDirStream;
|
use tokio_stream::wrappers::ReadDirStream;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
use zip::ZipArchive;
|
use zip::ZipArchive;
|
||||||
|
@ -424,6 +424,13 @@ pub(crate) async fn load_initial(path: PathBuf, is_default: bool) -> Result<Init
|
||||||
.await
|
.await
|
||||||
.wrap_err("Failed to read config file")?;
|
.wrap_err("Failed to read config file")?;
|
||||||
|
|
||||||
|
// Create or truncate the log file
|
||||||
|
let log_path = config.data_dir.join("dtmm.log");
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let _ = File::create(&log_path).await;
|
||||||
|
tracing::debug!("Truncated log file");
|
||||||
|
});
|
||||||
|
|
||||||
let game_info = tokio::task::spawn_blocking(dtmt_shared::collect_game_info)
|
let game_info = tokio::task::spawn_blocking(dtmt_shared::collect_game_info)
|
||||||
.await
|
.await
|
||||||
.wrap_err("Failed to collect Steam game info")?;
|
.wrap_err("Failed to collect Steam game info")?;
|
||||||
|
|
|
@ -5,7 +5,10 @@ use color_eyre::Help;
|
||||||
use color_eyre::Report;
|
use color_eyre::Report;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use druid::{ExtEventSink, SingleUse, Target};
|
use druid::{ExtEventSink, SingleUse, Target};
|
||||||
|
use tokio::fs::OpenOptions;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
@ -168,6 +171,15 @@ async fn handle_action(
|
||||||
)
|
)
|
||||||
.expect("failed to send command");
|
.expect("failed to send command");
|
||||||
}),
|
}),
|
||||||
|
AsyncAction::Log((state, line)) => tokio::spawn(async move {
|
||||||
|
if let Ok(mut f) = OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(state.data_dir.join("dtmm.log"))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
let _ = f.write_all(&line).await;
|
||||||
|
}
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,8 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use clap::command;
|
|
||||||
use clap::parser::ValueSource;
|
use clap::parser::ValueSource;
|
||||||
use clap::value_parser;
|
use clap::{command, value_parser, Arg};
|
||||||
use clap::Arg;
|
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use color_eyre::{Report, Result};
|
use color_eyre::{Report, Result};
|
||||||
use druid::AppLauncher;
|
use druid::AppLauncher;
|
||||||
|
@ -19,6 +17,7 @@ use crate::controller::worker::work_thread;
|
||||||
use crate::state::AsyncAction;
|
use crate::state::AsyncAction;
|
||||||
use crate::state::{Delegate, State};
|
use crate::state::{Delegate, State};
|
||||||
use crate::ui::theme;
|
use crate::ui::theme;
|
||||||
|
use crate::util::log::LogLevel;
|
||||||
|
|
||||||
mod controller;
|
mod controller;
|
||||||
mod state;
|
mod state;
|
||||||
|
@ -46,10 +45,22 @@ fn main() -> Result<()> {
|
||||||
.value_parser(value_parser!(PathBuf))
|
.value_parser(value_parser!(PathBuf))
|
||||||
.default_value(default_config_path.to_string_lossy().to_string()),
|
.default_value(default_config_path.to_string_lossy().to_string()),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("log-level")
|
||||||
|
.long("log-level")
|
||||||
|
.help("The maximum level of log events to print")
|
||||||
|
.value_parser(value_parser!(LogLevel))
|
||||||
|
.default_value("info"),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let (log_tx, log_rx) = tokio::sync::mpsc::unbounded_channel();
|
let (log_tx, log_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
util::log::create_tracing_subscriber(log_tx);
|
let level = if matches.value_source("log-level") == Some(ValueSource::DefaultValue) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
matches.get_one::<LogLevel>("log-level").cloned()
|
||||||
|
};
|
||||||
|
util::log::create_tracing_subscriber(log_tx, level);
|
||||||
|
|
||||||
let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel();
|
let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ pub(crate) enum AsyncAction {
|
||||||
SaveSettings(ActionState),
|
SaveSettings(ActionState),
|
||||||
CheckUpdates(ActionState),
|
CheckUpdates(ActionState),
|
||||||
LoadInitial((PathBuf, bool)),
|
LoadInitial((PathBuf, bool)),
|
||||||
|
Log((ActionState, Vec<u8>)),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Delegate {
|
pub(crate) struct Delegate {
|
||||||
|
@ -253,10 +254,22 @@ impl AppDelegate<State> for Delegate {
|
||||||
let line = cmd
|
let line = cmd
|
||||||
.get(ACTION_LOG)
|
.get(ACTION_LOG)
|
||||||
.expect("command type matched but didn't contain the expected value");
|
.expect("command type matched but didn't contain the expected value");
|
||||||
|
|
||||||
if let Some(line) = line.take() {
|
if let Some(line) = line.take() {
|
||||||
let line = String::from_utf8_lossy(&line);
|
{
|
||||||
state.log.push_back(ansi_to_rich_text(line.trim()));
|
let line = String::from_utf8_lossy(&line);
|
||||||
|
state.log.push_back(ansi_to_rich_text(line.trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self
|
||||||
|
.sender
|
||||||
|
.send(AsyncAction::Log((state.clone().into(), line)))
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
tracing::error!("Failed to queue action to add mod");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handled::Yes
|
Handled::Yes
|
||||||
}
|
}
|
||||||
cmd if cmd.is(ACTION_START_SAVE_SETTINGS) => {
|
cmd if cmd.is(ACTION_START_SAVE_SETTINGS) => {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use clap::ValueEnum;
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
use tracing_error::ErrorLayer;
|
use tracing_error::ErrorLayer;
|
||||||
use tracing_subscriber::filter::FilterFn;
|
use tracing_subscriber::filter::FilterFn;
|
||||||
|
@ -7,6 +8,28 @@ use tracing_subscriber::layer::SubscriberExt;
|
||||||
use tracing_subscriber::prelude::*;
|
use tracing_subscriber::prelude::*;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, ValueEnum)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Trace,
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LogLevel> for EnvFilter {
|
||||||
|
fn from(level: LogLevel) -> Self {
|
||||||
|
let filter = match level {
|
||||||
|
LogLevel::Trace => "error,dtmm=trace,sdk=trace",
|
||||||
|
LogLevel::Debug => "error,dtmm=debug,sdk=debug",
|
||||||
|
LogLevel::Info => "error,dtmm=info",
|
||||||
|
LogLevel::Warn => "error,dtmm=warn",
|
||||||
|
LogLevel::Error => "error",
|
||||||
|
};
|
||||||
|
EnvFilter::new(filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ChannelWriter {
|
pub struct ChannelWriter {
|
||||||
tx: UnboundedSender<Vec<u8>>,
|
tx: UnboundedSender<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
@ -32,8 +55,10 @@ impl std::io::Write for ChannelWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_tracing_subscriber(tx: UnboundedSender<Vec<u8>>) {
|
pub fn create_tracing_subscriber(tx: UnboundedSender<Vec<u8>>, level: Option<LogLevel>) {
|
||||||
let env_layer = if cfg!(debug_assertions) {
|
let env_layer = if let Some(level) = level {
|
||||||
|
EnvFilter::from(level)
|
||||||
|
} else if cfg!(debug_assertions) {
|
||||||
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"))
|
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"))
|
||||||
} else {
|
} else {
|
||||||
EnvFilter::new("error,dtmm=info")
|
EnvFilter::new("error,dtmm=info")
|
||||||
|
|
Loading…
Add table
Reference in a new issue