Logging
Use case
You need structured logging with levels (debug, info, warn, error) and control over what is shown at runtime. The log crate defines the API; env_logger is a simple implementation that reads the RUST_LOG environment variable.
In C#: Like ILogger / ILogger<T> and Serilog or NLog. In Rust, the log crate is the facade; you choose the backend (e.g. env_logger, tracing).
Initializing the logger
Call env_logger::init() once at startup (e.g. in main). It reads RUST_LOG to set the minimum level and which modules to show.
fn main() {
env_logger::init();
log::info!("starting");
}Run with RUST_LOG=info cargo run or RUST_LOG=debug to see debug. In C#: Like configuring log level in appsettings or environment.
Log levels
Use log::trace!, log::debug!, log::info!, log::warn!, log::error!. Only messages at or above the configured level are printed.
log::debug!("detail: {:?}", data);
log::info!("request completed");
log::warn!("deprecated API used");
log::error!("failed: {}", e);In C#: Like _logger.LogDebug, LogInformation, LogWarning, LogError.
RUST_LOG
Set per-module or global: RUST_LOG=info (all crates at info), RUST_LOG=myapp=debug (only myapp at debug), RUST_LOG=debug,myapp=trace.
In C#: Similar to log level filters per namespace or app.
Common pitfalls
env_logger::init()panics if called twice. It installs the global logger, which can only be set once — calling it again (e.g. in every test, or inside a library) panics with "env_logger::init should not be called after logger initialized". In tests/libraries uselet _ = env_logger::try_init();(returns aResult) instead.- No output? Set
RUST_LOG. WithRUST_LOGunset you'll see little or nothing; you needRUST_LOG=info(or=debug) to see those levels.
In C#: registering a logging provider twice is normally harmless; here it's a hard panic, so guard re-initialization.
Key takeaway
Use the log crate macros; call env_logger::init() once. Control output with RUST_LOG. For production, consider tracing for structured spans and events.