Skip to content

Commit

Permalink
Implement logging to file
Browse files Browse the repository at this point in the history
  • Loading branch information
thorio committed Jun 15, 2024
1 parent 9a9c010 commit 103e106
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 20 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ members = [
[workspace.dependencies]
anyhow = "1.0.86"
arboard = "3.4.0"
chrono = { version = "0.4.38", default-features = false }
clap = "4.5.7"
clap-verbosity-flag = "2.2.0"
color-eyre = "0.6.3"
enumflags2 = "0.7.10"
exec = "0.3.1"
fern = "0.6.2"
file-rotate = "0.7.6"
fltk = "1.4.31"
freedesktop_entry_parser = "1.3.0"
fuzzy-matcher = "0.3.7"
Expand Down Expand Up @@ -66,3 +69,4 @@ explicit_iter_loop = "warn"
question_mark = "warn"
redundant_closure_for_method_calls = "warn"
semicolon_if_nothing_returned = "warn"
unwrap_used = "warn"
12 changes: 12 additions & 0 deletions gravel-core/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub fn get_gravel_config_dir() -> PathBuf {
get_xdg_config_home().join(APP_NAME)
}

pub fn get_gravel_log_path() -> PathBuf {
get_xdg_state_home().join(APP_NAME).join("gravel.log")
}

fn get_xdg_config_home() -> PathBuf {
if let Ok(path) = env::var("XDG_CONFIG_HOME") {
return path.into();
Expand All @@ -28,6 +32,14 @@ fn get_xdg_config_home() -> PathBuf {
get_home().join(".config")
}

fn get_xdg_state_home() -> PathBuf {
if let Ok(path) = env::var("XDG_STATE_HOME") {
return path.into();
}

get_home().join(".local/state")
}

pub fn get_xdg_data_dirs() -> Vec<PathBuf> {
if let Ok(path) = env::var("XDG_DATA_DIRS") {
return path.split(':').map(PathBuf::from).collect();
Expand Down
2 changes: 1 addition & 1 deletion gravel-provider-exec/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn run_command(cmd: &str) -> Result<()> {
}

fn shell_execute(cmd: &str) -> Result<()> {
let cmd = CString::new(cmd).unwrap();
let cmd = CString::new(cmd)?;

let result = unsafe {
ShellExecuteA(
Expand Down
4 changes: 4 additions & 0 deletions gravel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ gravel-provider-program = { path = "../gravel-provider-program" }
gravel-provider-system = { path = "../gravel-provider-system" }
gravel-provider-websearch = { path = "../gravel-provider-websearch" }

anyhow.workspace = true
chrono = { workspace = true }
clap = { workspace = true, features = ["derive"] }
clap-verbosity-flag.workspace = true
color-eyre.workspace = true
fern.workspace = true
figment = { workspace = true, features = ["yaml"] }
file-rotate.workspace = true
hostname.workspace = true
lazy_static.workspace = true
log.workspace = true
Expand Down
19 changes: 17 additions & 2 deletions gravel/src/init/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use clap::Parser;
use clap_verbosity_flag::{Verbosity, WarnLevel};
use clap_verbosity_flag::{InfoLevel, Verbosity};
use std::path::PathBuf;

pub fn cli() -> Args {
Args::parse()
Expand All @@ -10,5 +11,19 @@ pub fn cli() -> Args {
#[command(propagate_version = true)]
pub struct Args {
#[command(flatten)]
pub verbosity: Verbosity<WarnLevel>,
pub logging: LogArgs,
}

#[derive(clap::Args, Debug)]
pub struct LogArgs {
#[command(flatten)]
pub verbosity: Verbosity<InfoLevel>,

/// Disable stderr logging
#[arg(long)]
pub no_stderr_log: bool,

/// Defaults to "$XDG_STATE_DIR/gravel/current.log"; Set to "off" to disable
#[arg(long)]
pub log_file: Option<PathBuf>,
}
62 changes: 56 additions & 6 deletions gravel/src/init/logging.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,60 @@
use log::LevelFilter;
use super::cli::LogArgs;
use anyhow::Result;
use chrono::Local;
use fern::{Dispatch, FormatCallback};
use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate};
use gravel_core::paths::get_gravel_log_path;
use log::{Log, Record};
use std::fmt::Arguments;
use std::io::Write;
use std::path::Path;

pub fn logging(level: LevelFilter) {
stderrlog::new()
.verbosity(level)
.init()
.expect("this must never be called twice");
pub fn logging(args: LogArgs) -> Result<()> {
let mut dispatch = Dispatch::new().level(args.verbosity.log_level_filter());

if !args.no_stderr_log {
dispatch = chain_stderr(dispatch);
}

let log_path = &args.log_file.unwrap_or(get_gravel_log_path());
if !matches!(log_path.to_str(), Some("off")) {
dispatch = chain_file(dispatch, log_path)?;
}

dispatch.apply()?;

log::trace!("hello world");

Ok(())
}

fn chain_stderr(dispatch: Dispatch) -> Dispatch {
let mut stderrlog = stderrlog::new();
stderrlog.verbosity(4);

dispatch.chain(Box::new(stderrlog) as Box<dyn Log>)
}

fn chain_file(dispatch: Dispatch, path: &Path) -> Result<Dispatch> {
fn format_line(out: FormatCallback, message: &Arguments, record: &Record) {
let level = record.level();
let target = record.target();
let timestamp = Local::now().format("%Y-%m-%dT%H:%M:%S");
out.finish(format_args!("{level:<5} {timestamp} [{target}] {message}"));
}

let rotate = FileRotate::new(
path,
AppendCount::new(2),
ContentLimit::Lines(2000),
Compression::None,
#[cfg(unix)]
None,
);

let file_dispatch = Dispatch::new()
.format(format_line)
.chain(Box::new(rotate) as Box<dyn Write + Send>);

Ok(dispatch.chain(file_dispatch))
}
27 changes: 16 additions & 11 deletions gravel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,35 @@
// Without this, windows will open an additional console window for the application
#![windows_subsystem = "windows"]

use anyhow::{Context, Result};
use gravel_core::{performance::Stopwatch, *};
use std::{env, path::Path, sync::mpsc};

mod init;

// unwrap instead of returning a Result so we hit color_eyre's panic handler
#[allow(clippy::unwrap_used)]
fn main() {
color_eyre::install().unwrap();

#[cfg(windows)]
init::windows_console::attach();

run();
run().unwrap();

#[cfg(windows)]
init::windows_console::detach();

log::trace!("exiting");
log::debug!("exiting");
}

fn run() {
fn run() -> Result<()> {
let stopwatch = Stopwatch::start();

let executable = env::current_exe().unwrap();
let executable = env::current_exe()?;

let args = init::cli();
init::logging(args.verbosity.log_level_filter());
init::logging(args.logging).context("logger error")?;

let config = init::config();

Expand All @@ -43,29 +46,31 @@ fn run() {

init::hotkeys(&config.root.hotkeys, sender);

log::trace!("initialization complete, took {stopwatch}");
log::info!("initialization complete, took {stopwatch}");
log::trace!("starting frontend");
let exit_status = frontend.run(receiver);

drop(single_instance);

match exit_status {
FrontendExitStatus::Exit => (),
FrontendExitStatus::Exit => Ok(()),
FrontendExitStatus::Restart => restart(&executable),
};
}
}

fn restart(executable: &Path) {
fn restart(executable: &Path) -> Result<()> {
log::debug!("attempting to restart gravel");

#[cfg(unix)]
panic!("{:?}", exec::execvp(executable, env::args()));
anyhow::bail!(exec::execvp(executable, env::args()));

#[cfg(not(unix))]
{
// Windows doesn't like the first arg being the binary path
let args = env::args().skip(1);

std::process::Command::new(executable).args(args).spawn().unwrap();
std::process::Command::new(executable).args(args).spawn()?;

Ok(())
}
}

0 comments on commit 103e106

Please sign in to comment.