- Use English only - All log messages must be in English
- No emojis - Do not use emojis in log messages
- Structured logging - Include relevant context and metadata in log messages using formatted strings with key-value information
- Avoid verbose logging - Keep log statements concise and meaningful, avoid excessive logging in normal operation paths
| Level | Value | Usage |
|---|---|---|
| TRACE | 0 | Verbose diagnostic info, performance-sensitive paths |
| DEBUG | 1 | Development debugging, internal state |
| INFO | 2 | General operational info (default in dev) |
| WARN | 3 | Potential issues, degraded functionality (default in prod) |
| ERROR | 4 | Failures, exceptions, requires attention |
- Import log macros at the top of the file:
use log::{info, debug, warn, error, trace}; - Include relevant context in log messages using formatted strings:
info!("Registered {} adapter for session: {}", adapter_type, session_id) - Pass Error objects using Display formatting:
error!("Failed to emit event for session {}: {}", session_id, e) - Avoid logging sensitive data (tokens, passwords, PII, API keys)
- Avoid excessive logging in hot paths (loops, frequent callbacks, tight loops)
- Use TRACE for expensive computations that may impact performance
- Include relevant context fields (session_id, request_id, user_id, operation) when available
- Use appropriate log levels - reserve ERROR for actual failures, not expected error conditions
- Keep log messages concise and actionable - focus on what happened and why it matters
- Use conditional logging for expensive operations:
if log::log_enabled!(log::Level::Debug) { ... }
Use shared timing helpers from bitfun_core::util::timing when recording internal durations.
use bitfun_core::util::{elapsed_ms_u64, TimingCollector};
use std::time::Instant;
let started_at = Instant::now();
let duration_ms = elapsed_ms_u64(started_at);
debug!("Git status completed: repo_path={}, duration_ms={}", repo_path, duration_ms);Rules:
- Prefer
elapsed_ms,elapsed_ms_u64, andTimingCollectorover repeatedInstant::now()pluselapsed().as_millis()formatting - Use
duration_msfor Rust diagnostic log keys - Preserve existing protocol and model field names such as
duration_ms,execution_time_ms, orresponse_time_mswhen they are part of events, API responses, or persisted state - Avoid introducing timing logs into tight loops or high-frequency runtime paths unless the diagnostic value clearly justifies it