tracing-throttle
High-performance log deduplication and rate limiting for the Rust tracing ecosystem.
Overview
tracing-throttle suppresses repetitive or bursty log events in high-volume systems. It helps you:
- Reduce I/O bandwidth from repetitive logs
- Improve log visibility by filtering noise
- Lower storage costs for log aggregation
- Prevent log backend overload during traffic spikes
The crate provides a tracing::Layer that deduplicates events based on their signature (level, message, and structured fields) and applies configurable rate limiting policies.
Features
- ๐ High Performance: Sharded maps and lock-free operations
- ๐ฏ Flexible Policies: Count-based, time-window, exponential backoff, and custom policies
- ๐ Per-signature Throttling: Events with identical signatures are throttled together
- ๐พ Memory Control: Optional LRU eviction to prevent unbounded memory growth
- ๐ Observability Metrics: Built-in tracking of allowed, suppressed, and evicted events
- ๐ก๏ธ Fail-Safe Circuit Breaker: Fails open to preserve observability during errors
- โฑ๏ธ Suppression Summaries: Periodic emission of suppression statistics (coming in v0.2)
- ๐ง Easy Integration: Drop-in
tracing::Layercompatible with existing subscribers
Installation
Add this to your Cargo.toml:
[]
= "0.1"
= "0.1"
= "0.3"
Quick Start
use ;
use *;
use Duration;
// Create a rate limit filter with safe defaults
// Defaults: 100 events per signature, 10k max signatures with LRU eviction
let rate_limit = builder
.with_policy
.build
.expect;
// Or customize the limits:
let rate_limit = builder
.with_policy
.with_max_signatures // Custom signature limit
.with_summary_interval
.build
.expect;
// Add it as a filter to your fmt layer
registry
.with
.init;
// Now your logs are rate limited!
for i in 0..1000
// Only the first 100 will be emitted
Observability & Metrics
Monitor rate limiting behavior with built-in metrics:
use ;
let rate_limit = builder
.with_policy
.build
.expect;
// ... after some log events have been processed ...
// Get current metrics
let metrics = rate_limit.metrics;
println!;
println!;
println!;
// Or get a snapshot for calculations
let snapshot = metrics.snapshot;
println!;
println!;
// Check how many unique signatures are being tracked
println!;
Available Metrics:
events_allowed()- Total events allowed throughevents_suppressed()- Total events suppressedsignatures_evicted()- Signatures removed due to LRU evictionsignature_count()- Current number of tracked signaturessuppression_rate()- Ratio of suppressed to total events (0.0 - 1.0)
Use Cases:
- Monitor suppression rates in production dashboards
- Alert when suppression rate exceeds threshold
- Track signature cardinality growth
- Observe LRU eviction frequency
- Validate rate limiting effectiveness
Fail-Safe Operation
tracing-throttle uses a circuit breaker pattern to prevent cascading failures. If rate limiting operations fail (e.g., panics or internal errors), the library fails open to preserve observability:
use ;
let rate_limit = new;
// Check circuit breaker health
let cb = rate_limit.circuit_breaker;
match cb.state
println!;
Circuit Breaker Behavior:
- Closed: Normal operation, rate limiting active
- Open: After threshold failures (default: 5), fails open and allows all events
- HalfOpen: After recovery timeout (default: 30s), tests if system has recovered
- Fail-Open Strategy: Preserves observability over strict rate limiting
This ensures your logs remain visible during system instability, preventing silent data loss.
Rate Limiting Policies
Count-Based Policy
Allow N events, then suppress all subsequent occurrences:
use Policy;
let policy = count_based.expect;
// Allows first 50 events, suppresses the rest
Time-Window Policy
Allow K events within a sliding time window:
use Duration;
use Policy;
let policy = time_window
.expect;
// Allows 10 events per minute
Exponential Backoff Policy
Emit events at exponentially increasing intervals (1st, 2nd, 4th, 8th, 16th, ...):
use Policy;
let policy = exponential_backoff;
// Useful for extremely noisy logs
Custom Policies
Implement the RateLimitPolicy trait for custom behavior:
use RateLimitPolicy;
use Instant;
;
How It Works
When a log event is emitted:
- A signature is computed from the event's level, message, and fields
- The rate limiting policy is checked for that signature
- The event is either allowed through or suppressed
- Suppression counts are tracked per signature
Different log messages are throttled independently, so important logs aren't suppressed just because other logs are noisy.
Memory Management
By default, the layer tracks up to 10,000 unique event signatures with LRU eviction. Each signature uses approximately 150-250 bytes.
Typical memory usage:
- 10,000 signatures (default): ~1.5-2.5 MB
- 50,000 signatures: ~7.5-12.5 MB
- 100,000 signatures: ~15-25 MB
// Increase limit for high-cardinality applications
let rate_limit = builder
.with_max_signatures
.build
.expect;
// Monitor usage in production
let sig_count = rate_limit.signature_count;
let evictions = rate_limit.metrics.signatures_evicted;
โ ๏ธ High-cardinality warning: Avoid logging fields with unbounded cardinality (UUIDs, timestamps, request IDs) as they will cause rapid memory growth and eviction.
๐ See detailed memory documentation for:
- Memory breakdown and overhead calculations
- Signature cardinality analysis and estimation
- Configuration guidelines for different use cases
- Production monitoring and profiling techniques
Performance
Measured on Apple Silicon with comprehensive benchmarks:
Throughput:
- 20 million rate limiting decisions/sec (single-threaded)
- 44 million ops/sec with 8 threads
- Scales well with concurrent access
Latency:
- Signature computation: 13-37ns (simple), 200ns (20 fields)
- Rate limit decision: ~50ns per operation
Design:
- ahash for fast non-cryptographic hashing
- DashMap for lock-free concurrent access
- Atomic operations for lock-free counters
- Zero allocations in the hot path
See BENCHMARKS.md for detailed measurements and methodology.
Run benchmarks yourself:
Examples
Run the included examples:
# Basic count-based rate limiting
# Demonstrate different policies
Roadmap
v0.1.0 (Current - MVP Release)
โ Completed:
- Domain policies (count-based, time-window, exponential backoff)
- Basic registry and rate limiter
tracing::Layerimplementation- LRU eviction with configurable memory limits
- Comprehensive test suite (105 tests: 94 unit + 11 doc)
- Performance benchmarks (20M ops/sec)
- Hexagonal architecture (clean ports & adapters)
- Observability metrics (events allowed/suppressed, eviction tracking)
v0.1.1 (Production Hardening) - NEXT
Critical Fixes:
- โ Add maximum signature limit with LRU eviction
- โ Fix OnceLock timestamp bug (shared base instant)
- โ Fix atomic memory ordering (Release/Acquire)
- โ Add saturation arithmetic for overflow protection
- โ Add input validation (non-zero limits, durations, and reasonable max_events)
- โ Add observability metrics (signature count, suppression rates)
Major Improvements:
- ๐ก๏ธ Add circuit breaker for fail-safe operation
- ๐ Document memory implications and limitations
- โ๏ธ Add graceful shutdown for async emitter
- ๐งช Add integration tests for edge cases
v0.2.0 (Enhanced Observability)
- Active suppression summary emission
- Metrics adapters (Prometheus/OTel)
- Configurable summary formatting
- Memory usage telemetry
v0.3.0 (Advanced Features)
- Pluggable storage backends (Redis, etc.)
- Streaming-friendly summaries
- Rate limit by span context
- Advanced eviction policies
v1.0.0 (Stable Release)
- Stable API guarantee
- Production-ready documentation
- Optional WASM support
- Performance regression testing
Contributing
Contributions are welcome! Please open issues or pull requests on GitHub.
License
Licensed under the MIT License.