refactor: standardize structured logging across Rust and TypeScript

Convert string interpolation to structured fields in tracing/LogTape calls. Add target prefixes (rust::, bun:) to differentiate processes in combined logs.
This commit is contained in:
2026-01-13 15:33:08 -06:00
parent fe23967c5e
commit 6d8766d3a6
5 changed files with 35 additions and 21 deletions
+7 -7
View File
@@ -72,8 +72,8 @@ impl SessionManager {
}
tracing::info!(
"Loaded {} active sessions from database",
self.sessions.len()
session_count = self.sessions.len(),
"Loaded active sessions from database"
);
Ok(())
@@ -111,7 +111,7 @@ impl SessionManager {
self.sessions.insert(id, session.clone());
tracing::debug!("Created session {} for user {}", id, user_id);
tracing::debug!(session_id = %id, user_id, "Created session");
Ok(session)
}
@@ -139,7 +139,7 @@ impl SessionManager {
.execute(&self.pool)
.await?;
tracing::debug!("Deleted session {}", session_id);
tracing::debug!(session_id = %session_id, "Deleted session");
Ok(())
}
@@ -157,7 +157,7 @@ impl SessionManager {
self.sessions.retain(|_, session| session.expires_at >= now);
if expired_count > 0 {
tracing::info!("Cleaned up {} expired sessions", expired_count);
tracing::info!(expired_count, "Cleaned up expired sessions");
}
Ok(expired_count)
@@ -234,9 +234,9 @@ pub async fn ensure_admin_user(pool: &PgPool) -> Result<(), Box<dyn std::error::
if get_admin_user(pool, &username).await?.is_none() {
create_admin_user(pool, &username, &password).await?;
tracing::info!("Created admin user: {}", username);
tracing::info!(username, "Created admin user");
} else {
tracing::debug!("Admin user '{}' already exists", username);
tracing::debug!(username, "Admin user already exists");
}
Ok(())
+15 -3
View File
@@ -13,6 +13,17 @@ use tracing_subscriber::registry::LookupSpan;
const TIMESTAMP_FORMAT: &[FormatItem<'static>] =
format_description!("[hour]:[minute]:[second].[subsecond digits:3]");
/// Transform tracing target from `api::*` to `rust::*` for combined log differentiation
fn transform_target(target: &str) -> String {
if target == "api" {
"rust".to_string()
} else if let Some(rest) = target.strip_prefix("api::") {
format!("rust::{rest}")
} else {
target.to_string()
}
}
pub struct CustomPrettyFormatter;
impl<S, N> FormatEvent<S, N> for CustomPrettyFormatter
@@ -63,10 +74,11 @@ where
}
}
let target = transform_target(meta.target());
if writer.has_ansi_escapes() {
write!(writer, "{}: ", Color::DarkGray.paint(meta.target()))?;
write!(writer, "{}: ", Color::DarkGray.paint(&target))?;
} else {
write!(writer, "{}: ", meta.target())?;
write!(writer, "{}: ", target)?;
}
ctx.format_fields(writer.by_ref(), event)?;
@@ -189,7 +201,7 @@ where
.unwrap_or_else(|_| String::from("1970-01-01T00:00:00Z")),
message: message.unwrap_or_default(),
level: meta.level().to_string().to_lowercase(),
target: meta.target().to_string(),
target: transform_target(meta.target()),
fields,
};
+3 -5
View File
@@ -88,7 +88,7 @@ async fn main() {
.expect("Failed to connect to database");
// Run migrations on startup
tracing::info!("Running database migrations...");
tracing::info!("Running database migrations");
sqlx::migrate!().run(&pool).await.unwrap_or_else(|e| {
tracing::error!(error = %e, "Migration failed");
std::process::exit(1);
@@ -146,10 +146,8 @@ async fn main() {
tracing::info!(
enabled = tarpit_state.config.enabled,
delay_range_ms = format!(
"{}-{}",
tarpit_state.config.delay_min_ms, tarpit_state.config.delay_max_ms
),
delay_min_ms = tarpit_state.config.delay_min_ms,
delay_max_ms = tarpit_state.config.delay_max_ms,
max_global = tarpit_state.config.max_global_connections,
max_per_ip = tarpit_state.config.max_connections_per_ip,
"Tarpit initialized"