refactor(core): compact human log format, quieter lock lifecycle, nonzero_summary helper
Three quality-of-life improvements to reduce log noise and improve readability: 1. logging.rs: Add CompactHumanFormat for stderr tracing output. Replaces the default format with a minimal 'HH:MM:SS LEVEL message key=value' layout — no span context, no full timestamps, no target module. The JSON file log layer is unaffected. This makes watching 'lore sync' output much cleaner. 2. lock.rs: Downgrade AppLock acquire/release messages from info! to debug!. Lock lifecycle events (acquired new, acquired existing, released) are operational bookkeeping that clutters normal output. They remain visible at -vv verbosity for troubleshooting. 3. ingestion/mod.rs: Add nonzero_summary() utility that formats named counters as a compact middle-dot-separated string, suppressing zero values. Produces output like '42 fetched · 3 labels · 12 notes' instead of verbose key=value structured fields. Returns 'nothing to update' when all values are zero. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::db::create_connection;
|
use super::db::create_connection;
|
||||||
@@ -75,7 +75,7 @@ impl AppLock {
|
|||||||
"INSERT INTO app_locks (name, owner, acquired_at, heartbeat_at) VALUES (?, ?, ?, ?)",
|
"INSERT INTO app_locks (name, owner, acquired_at, heartbeat_at) VALUES (?, ?, ?, ?)",
|
||||||
(&self.name, &self.owner, now, now),
|
(&self.name, &self.owner, now, now),
|
||||||
)?;
|
)?;
|
||||||
info!(owner = %self.owner, "Lock acquired (new)");
|
debug!(owner = %self.owner, "Lock acquired (new)");
|
||||||
}
|
}
|
||||||
Some((existing_owner, acquired_at, heartbeat_at)) => {
|
Some((existing_owner, acquired_at, heartbeat_at)) => {
|
||||||
let is_stale = now - heartbeat_at > self.stale_lock_ms;
|
let is_stale = now - heartbeat_at > self.stale_lock_ms;
|
||||||
@@ -85,7 +85,7 @@ impl AppLock {
|
|||||||
"UPDATE app_locks SET owner = ?, acquired_at = ?, heartbeat_at = ? WHERE name = ?",
|
"UPDATE app_locks SET owner = ?, acquired_at = ?, heartbeat_at = ? WHERE name = ?",
|
||||||
(&self.owner, now, now, &self.name),
|
(&self.owner, now, now, &self.name),
|
||||||
)?;
|
)?;
|
||||||
info!(
|
debug!(
|
||||||
owner = %self.owner,
|
owner = %self.owner,
|
||||||
previous_owner = %existing_owner,
|
previous_owner = %existing_owner,
|
||||||
was_stale = is_stale,
|
was_stale = is_stale,
|
||||||
@@ -125,7 +125,7 @@ impl AppLock {
|
|||||||
"DELETE FROM app_locks WHERE name = ? AND owner = ?",
|
"DELETE FROM app_locks WHERE name = ? AND owner = ?",
|
||||||
(&self.name, &self.owner),
|
(&self.name, &self.owner),
|
||||||
) {
|
) {
|
||||||
Ok(_) => info!(owner = %self.owner, "Lock released"),
|
Ok(_) => debug!(owner = %self.owner, "Lock released"),
|
||||||
Err(e) => error!(
|
Err(e) => error!(
|
||||||
owner = %self.owner,
|
owner = %self.owner,
|
||||||
error = %e,
|
error = %e,
|
||||||
|
|||||||
@@ -1,7 +1,45 @@
|
|||||||
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
use tracing_subscriber::fmt::format::{FormatEvent, FormatFields};
|
||||||
|
use tracing_subscriber::registry::LookupSpan;
|
||||||
|
|
||||||
|
/// Compact stderr formatter: `HH:MM:SS LEVEL message key=value`
|
||||||
|
///
|
||||||
|
/// No span context, no full timestamps, no target — just the essentials.
|
||||||
|
/// The JSON file log is unaffected (it uses its own layer).
|
||||||
|
pub struct CompactHumanFormat;
|
||||||
|
|
||||||
|
impl<S, N> FormatEvent<S, N> for CompactHumanFormat
|
||||||
|
where
|
||||||
|
S: tracing::Subscriber + for<'a> LookupSpan<'a>,
|
||||||
|
N: for<'a> FormatFields<'a> + 'static,
|
||||||
|
{
|
||||||
|
fn format_event(
|
||||||
|
&self,
|
||||||
|
ctx: &tracing_subscriber::fmt::FmtContext<'_, S, N>,
|
||||||
|
mut writer: tracing_subscriber::fmt::format::Writer<'_>,
|
||||||
|
event: &tracing::Event<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
let now = chrono::Local::now();
|
||||||
|
let time = now.format("%H:%M:%S");
|
||||||
|
|
||||||
|
let level = *event.metadata().level();
|
||||||
|
let styled = match level {
|
||||||
|
tracing::Level::ERROR => console::style("ERROR").red().bold(),
|
||||||
|
tracing::Level::WARN => console::style(" WARN").yellow(),
|
||||||
|
tracing::Level::INFO => console::style(" INFO").green(),
|
||||||
|
tracing::Level::DEBUG => console::style("DEBUG").dim(),
|
||||||
|
tracing::Level::TRACE => console::style("TRACE").dim(),
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(writer, "{time} {styled} ")?;
|
||||||
|
ctx.format_fields(writer.by_ref(), event)?;
|
||||||
|
writeln!(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_stderr_filter(verbose: u8, quiet: bool) -> EnvFilter {
|
pub fn build_stderr_filter(verbose: u8, quiet: bool) -> EnvFilter {
|
||||||
if std::env::var("RUST_LOG").is_ok() {
|
if std::env::var("RUST_LOG").is_ok() {
|
||||||
|
|||||||
@@ -14,6 +14,22 @@ pub use merge_requests::{
|
|||||||
ingest_merge_requests,
|
ingest_merge_requests,
|
||||||
};
|
};
|
||||||
pub use mr_discussions::{IngestMrDiscussionsResult, ingest_mr_discussions};
|
pub use mr_discussions::{IngestMrDiscussionsResult, ingest_mr_discussions};
|
||||||
|
/// Format a set of named counters as a compact human-readable summary,
|
||||||
|
/// filtering out zero values and joining with middle-dot separators.
|
||||||
|
/// Returns `"nothing to update"` when all values are zero.
|
||||||
|
pub(crate) fn nonzero_summary(pairs: &[(&str, usize)]) -> String {
|
||||||
|
let parts: Vec<String> = pairs
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| *v > 0)
|
||||||
|
.map(|(k, v)| format!("{v} {k}"))
|
||||||
|
.collect();
|
||||||
|
if parts.is_empty() {
|
||||||
|
"nothing to update".to_string()
|
||||||
|
} else {
|
||||||
|
parts.join(" \u{b7} ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub use orchestrator::{
|
pub use orchestrator::{
|
||||||
DrainResult, IngestMrProjectResult, IngestProjectResult, ProgressCallback, ProgressEvent,
|
DrainResult, IngestMrProjectResult, IngestProjectResult, ProgressCallback, ProgressEvent,
|
||||||
ingest_project_issues, ingest_project_issues_with_progress, ingest_project_merge_requests,
|
ingest_project_issues, ingest_project_issues_with_progress, ingest_project_merge_requests,
|
||||||
|
|||||||
Reference in New Issue
Block a user