Add comprehensive logging with tracing, file rotation, and systemd integration

- Add tracing-appender and tracing-journald for production logging
- Add LoggingConfig with trace_sample_rate, json_output, journald options
- Expand init_logging() with file rotation, journald, and stderr layers
- Add sanitize_path() helper for PII protection in logs
- Instrument FUSE operations with #[instrument] and trace decision points
- Instrument gRPC handlers (10 methods) with span correlation
- Add spawn instrumentation for health monitor, indexer, watcher tasks
- Add broadcast lag handling (RecvError::Lagged) in event subscribers
- Fix webhook.rs expect() calls with proper error handling
- Add logging to patterns.rs, collections.rs, artwork.rs database ops
- Add Drop impl logging for PluginManager and WatchHandle
- Update systemd service with rate limiting and journal output
- Add logrotate config and example config.toml with logging section
This commit is contained in:
Alexander
2026-05-13 11:21:51 +02:00
parent bc9fa36646
commit 5ac33987c0
32 changed files with 1646 additions and 177 deletions
+13 -8
View File
@@ -4,7 +4,7 @@ use musicfs_origins::Origin;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use std::time::SystemTime;
use tracing::{debug, info};
use tracing::{debug, info, trace};
#[derive(Debug, Clone)]
pub struct ScannedFile {
@@ -66,9 +66,13 @@ impl DeltaDetector {
cached: &HashMap<FileId, FileMeta>,
manifests: &HashMap<FileId, Vec<ManifestChunk>>,
) -> Result<ChangeSet, DeltaError> {
let origin_id = origin.id().clone();
info!(origin_id = %origin_id, "Starting delta detection");
let mut changes = ChangeSet::default();
let origin_files = self.scan_origin(origin).await?;
trace!(origin_id = %origin_id, scanned_count = origin_files.len(), "Completed origin scan");
let cached_by_path: HashMap<_, _> = cached
.values()
@@ -78,7 +82,7 @@ impl DeltaDetector {
for scanned in &origin_files {
if let Some(cached_file) = cached_by_path.get(&scanned.path) {
if self.is_modified_scan(cached_file, scanned) {
debug!("File modified: {:?}", scanned.path);
debug!(origin_id = %origin_id, path = ?scanned.path, "File modified");
if let Some(old_chunks) = manifests.get(&cached_file.id) {
let new_chunks = self.compute_chunks_for_scan(origin, scanned).await?;
@@ -87,7 +91,7 @@ impl DeltaDetector {
}
}
} else {
debug!("File added: {:?}", scanned.path);
debug!(origin_id = %origin_id, path = ?scanned.path, "File added");
changes.added.push(scanned.clone());
}
}
@@ -96,16 +100,17 @@ impl DeltaDetector {
for cached_file in cached.values() {
if !origin_paths.contains(&cached_file.real_path.path) {
debug!("File removed: {:?}", cached_file.real_path.path);
debug!(origin_id = %origin_id, path = ?cached_file.real_path.path, "File removed");
changes.removed.push(cached_file.id);
}
}
info!(
"Delta detection complete: {} added, {} removed, {} modified",
changes.added.len(),
changes.removed.len(),
changes.modified.len()
origin_id = %origin_id,
files_added = changes.added.len(),
files_removed = changes.removed.len(),
files_modified = changes.modified.len(),
"Delta detection complete"
);
Ok(changes)
+16 -11
View File
@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::mpsc;
use tracing::{debug, error, info};
use tracing::{error, info, info_span, trace, Instrument};
const DEBOUNCE_MS: u64 = 200;
@@ -31,11 +31,15 @@ impl OriginWatcher {
let root = self.root.clone();
let event_bus = self.event_bus.clone();
tokio::spawn(async move {
if let Err(e) = Self::watch_loop(&origin_id, &root, &event_bus, &mut stop_rx).await {
error!("Watcher error: {}", e);
let origin_id_str = origin_id.to_string();
tokio::spawn(
async move {
if let Err(e) = Self::watch_loop(&origin_id, &root, &event_bus, &mut stop_rx).await {
error!("Watcher error: {}", e);
}
}
});
.instrument(info_span!("file_watcher", origin_id = %origin_id_str)),
);
WatchHandle { stop_tx }
}
@@ -62,7 +66,7 @@ impl OriginWatcher {
.watch(root, RecursiveMode::Recursive)
.map_err(|e| WatchError::Watch(e.to_string()))?;
info!("Watching origin {} at {:?}", origin_id, root);
info!(origin_id = %origin_id, path = ?root, "Watcher started");
let mut debouncer: HashMap<PathBuf, Instant> = HashMap::new();
@@ -72,7 +76,7 @@ impl OriginWatcher {
Self::handle_notify_event(origin_id, root, event_bus, event, &mut debouncer);
}
_ = stop_rx.recv() => {
info!("Stopping watcher for {}", origin_id);
info!(origin_id = %origin_id, "Watcher stopped");
break;
}
}
@@ -104,7 +108,7 @@ impl OriginWatcher {
if let Some(last_seen) = debouncer.get(&relative) {
if now.duration_since(*last_seen).as_millis() < DEBOUNCE_MS as u128 {
debug!("Debouncing event for {:?}", relative);
trace!(origin_id = %origin_id, path = ?relative, "Debouncing event");
continue;
}
}
@@ -114,18 +118,18 @@ impl OriginWatcher {
match event.kind {
EventKind::Create(_) => {
debug!("File created: {:?}", relative);
trace!(origin_id = %origin_id, path = ?relative, "File created");
event_bus.publish(Event::FileAdded {
path: vpath,
origin_id: origin_id.clone(),
});
}
EventKind::Remove(_) => {
debug!("File removed: {:?}", relative);
trace!(origin_id = %origin_id, path = ?relative, "File removed");
event_bus.publish(Event::FileRemoved { path: vpath, file_id: None });
}
EventKind::Modify(_) => {
debug!("File modified: {:?}", relative);
trace!(origin_id = %origin_id, path = ?relative, "File modified");
event_bus.publish(Event::FileModified { path: vpath });
}
_ => {}
@@ -156,6 +160,7 @@ impl WatchHandle {
impl Drop for WatchHandle {
fn drop(&mut self) {
trace!("WatchHandle dropped");
let _ = self.stop_tx.try_send(());
}
}