feat(logging): add --log arg to enable logs
and/or to pass a custom log directory.
This commit is contained in:
parent
843c4d019d
commit
e094d7d81b
@ -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.
|
||||||
|
|||||||
16
src/args.rs
16
src/args.rs
@ -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")]
|
||||||
|
|||||||
@ -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)?;
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
30
src/main.rs
30
src/main.rs
@ -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();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user