feat(logging): add --log arg to enable logs

and/or to pass a custom log directory.
This commit is contained in:
jk 2025-02-06 20:33:52 +01:00
parent 843c4d019d
commit e094d7d81b
No known key found for this signature in database
5 changed files with 58 additions and 11 deletions

View File

@ -78,8 +78,8 @@ Options:
-r, --reset Reset stored values to default values. -r, --reset Reset stored values to default values.
-n, --notification <NOTIFICATION> Toggle desktop notifications. Experimental. [possible values: on, off] -n, --notification <NOTIFICATION> Toggle desktop notifications. Experimental. [possible values: on, off]
--blink <BLINK> Toggle blink mode to animate a clock when it reaches its finished mode. [possible values: on, off] --blink <BLINK> Toggle blink mode to animate a clock when it reaches its finished mode. [possible values: on, off]
--log [<LOG>] Directory to store log file. If not set, standard application log directory is used (check README for details).
-h, --help Print help -h, --help Print help
-V, --version Print version
``` ```
Extra option (if `--features sound` is enabled by local build only): Extra option (if `--features sound` is enabled by local build only):
@ -185,7 +185,9 @@ C:/Users/{user}/AppData/Local/timr-tui/data/app.data
## Logs ## Logs
In `debug` mode only. Locations: To get log output, start the app by passing `--log` to `timr-tui`. See [CLI](./#cli) for details.
Logs will be stored in an `app.log` file at following locations:
```sh ```sh
# Linux # Linux
@ -195,3 +197,5 @@ In `debug` mode only. Locations:
# `Windows` # `Windows`
C:/Users/{user}/AppData/Local/timr-tui/logs/app.log C:/Users/{user}/AppData/Local/timr-tui/logs/app.log
``` ```
Optional: You can use a custom directory by passing it via `--log` arg.

View File

@ -5,10 +5,11 @@ use crate::{
#[cfg(feature = "sound")] #[cfg(feature = "sound")]
use crate::{sound, sound::SoundError}; use crate::{sound, sound::SoundError};
use clap::Parser; use clap::Parser;
#[cfg(feature = "sound")]
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
pub const LOG_DIRECTORY_DEFAULT_MISSING_VALUE: &str = " "; // empty string
#[derive(Parser)] #[derive(Parser)]
#[command(version)] #[command(version)]
pub struct Args { pub struct Args {
@ -66,6 +67,19 @@ pub struct Args {
value_parser = sound_file_parser, value_parser = sound_file_parser,
)] )]
pub sound: Option<PathBuf>, pub sound: Option<PathBuf>,
#[arg(
long,
// allows both --log=path and --log path syntax
num_args = 0..=1,
// Note: If no value is passed, use a " " by default,
// this value will be checked later in `main`
// to use another (default) log directory instead
default_missing_value=LOG_DIRECTORY_DEFAULT_MISSING_VALUE,
help = "Directory to store log file. If not set, standard application log directory is used (check README for details).",
value_hint = clap::ValueHint::DirPath,
)]
pub log: Option<PathBuf>,
} }
#[cfg(feature = "sound")] #[cfg(feature = "sound")]

View File

@ -5,16 +5,17 @@ use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
pub struct Config { pub struct Config {
// silence `field `log_dir` is never read` the easy way
#[cfg_attr(not(debug_assertions), allow(dead_code))]
pub log_dir: PathBuf, pub log_dir: PathBuf,
pub data_dir: PathBuf, pub data_dir: PathBuf,
} }
impl Config { impl Config {
pub fn init() -> Result<Self> { pub fn init() -> Result<Self> {
// default logs dir
let log_dir = get_default_state_dir()?.join("logs"); let log_dir = get_default_state_dir()?.join("logs");
fs::create_dir_all(&log_dir)?; fs::create_dir_all(&log_dir)?;
// default data dir
let data_dir = get_default_state_dir()?.join("data"); let data_dir = get_default_state_dir()?.join("data");
fs::create_dir_all(&data_dir)?; fs::create_dir_all(&data_dir)?;

View File

@ -1,4 +1,4 @@
use color_eyre::eyre::Result; use color_eyre::eyre::{eyre, Result};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
@ -17,7 +17,13 @@ impl Logger {
pub fn init(&self) -> Result<()> { pub fn init(&self) -> Result<()> {
let log_path = self.log_dir.join("app.log"); let log_path = self.log_dir.join("app.log");
let log_file = fs::File::create(log_path)?; let log_file = fs::File::create(log_path).map_err(|err| {
eyre!(
"Could not create a log file in {:?} : {}",
self.log_dir,
err
)
})?;
let fmt_layer = tracing_subscriber::fmt::layer() let fmt_layer = tracing_subscriber::fmt::layer()
.with_file(true) .with_file(true)
.with_line_number(true) .with_line_number(true)

View File

@ -3,7 +3,6 @@ mod common;
mod config; mod config;
mod constants; mod constants;
mod events; mod events;
#[cfg(debug_assertions)]
mod logging; mod logging;
mod args; mod args;
@ -17,21 +16,44 @@ mod widgets;
mod sound; mod sound;
use app::{App, FromAppArgs}; use app::{App, FromAppArgs};
use args::Args; use args::{Args, LOG_DIRECTORY_DEFAULT_MISSING_VALUE};
use clap::Parser; use clap::Parser;
use color_eyre::Result; use color_eyre::Result;
use config::Config; use config::Config;
use std::path::PathBuf;
use storage::{AppStorage, Storage}; use storage::{AppStorage, Storage};
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// init `Config`
let cfg = Config::init()?; let cfg = Config::init()?;
#[cfg(debug_assertions)]
logging::Logger::new(cfg.log_dir).init()?;
color_eyre::install()?; color_eyre::install()?;
// get args given by CLI // get args given by CLI
let args = Args::parse(); let args = Args::parse();
// Note:
// `log` arg can have three different values:
// (1) not set => None
// (2) set with path => Some(Some(path))
// (3) set without path => Some(None)
let custom_log_dir: Option<Option<&PathBuf>> = if let Some(path) = &args.log {
if path.ne(PathBuf::from(LOG_DIRECTORY_DEFAULT_MISSING_VALUE).as_os_str()) {
// (2)
Some(Some(path))
} else {
// (3)
Some(None)
}
} else {
// (1)
None
};
if let Some(log_dir) = custom_log_dir {
let dir: PathBuf = log_dir.unwrap_or(&cfg.log_dir).to_path_buf();
logging::Logger::new(dir).init()?;
}
let mut terminal = terminal::setup()?; let mut terminal = terminal::setup()?;
let events = events::Events::new(); let events = events::Events::new();