Compatibility Overview¶
LogXide is a high-performance logging library with a familiar API inspired by Python's standard logging module. It delivers significant performance improvements through its Rust native core, prioritizing speed over perfect compatibility.
For common use cases, LogXide provides a highly compatible experience. Standard patterns like getLogger(), basicConfig(), dictConfig, and built-in handlers work with minimal or no code changes. However, LogXide is not a drop-in replacement for every stdlib logging scenario. Its Zero-GIL architecture means some advanced patterns, particularly those involving custom Python subclasses or deep monkeypatching, are not supported.
This document provides a high-level compatibility overview. For detailed comparisons against specific logging libraries, see the deep-dive guides below.
Quick Compatibility Summary¶
| Feature | Status | Notes |
|---|---|---|
Basic logging API (getLogger, info, debug, etc.) |
✅ | Familiar stdlib-like API |
basicConfig() |
✅ | Direct mapping to LogXide handlers |
dictConfig() |
✅ | Use logxide.config.dictConfig for Django/FastAPI |
Standard formatters (%-style, {}-style) |
✅ | Processed natively in Rust |
| FileHandler, StreamHandler, RotatingFileHandler | ✅ | Rust-native implementations |
Custom Python formatters (subclassed Formatter) |
❌ | Format strings work; custom format() methods don't |
| Custom Python handlers | ⚠️ | Accepted but bypass Rust performance pipeline |
Subclassing LogRecord or Logger |
❌ | Rust types, not subclassable |
pytest caplog |
⚠️ | Use caplog_logxide fixture instead |
| StringIO capture | ❌ | Use file-based logging for tests |
The Zero-GIL Architecture¶
LogXide's performance comes from its fundamental architectural differences:
Standard library logging: Creates a Python LogRecord object for every log call, then recursively bubbles it through all loggers while holding the GIL with threading.RLock().
LogXide: Drops the GIL immediately and packs raw attributes into a natively dispatched Rust Arc<LogRecord>. Formatting, filtering, bubbling, and I/O all happen outside Python's GIL in Rust.
Because of this, any custom logic that overrides standard Python implementations, such as subclassed Formatters with custom format() methods, will not execute natively.
Supported Patterns ✅¶
- Basic Configuration:
logging.basicConfig()maps directly to LogXide - Structural Configuration:
logxide.config.dictConfigtranslates Python dictionary configurations (Django, FastAPI) to native Rust objects - Logger Hierarchy: Dot-delimited logger names (e.g.,
app.db.sql) bubble matching Python's resolution logic - Standard Formatting:
%-style and{}-style placeholders, including{asctime}, map to Rust's Chrono formats - Standard Handlers: StreamHandler, FileHandler, RotatingFileHandler behavior replicated in Rust
- Exception Logging:
exc_info=Truecorrectly fetches and logs stack traces - Third-party Interception:
logxide.intercept_stdlib()captures logs from libraries using standard logging
Unsupported Patterns ❌¶
1. Custom Python Formatters¶
LogXide maps the format pattern string directly into Rust. If you subclass logging.Formatter to mutate records in a custom format(self, record) method, this method will not be called because no pure-Python LogRecord is materialized.
Alternative: Use JSON templates via logxide.HTTPHandler or transform output at the application edge.
2. Synchronous Python Custom Handlers¶
If you create a new logging sink (e.g., class MailLog(logging.Handler)), LogXide cannot translate this into zero-cost Rust runtime behavior. Python handlers assigned to LogXide loggers still work but lose the Rust backend concurrency advantage.
3. Standard Library Unit Tests¶
LogXide fails CPython's test_logging.py unit tests. These tests validate locking behavior, internal .handlers array mutability, and .disabled states using memory assertions that conflict with Rust's encapsulated states and RwLocks.
Detailed Comparison Guides¶
For side-by-side comparisons with specific logging libraries, including benchmark data and migration guidance:
| Comparison | Description |
|---|---|
| LogXide vs stdlib | Handler-by-handler performance vs Python's logging module, feature matrix, and migration path for standard use cases |
| LogXide vs Loguru | Architecture differences, performance benchmarks, feature trade-offs, and when to choose each |
| LogXide vs Structlog | Structured logging capabilities, processor pipelines, context binding, and performance comparison |
| LogXide vs Picologging | Rust vs Cython implementation, Python 3.13+ compatibility, and feature ecosystem comparison |
Migration Checklist¶
When migrating an application to LogXide:
- Initialize early: Import and initialize LogXide before framework initialization (Django/Flask/FastAPI)
- Intercept stdlib: Call
logxide.intercept_stdlib()to capture logs from third-party dependencies - Use structural config: Prefer
logxide.config.dictConfigover custom instantiation - Check custom handlers: Verify any custom Python handlers are acceptable (they will work but bypass Rust performance)
- Update tests: Replace
caplogwithcaplog_logxideand use file-based logging instead of StringIO
For detailed third-party library compatibility information, see the Third-Party Compatibility Guide.