Logging System

Overview

Elevator Saga uses a unified logging system with colored output and multiple log levels. The logging system provides consistent, filterable output across all components.

Log Levels

The logger supports four log levels with distinct colors:

  • DEBUG - Gray/Bright Black - Detailed debugging information

  • INFO - Cyan - General informational messages

  • WARNING - Yellow - Warning messages

  • ERROR - Red - Error messages

Configuration

Environment Variable

The default log level is controlled by the ELEVATOR_LOG_LEVEL environment variable:

# Set log level to DEBUG (default)
export ELEVATOR_LOG_LEVEL=DEBUG

# Set log level to INFO (less verbose)
export ELEVATOR_LOG_LEVEL=INFO

# Set log level to WARNING (only warnings and errors)
export ELEVATOR_LOG_LEVEL=WARNING

# Set log level to ERROR (only errors)
export ELEVATOR_LOG_LEVEL=ERROR

If not set, the default is DEBUG mode.

Programmatic Control

You can also control the log level programmatically:

from elevator_saga.utils.logger import LogLevel, set_log_level

# Set to INFO level
set_log_level(LogLevel.INFO)

# Set to DEBUG level
set_log_level(LogLevel.DEBUG)

Basic Usage

Simple Logging

from elevator_saga.utils.logger import debug, info, warning, error

# Simple messages
info("Server started successfully")
warning("Connection timeout")
error("Failed to load configuration")
debug("Processing tick 42")

With Prefix

Add a prefix to identify the source of the log message:

# Server logs
info("Client registered", prefix="SERVER")
debug("Algorithm client processed tick 42", prefix="SERVER")

# Client logs
info("API Client initialized", prefix="CLIENT")
warning("Command ignored", prefix="CLIENT")

# Controller logs
info("启动 MyController 算法", prefix="CONTROLLER")
error("模拟运行错误", prefix="CONTROLLER")

Advanced Usage

Custom Logger

Create a custom logger instance with specific settings:

from elevator_saga.utils.logger import get_logger, LogLevel

# Get a custom logger
logger = get_logger("MyComponent", min_level=LogLevel.WARNING)
logger.info("This will not appear (level too low)")
logger.warning("This will appear")
logger.error("This will appear")

Color Output

The logger automatically detects if output is to a TTY (terminal) and enables colors. When redirecting to files or pipes, colors are automatically disabled for clean output.

Log Format

All log messages follow a consistent format:

LEVEL     [PREFIX] message

Examples:

DEBUG    [SERVER] Algorithm client registered: abc-123
INFO     [SERVER] Loading traffic from test_case_01.json
WARNING  [SERVER] GUI client: timeout waiting for tick 42
ERROR    [CLIENT] Reset failed: Connection refused
INFO     [CONTROLLER] 启动 MyController 算法

Component Prefixes

Standard prefixes used throughout the system:

  • SERVER - Simulator server logs

  • CLIENT - API client logs

  • CONTROLLER - Controller/algorithm logs

You can use any prefix that makes sense for your component.

API Reference

Functions

debug(message: str, prefix: str | None = None) None

Log a DEBUG level message.

Parameters:
  • message – The message to log

  • prefix – Optional prefix to identify the source

info(message: str, prefix: str | None = None) None

Log an INFO level message.

Parameters:
  • message – The message to log

  • prefix – Optional prefix to identify the source

warning(message: str, prefix: str | None = None) None

Log a WARNING level message.

Parameters:
  • message – The message to log

  • prefix – Optional prefix to identify the source

error(message: str, prefix: str | None = None) None

Log an ERROR level message.

Parameters:
  • message – The message to log

  • prefix – Optional prefix to identify the source

set_log_level(level: LogLevel) None

Set the global log level.

Parameters:

level – The minimum log level to display

get_logger(name: str = 'ElevatorSaga', min_level: LogLevel | None = None) Logger

Get or create the global logger instance.

Parameters:
  • name – Name of the logger

  • min_level – Minimum log level (defaults to ELEVATOR_LOG_LEVEL or DEBUG)

Returns:

Logger instance

Classes

class LogLevel

Enumeration of available log levels.

DEBUG = 0

Debug level - most verbose

INFO = 1

Info level - general information

WARNING = 2

Warning level - warnings only

ERROR = 3

Error level - errors only

classmethod from_string(level_str: str) LogLevel

Convert a string to a LogLevel.

Parameters:

level_str – String representation (case-insensitive)

Returns:

Corresponding LogLevel (defaults to DEBUG if invalid)

class Logger

The main logger class.

__init__(name: str = 'ElevatorSaga', min_level: LogLevel = LogLevel.INFO, use_color: bool = True)

Initialize a logger instance.

Parameters:
  • name – Logger name

  • min_level – Minimum level to log

  • use_color – Whether to use colored output

debug(message: str, prefix: str | None = None) None

Log a DEBUG message.

info(message: str, prefix: str | None = None) None

Log an INFO message.

warning(message: str, prefix: str | None = None) None

Log a WARNING message.

error(message: str, prefix: str | None = None) None

Log an ERROR message.

set_level(level: LogLevel) None

Change the minimum log level.

Best Practices

  1. Use appropriate levels:

    • DEBUG for detailed state changes and internal operations

    • INFO for significant events (startup, completion, etc.)

    • WARNING for unexpected but recoverable situations

    • ERROR for failures and exceptions

  2. Use prefixes consistently:

    • Always use the same prefix for the same component

    • Use uppercase for standard prefixes (SERVER, CLIENT, CONTROLLER)

  3. Keep messages concise:

    • One log message per event

    • Include relevant context (IDs, values, etc.)

    • Avoid multi-line messages

  4. Set appropriate default level:

    • Use DEBUG for development

    • Use INFO for production

    • Use WARNING for minimal logging

  5. Avoid logging in tight loops:

    • Excessive logging can impact performance

    • Consider conditional logging or sampling

Examples

Server Startup

from elevator_saga.utils.logger import info, debug

info("Elevator simulation server (Async) running on http://127.0.0.1:8000", prefix="SERVER")
info("Using Quart (async Flask) for better concurrency", prefix="SERVER")
debug("Found 5 traffic files: ['test01.json', 'test02.json', ...]", prefix="SERVER")

Client Operations

from elevator_saga.utils.logger import info, warning, error

info("Client registered successfully with ID: xyz-789", prefix="CLIENT")
warning("Client type 'gui' cannot send control commands", prefix="CLIENT")
error("Reset failed: Connection refused", prefix="CLIENT")

Controller Logic

from elevator_saga.utils.logger import info, debug

info("启动 MyController 算法", prefix="CONTROLLER")
debug("Updated traffic info - max_tick: 1000", prefix="CONTROLLER")
info("停止 MyController 算法", prefix="CONTROLLER")