Skip to content

Logging Best Practices

Logging Levels

Use appropriate levels:

  • DEBUG - Detailed diagnostic info (verbose, disabled in production)
  • INFO - Key workflow steps, results, metrics
  • WARNING - Unexpected conditions that were handled
  • ERROR - Errors preventing operation completion
  • CRITICAL - System failures

Logging Format

Always use %-formatting for performance:

# Good (lazy evaluation)
logger.info("Processed %d items in %.2fs", count, duration)

# Bad (eager evaluation even if not logged)
logger.info(f"Processed {count} items in {duration:.2f}s")

What to Log

Always Log

  • File I/O operations (loading, saving)
  • Major workflow steps (start/end of operations)
  • Final results and metrics
  • Warnings and errors

Use DEBUG Level

  • Loop iterations
  • Intermediate calculations
  • Data shape/size details
  • Detailed diagnostics

Don't Log

  • Passwords, API keys, sensitive data
  • Redundant information
  • Every iteration of tight loops

Performance Logging

Use timing context managers:

from portfolio_management.core.logging_utils import log_execution_time

with log_execution_time("portfolio construction"):
    portfolio = construct_portfolio(...)
# Logs: "Portfolio construction completed in 2.34s"

Progress Logging

For long operations, log progress:

from portfolio_management.core.logging_utils import ProgressLogger

progress = ProgressLogger(total=len(assets), operation="backtesting")
for asset in assets:
    process(asset)
    progress.update()
# Logs every 100 items: "Backtesting: 500/1000 (50.0%) - 43.2 items/sec"

Structured Logging

Use consistent formats for event types:

# Data events
logger.info("Loading data: source=%s, rows=%d, columns=%d", source, rows, cols)

# Construction events
logger.info("Portfolio: strategy=%s, assets=%d, sharpe=%.2f", strategy, n, sharpe)