Expand description
§logwise

An opinionated logging library for Rust with structured logging, privacy-aware data handling, and hierarchical task-based context management.
§Development Status
logwise is experimental and the API may change.
§The Problem
Traditional logging crates like log offer generic log levels
(error, warn, info, debug, trace) that are often too vague for real-world use cases.
This leads to several problems:
- Ambiguous levels: Is
debugfor print-style debugging in your library, or for users debugging their own code? - Build control: How do you compile out expensive logs by default but enable them when debugging user-reported issues?
- Missing use cases: What level is appropriate for “this is slow and should be optimized”?
logwise solves these problems with opinionated, use-case-specific log levels.
§Core Philosophy
Think of log levels like module visibility. You have pub, pub(crate), pub(super), and
private visibility for different use cases. logwise provides similar granular control for logging.
§Log Levels
logwise provides specific log levels for defined use cases:
| Level | Use Case | Build Type | Thread Control |
|---|---|---|---|
trace | Detailed debugging | debug only | Must enable per-thread via Context::begin_trace() |
debuginternal | Print-style debugging | debug only | On by default in current crate, per-thread in downstream |
info | Supporting downstream crates | debug only | On by default |
mandatory | Printf-style debugging | all builds | Always on |
profile | Profiling output | all builds | Always on |
perfwarn | Performance problems with analysis | all builds | Always on |
warning | Suspicious conditions | all builds | Always on |
error | Logging errors in Results | all builds | Always on |
panic | Programmer errors | all builds | Always on |
§Quick Start
§Basic Logging
logwise::declare_logging_domain!();
// Simple structured logging
logwise::info_sync!("User logged in", user_id=42);
// With multiple parameters
logwise::warn_sync!("Request failed",
status=404,
path="/api/users"
);logwise::declare_logging_domain!();
// Async logging for better performance
async fn handle_request() {
logwise::info_async!("Processing request",
method="GET",
endpoint="/health"
);
}§Privacy-Aware Logging
logwise’s privacy system ensures sensitive data is handled appropriately:
logwise::declare_logging_domain!();
use logwise::privacy::{LogIt, IPromiseItsNotPrivate};
#[derive(Debug)]
struct User {
id: u64,
name: String,
email: String,
}
// Complex types require explicit privacy handling
let user = User {
id: 123,
name: "Alice".into(),
email: "alice@example.com".into()
};
// Use LogIt wrapper for complex types
logwise::info_sync!("User created", user=LogIt(&user));
// Mark explicitly non-private data when it's safe
let public_id = "PUBLIC-123";
logwise::info_sync!("Processing {id}",
id=IPromiseItsNotPrivate(public_id)
);§Context and Task Management
Track hierarchical tasks with automatic performance monitoring:
use logwise::context::Context;
// Create a new task
let ctx = Context::new_task(
Some(Context::current()),
"data_processing".to_string(),
logwise::Level::Info,
true,
);
ctx.clone().set_current();
// Enable detailed tracing for debugging
Context::begin_trace();
// Nested tasks automatically track hierarchy
let child_ctx = Context::new_task(
Some(Context::current()),
"parse_csv".to_string(),
logwise::Level::Info,
true,
);
child_ctx.clone().set_current();
// Task completion is logged automatically when dropped§Performance Tracking
Use the perfwarn! macro to track and log slow operations:
logwise::declare_logging_domain!();
// Tracks execution time automatically
logwise::perfwarn!("database_query", {
// Your expensive operation here
perform_database_query()
});
// Logs warning if operation exceeds thresholdFor conditional performance warnings that only log when a threshold is exceeded:
logwise::declare_logging_domain!();
// Only logs if operation takes longer than 100ms
let _interval = logwise::perfwarn_begin_if!(
Duration::from_millis(100),
"slow_operation"
);
fetch_data();
// Warning logged only if threshold exceeded§Heartbeat Monitoring
Use heartbeat to monitor that operations complete within a deadline:
// Create a heartbeat that warns if not completed within 5 seconds
let _guard = logwise::heartbeat("critical_task", Duration::from_secs(5));
critical_task();
// Warning logged if guard is dropped after deadline§Checking Log Level Enablement
Use log_enabled! to check if a log level is enabled before doing expensive work:
logwise::declare_logging_domain!();
use logwise::{Level, log_enabled};
// Skip expensive computation if the log level is disabled
if log_enabled!(Level::Trace) {
let expensive_data = expensive_debug_computation();
logwise::trace_sync!("Debug data: {data}", data=expensive_data);
}§Mandatory Logging
Use mandatory_sync! or mandatory_async! for printf-style debugging that is always enabled, even in release builds:
logwise::declare_logging_domain!();
// This log will appear in all builds
logwise::mandatory_sync!("Debugging value: {value}", value=42);§Profiling
Use profiling macros to track execution time and performance characteristics:
logwise::declare_logging_domain!();
// Logs duration when the interval is dropped
let _interval = logwise::profile_begin!("data_processing");
process_data();
// Automatically logs completion timeFor explicit profiling messages:
logwise::declare_logging_domain!();
logwise::profile_sync!("Computation took {ms} ms", ms=elapsed_ms);§Architecture Overview
§Core Components
Logger: The trait defining logging backendsLogRecord: Structured log entry with metadataLevel: Enumeration of available log levelscontextmodule: Thread-local hierarchical task managementprivacymodule: Privacy-aware data handling systemglobal_loggermodule: Global logger registration and managementintervalmodule: Performance interval tracking (interval::PerfwarnInterval,interval::PerfwarnIntervalIf,interval::ProfileInterval)HeartbeatGuard: Deadline monitoring for operations
§Logging Flow
- Macros generate a
LogRecordwith source location metadata - The
privacy::Loggabletrait determines how values are logged - Records are dispatched to registered
Loggerimplementations - Loggers can process records synchronously or asynchronously
§Examples
§Complete Application Example
logwise::declare_logging_domain!();
use logwise::{context::Context, privacy::LogIt};
#[derive(Debug)]
struct Config {
database_url: String,
port: u16,
}
// Initialize root context
Context::reset("application".to_string());
// Log application startup
logwise::info_sync!("Starting application", version="1.0.0");
// Load configuration
let config = Config {
database_url: "postgres://localhost/myapp".into(),
port: 8080,
};
// Use LogIt for complex types
logwise::info_sync!("Configuration loaded",
config=LogIt(&config)
);
// Track performance-critical operations
logwise::perfwarn!("database_connection", {
// connect_to_database(&config.database_url)
});
logwise::info_sync!("Application ready", port=config.port);§Custom Logger Implementation
use logwise::{Logger, LogRecord};
use std::sync::Arc;
use std::fmt::Debug;
use std::pin::Pin;
use std::future::Future;
#[derive(Debug)]
struct CustomLogger;
impl Logger for CustomLogger {
fn finish_log_record(&self, record: LogRecord) {
// Custom logging logic
eprintln!("[CUSTOM] {}", record);
}
fn finish_log_record_async<'s>(&'s self, record: LogRecord) -> Pin<Box<dyn Future<Output = ()> + Send + 's>> {
Box::pin(async move {
// Async logging logic
eprintln!("[CUSTOM ASYNC] {}", record);
})
}
fn prepare_to_die(&self) {
// Cleanup logic
}
}
// Register the logger
logwise::add_global_logger(Arc::new(CustomLogger));§Thread Safety and Async Support
logwise is designed for concurrent and async environments:
- All
Loggerimplementations must beSend + Sync - Context is thread-local with parent inheritance
context::ApplyContextpreserves context across async boundaries- Both sync and async logging variants are available
§Performance Considerations
- Use async variants (
*_async!) in async contexts for better performance - The
perfwarn!macro includes automatic interval tracking - Debug-only levels are compiled out in release builds
- Thread-local caching reduces synchronization overhead
§WASM Support
logwise includes WebAssembly support with browser-specific features:
- Uses
web-timefor time operations - Console output via
web-sys - Batched logging with
InMemoryLogger::periodic_drain_to_console
Re-exports§
pub use global_logger::add_global_logger;pub use global_logger::global_loggers;pub use global_logger::set_global_loggers;
Modules§
- context
- Thread-local context management for hierarchical, task-based logging.
- global_
logger - Global logger management for the logwise logging system.
- interval
- Defines our Interval types.
- privacy
- Privacy-aware logging system for logwise.
Macros§
- debuginternal_
async - Asynchronous debug-internal logging (debug builds only).
- debuginternal_
sync - Synchronous debug-internal logging (debug builds only).
- declare_
logging_ domain - Declares the logging domain for the current crate.
- error_
async - Asynchronous error-level logging (all builds).
- error_
sync - Synchronous error-level logging (all builds).
- info_
async - Asynchronous info-level logging (debug builds only).
- info_
sync - Synchronous info-level logging (debug builds only).
- log_
enabled - Returns whether logging is enabled for a given
Level. - mandatory_
async - Asynchronous mandatory-level logging (all builds).
- mandatory_
sync - Synchronous mandatory-level logging (all builds).
- perfwarn
- Block-scoped performance warning interval (all builds).
- perfwarn_
begin - Begin a performance warning interval (all builds).
- perfwarn_
begin_ if - Conditional performance warning interval.
- profile_
async - Asynchronous profile-level logging (all builds).
- profile_
begin - Begin a profile interval (all builds).
- profile_
sync - Synchronous profile-level logging (all builds).
- trace_
async - Asynchronous trace-level logging (debug builds only, per-thread activation).
- trace_
sync - Synchronous trace-level logging (debug builds only, per-thread activation).
- warn_
sync - Synchronous warning-level logging (all builds).
Structs§
- Duration
- A
Durationtype to represent a span of time, typically used for system timeouts. - Heartbeat
Guard - RAII guard that ensures work completes before a specified deadline.
- InMemory
Logger - An in-memory logger that stores log messages in a
Vec<String>. - LogRecord
- A log record.
- Logging
Domain - Controls whether internal logging is enabled for a crate.
Enums§
- Level
- Log severity levels with opinionated use-case semantics.
Traits§
- Logger
- Core trait for implementing logging backends in logwise.
Functions§
- heartbeat
- Creates a
HeartbeatGuardthat will warn if it is not dropped beforeduration.
Attribute Macros§
- profile
- Attribute macro to automatically profile a function’s execution time.