Performance
RichColorLog includes performance monitoring and optimization features.
Performance Tracker
Built-in performance tracking for logging operations:
from richcolorlog.logger import _performance
# After logging operations
stats = _performance.get_stats()
print(stats)
# Output:
# {
# 'format': {'count': 1000, 'avg': 0.0001, 'min': 0.00005, 'max': 0.001},
# }
Performance Decorator
Monitor custom functions:
from richcolorlog.logger import performance_monitor
@performance_monitor
def my_expensive_operation():
# ... do work
pass
# Stats recorded in _performance tracker
Optimization Tips
1. Disable Unused Features
logger = setup_logging(
show_icon=False, # Skip icon lookup
show_path=False, # Skip path resolution
show_time=False, # Skip time formatting
rich_tracebacks=False, # Skip rich traceback
markup=False, # Skip markup parsing
lexer=None, # Skip syntax highlighting
)
2. Use Appropriate Handler
from richcolorlog import setup_logging
from richcolorlog.logger import AnsiLogHandler
# ANSI handler is lighter than Rich handler
logger = setup_logging(HANDLER=AnsiLogHandler)
3. Check Level Before Expensive Operations
if logger.isEnabledFor(logging.DEBUG):
# Only compute if DEBUG is enabled
expensive_data = compute_debug_info()
logger.debug(f"Debug info: {expensive_data}")
4. Use Lazy Formatting
# Good - formatting happens only if logged
logger.debug("Data: %s", expensive_object)
# Less efficient - always formats
logger.debug(f"Data: {expensive_object}")
5. Batch Logging
# Collect messages, log once
messages = []
for item in items:
messages.append(f"Processed {item}")
logger.info("Batch result:\n" + "\n".join(messages))
6. Async Logging
For high-throughput applications:
import logging
from logging.handlers import QueueHandler, QueueListener
import queue
log_queue = queue.Queue(-1)
# Main thread uses queue handler
queue_handler = QueueHandler(log_queue)
logger.addHandler(queue_handler)
# Separate thread processes logs
file_handler = logging.FileHandler('app.log')
listener = QueueListener(log_queue, file_handler)
listener.start()
# Don't forget to stop
# listener.stop()
7. Memory Handler for Buffering
from logging.handlers import MemoryHandler
# Buffer 1000 records before flushing
memory_handler = MemoryHandler(
capacity=1000,
flushLevel=logging.ERROR,
target=file_handler
)
logger.addHandler(memory_handler)
Benchmarking
Compare handler performance:
import time
import logging
from richcolorlog import setup_logging
from richcolorlog.logger import AnsiLogHandler, RichColorLogHandler
def benchmark(name, logger, iterations=10000):
start = time.time()
for i in range(iterations):
logger.info(f"Test message {i}")
elapsed = time.time() - start
print(f"{name}: {elapsed:.3f}s ({iterations/elapsed:.0f} msg/s)")
# Benchmark Rich handler
logger1 = setup_logging(name='rich_bench')
benchmark("Rich Handler", logger1)
# Benchmark ANSI handler
logger2 = setup_logging(name='ansi_bench', HANDLER=AnsiLogHandler)
benchmark("ANSI Handler", logger2)
# Benchmark with features disabled
logger3 = setup_logging(
name='minimal_bench',
show_icon=False,
show_path=False,
HANDLER=AnsiLogHandler
)
benchmark("Minimal Handler", logger3)
Disabling Logging
Completely disable logging for maximum performance:
import os
# Via environment variable
os.environ['NO_LOGGING'] = '1'
# Or
os.environ['LOGGING'] = '0'
# Then import
from richcolorlog import setup_logging
logger = setup_logging() # Returns disabled logger
Or programmatically:
import logging
# Disable all logging
logging.disable(logging.CRITICAL)
# Re-enable
logging.disable(logging.NOTSET)
Production Recommendations
import os
is_production = os.getenv('ENV') == 'production'
logger = setup_logging(
name='myapp',
level='INFO' if is_production else 'DEBUG',
# Minimize console overhead in production
show_icon=not is_production,
show_background=not is_production,
show_path=not is_production,
# Use file logging in production
log_file=True,
log_file_name='/var/log/myapp/app.log',
log_file_level='DEBUG',
# Use async handlers for high throughput
# (implement custom async handler)
)
Memory Usage
Monitor memory usage:
import tracemalloc
tracemalloc.start()
# Logging operations
for i in range(10000):
logger.info(f"Message {i}")
current, peak = tracemalloc.get_traced_memory()
print(f"Current: {current / 1024:.1f} KB")
print(f"Peak: {peak / 1024:.1f} KB")
tracemalloc.stop()