Files

6.9 KiB

Logging Guidelines

  • Status: Canonical
  • Last reviewed: 2026-07-05
  • Update when: Logging utilities, exception-handling policy, or silent-handler criteria change.

This document describes the logging conventions and best practices for ComfyUI-LLM-Session.

This is the canonical policy for current logging, exception-handling, and silent-handler decisions. Historical audit records such as error-handling-audit.md and acceptable-silent-errors.md preserve past review context, but should not override the rules in this document.

Log Levels

The project uses three log levels:

Level Description When to Use
minimal Only critical errors Production environments, minimal console output
timing Timing information + critical errors (default) Normal development and usage
debug Full debug output including tracebacks Debugging issues, development

Logging Utilities

Core Module: core.logging_utils

The core.logging_utils module provides common logging helpers:

from core.logging_utils import (
    get_module_logger,
    log_error_safely,
    log_with_exception_info,
    create_fallback_logger,
    handle_exception_safely,
    LOG_LEVEL_MINIMAL,
    LOG_LEVEL_TIMING,
    LOG_LEVEL_DEBUG,
)

Getting a Module Logger

# Create a logger for your module
log = get_module_logger("MyModuleName")

# Use the logger
log("Operation completed", LOG_LEVEL_TIMING)
log("Debug detail", LOG_LEVEL_DEBUG)

Logging Errors in Except Blocks

Recommended pattern:

from core.logging_utils import log_error_safely, LOG_LEVEL_MINIMAL

try:
    # some operation
    result = do_something()
except Exception as e:
    log_error_safely("MyModule", e, "Failed to do something", LOG_LEVEL_MINIMAL)
    return None  # or appropriate fallback

Alternative pattern with fallback logger:

from core.logging_utils import create_fallback_logger, LOG_LEVEL_MINIMAL

# Create fallback logger at module level
_log_error = create_fallback_logger("MyModule", LOG_LEVEL_MINIMAL)

def my_function():
    try:
        # some operation
        result = do_something()
    except Exception as e:
        _log_error(e, "Failed to do something")
        return None

Logging with Full Exception Info

For debug-level logging with traceback information:

from core.logging_utils import log_with_exception_info, LOG_LEVEL_DEBUG

try:
    # some operation
    result = do_something()
except Exception:
    log_with_exception_info("MyModule", "Failed to do something", level=LOG_LEVEL_DEBUG)
    return None

Error Handling Patterns

Pattern 1: Fallback with Logging

Use when the operation has a safe fallback:

from core.logging_utils import log_error_safely, LOG_LEVEL_TIMING

def load_optional_config(path: str) -> dict:
    try:
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        log_error_safely("ConfigLoader", e, "Failed to load optional config", LOG_LEVEL_TIMING)
        return {}  # safe fallback

Pattern 2: Critical Error with Propagation

Use when the operation must succeed:

from core.logging_utils import log_error_safely, LOG_LEVEL_MINIMAL

def load_required_history(path: str) -> dict:
    try:
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        log_error_safely("HistoryLoader", e, "Failed to load required history", LOG_LEVEL_MINIMAL)
        raise  # re-raise for caller to handle

Pattern 3: Silent Error (Acceptable)

Use only for truly optional operations where logging would add noise:

def cleanup_temp_file(path: str) -> None:
    try:
        os.remove(path)
    except Exception:
        pass  # Acceptable: temp file cleanup is best-effort

When Silence Is Acceptable

Silent errors (Pattern 3) should only be used when all of the following are true:

  1. Fallback behavior exists.
  2. Failure does not risk data corruption or data loss.
  3. Core functionality continues to work.
  4. Logging would add noise because the error is expected in normal operation.
  5. The issue can still be diagnosed through another path when needed.

Silent handlers should be reviewed when:

  1. Users report issues that may be related to these code paths.
  2. Debugging becomes difficult due to lack of visibility.
  3. Fallback behavior changes.
  4. The error becomes more frequent due to external changes.

When a silent handler remains intentional, keep the rationale documented in the nearest relevant policy, audit, or code comment.

Best Practices

DO:

  1. Use module-specific loggers for clear log attribution
  2. Include context in error messages (what operation was being attempted)
  3. Use appropriate log levels (minimal for errors, timing for info, debug for verbose)
  4. Log before falling back so users know when fallbacks are triggered
  5. Keep log messages concise but informative

DON'T:

  1. Don't use bare except: - always use except Exception:
  2. Don't log in loops without rate limiting
  3. Don't log sensitive information (API keys, personal data)
  4. Don't use print() directly - use logging utilities
  5. Don't silently swallow errors without documentation

Migration Guide

Replacing Existing Patterns

Old pattern:

def _simple_config_log(message: str, log_level: str) -> None:
    try:
        if str(log_level).strip().lower() != "minimal":
            print(f"[LLM Session Simple] {message}")
    except Exception:
        pass

New pattern:

from core.logging_utils import get_module_logger, LOG_LEVEL_TIMING

log = get_module_logger("LLM Session Simple")

# Usage
log("Config loaded", LOG_LEVEL_TIMING)

Old pattern:

try:
    # operation
except Exception:
    pass  # Silent failure

New pattern:

from core.logging_utils import log_error_safely, LOG_LEVEL_MINIMAL

try:
    # operation
except Exception as e:
    log_error_safely("MyModule", e, "operation description", LOG_LEVEL_MINIMAL)
    # fallback or re-raise

Configuration

Setting Log Levels

from core.logging_utils import set_global_log_level, set_module_log_level

# Set global log level
set_global_log_level("debug")

# Set module-specific log level
set_module_log_level("MyModule", "minimal")

Log Level Hierarchy

Log levels follow this hierarchy (most verbose to least verbose):

  1. debug - Shows all messages
  2. timing - Shows timing + minimal messages
  3. minimal - Shows only critical errors

File Locations

  • core/logging_utils.py - Logging utility implementations
  • docs/logging-guidelines.md - This document
  • docs/error-handling-audit.md - Historical 2026-03-22 audit of error handling locations
  • docs/acceptable-silent-errors.md - Historical 2026-03-22 silent-error allowlist