-
Notifications
You must be signed in to change notification settings - Fork 1
feat: implement comprehensive logging system with tracing #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,35 +12,52 @@ use bodo::{ | |
BodoError, | ||
}; | ||
use clap::Parser; | ||
use log::{error, LevelFilter}; | ||
use std::{collections::HashMap, process::exit}; | ||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; | ||
|
||
fn main() { | ||
let args = Args::parse(); | ||
|
||
if args.debug { | ||
// Set log level based on flags | ||
if args.verbose || args.debug { | ||
std::env::set_var("RUST_LOG", "bodo=debug"); | ||
} else if args.quiet { | ||
std::env::set_var("RUST_LOG", "bodo=error"); | ||
} else if std::env::var("RUST_LOG").is_err() { | ||
std::env::set_var("RUST_LOG", "bodo=info"); | ||
} | ||
env_logger::Builder::from_default_env() | ||
.filter_module( | ||
"bodo", | ||
if args.debug { | ||
LevelFilter::Debug | ||
} else { | ||
LevelFilter::Info | ||
}, | ||
) | ||
|
||
// Set up log file rotation | ||
let file_appender = tracing_appender::rolling::daily("logs", "bodo.log"); | ||
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); | ||
|
||
// Create layers | ||
let console_layer = tracing_subscriber::fmt::layer() | ||
.with_target(false) | ||
.with_thread_ids(false) | ||
.with_thread_names(false); | ||
|
||
let file_layer = tracing_subscriber::fmt::layer() | ||
.with_writer(non_blocking) | ||
.json() | ||
.with_target(false) | ||
.with_thread_ids(false) | ||
.with_thread_names(false); | ||
|
||
// Initialize tracing subscriber with both layers | ||
tracing_subscriber::registry() | ||
.with(tracing_subscriber::EnvFilter::from_default_env()) | ||
.with(console_layer) | ||
.with(file_layer) | ||
.init(); | ||
|
||
if let Err(e) = run(args) { | ||
error!("Error: {}", e); | ||
if let Err(e) = run(args, guard) { | ||
tracing::error!("Error: {}", e); | ||
exit(1); | ||
} | ||
} | ||
|
||
fn run(args: Args) -> Result<(), BodoError> { | ||
fn run(args: Args, _guard: tracing_appender::non_blocking::WorkerGuard) -> Result<(), BodoError> { | ||
Comment on lines
+54
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Suggested concrete fix for WorkerGuard lifetime: keep the guard in main and restore the original run signature. For example: Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
let watch_mode = if std::env::var("BODO_NO_WATCH").is_ok() { | ||
false | ||
} else if args.auto_watch { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ use crate::{ | |
Result, | ||
}; | ||
use globset::{Glob, GlobSet, GlobSetBuilder}; | ||
use log::{debug, error, warn}; | ||
use notify::{Config as NotifyConfig, Event, RecommendedWatcher, RecursiveMode, Watcher}; | ||
use std::{ | ||
any::Any, | ||
|
@@ -57,7 +56,7 @@ impl WatchPlugin { | |
// Here we'll keep it simpler and just store a flag we can read in on_after_run. | ||
|
||
fn create_watcher() -> Result<(RecommendedWatcher, Receiver<notify::Result<Event>>)> { | ||
debug!("Creating file watcher with 1s poll interval"); | ||
tracing::debug!("Creating file watcher with 1s poll interval"); | ||
let (tx, rx) = mpsc::channel(); | ||
let watcher = RecommendedWatcher::new( | ||
move |res| { | ||
|
@@ -84,7 +83,7 @@ impl WatchPlugin { | |
let cwd = match std::env::current_dir() { | ||
Ok(path) => path, | ||
Err(e) => { | ||
warn!("Failed to get current directory: {}", e); | ||
tracing::warn!("Failed to get current directory: {}", e); | ||
return vec![]; | ||
} | ||
}; | ||
|
@@ -93,7 +92,7 @@ impl WatchPlugin { | |
let changed_abs = match changed_path.canonicalize() { | ||
Ok(p) => p, | ||
Err(e) => { | ||
warn!( | ||
tracing::warn!( | ||
"Failed to canonicalize path {}: {}", | ||
changed_path.display(), | ||
e | ||
|
@@ -106,7 +105,7 @@ impl WatchPlugin { | |
let watch_abs = match watch_dir.canonicalize() { | ||
Ok(p) => p, | ||
Err(e) => { | ||
warn!( | ||
tracing::warn!( | ||
"Failed to canonicalize watch dir {}: {}", | ||
watch_dir.display(), | ||
e | ||
|
@@ -218,10 +217,15 @@ impl Plugin for WatchPlugin { | |
auto_watch: true, .. | ||
}) = &task_data.watch | ||
{ | ||
// Found auto_watch == true, enable watch mode only if BODO_NO_WATCH is not set | ||
if std::env::var("BODO_NO_WATCH").is_err() { | ||
self.watch_mode = true; | ||
break; | ||
// Found auto_watch == true, enable watch mode only if BODO_NO_WATCH is not set to "1" | ||
match std::env::var("BODO_NO_WATCH") { | ||
Ok(ref v) if v == "1" => { | ||
// BODO_NO_WATCH is set to "1", do not enable watch mode | ||
} | ||
_ => { | ||
self.watch_mode = true; | ||
break; | ||
} | ||
} | ||
Comment on lines
+220
to
229
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic only disables watch when BODO_NO_WATCH == "1" but main currently disables when the var is set to any value, creating conflicting behavior. Update main to mirror this exact check so both places agree. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
} | ||
} | ||
|
@@ -313,7 +317,7 @@ impl Plugin for WatchPlugin { | |
for d in &all_dirs { | ||
if d.is_dir() { | ||
if let Err(e) = watcher.watch(d, RecursiveMode::Recursive) { | ||
warn!("WatchPlugin: Failed to watch '{}': {}", d.display(), e); | ||
tracing::warn!("WatchPlugin: Failed to watch '{}': {}", d.display(), e); | ||
} | ||
} | ||
} | ||
|
@@ -327,22 +331,22 @@ impl Plugin for WatchPlugin { | |
let event = match rx.recv() { | ||
Ok(e) => e, | ||
Err(_) => { | ||
debug!("WatchPlugin: Watcher channel closed. Exiting loop."); | ||
tracing::debug!("WatchPlugin: Watcher channel closed. Exiting loop."); | ||
break; | ||
} | ||
}; | ||
let event = match event { | ||
Ok(ev) => ev, | ||
Err(err) => { | ||
warn!("WatchPlugin: Watch error: {}", err); | ||
tracing::warn!("WatchPlugin: Watch error: {}", err); | ||
continue; | ||
} | ||
}; | ||
|
||
let now = Instant::now(); | ||
let since_last = now.duration_since(last_run); | ||
if since_last < Duration::from_millis(max_debounce) { | ||
debug!("Debouncing event (too soon after last run)"); | ||
tracing::debug!("Debouncing event (too soon after last run)"); | ||
continue; | ||
} | ||
last_run = now; | ||
|
@@ -402,9 +406,11 @@ impl Plugin for WatchPlugin { | |
options: Some(options), | ||
}; | ||
if let Err(e) = new_manager.run_plugins(Some(plugin_config)) { | ||
error!("WatchPlugin: re-run failed: {}", e); | ||
tracing::error!("WatchPlugin: re-run failed: {}", e); | ||
if self.stop_on_fail { | ||
warn!("WatchPlugin: Stopping watch loop due to re-run failure"); | ||
tracing::warn!( | ||
"WatchPlugin: Stopping watch loop due to re-run failure" | ||
); | ||
return Ok(()); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WorkerGuard is moved into run and dropped before the error log in main, so the file appender may not flush the final error message to the log file. Keep the guard alive in main for the entire program and do not pass it into run.
Copilot uses AI. Check for mistakes.