#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Timestamp: "2025-11-11 (ywatanabe)" """ Custom logging setup for scitex-writer scripts Provides color-coded logging with custom levels matching scitex.logging conventions. This module is standalone and only depends on stdlib. Dependencies: - packages: - logging (stdlib) IO: - input-files: None - output-files: None (logs to stderr) """ import logging # Add custom log levels (matching scitex conventions) SUCCESS = 31 # Between WARNING (30) and ERROR (40) FAIL = 35 # Between WARNING (30) and ERROR (40) # Add custom levels with 4-character abbreviations logging.addLevelName(SUCCESS, "SUCC") logging.addLevelName(FAIL, "FAIL") logging.addLevelName(logging.DEBUG, "DEBU") logging.addLevelName(logging.INFO, "INFO") logging.addLevelName(logging.WARNING, "WARN") logging.addLevelName(logging.ERROR, "ERRO") logging.addLevelName(logging.CRITICAL, "CRIT") def success(self, message, *args, **kwargs): """Log success message.""" if self.isEnabledFor(SUCCESS): self._log(SUCCESS, message, args, **kwargs) def fail(self, message, *args, **kwargs): """Log failure message.""" if self.isEnabledFor(FAIL): self._log(FAIL, message, args, **kwargs) # Add methods to Logger class logging.Logger.success = success logging.Logger.fail = fail class ColoredFormatter(logging.Formatter): """Custom formatter with color support - colors entire message.""" COLORS = { "DEBU": "\033[90m", # Grey "INFO": "\033[90m", # Grey "SUCC": "\033[32m", # Green "WARN": "\033[33m", # Yellow "FAIL": "\033[91m", # Light Red "ERRO": "\033[31m", # Red "CRIT": "\033[35m", # Magenta } RESET = "\033[0m" def format(self, record): # Format the message first formatted = super().format(record) # Apply color to entire message based on level levelname = record.levelname if levelname in self.COLORS: color = self.COLORS[levelname] return f"{color}{formatted}{self.RESET}" return formatted def setup_logger(name: str, verbose: bool = False) -> logging.Logger: """Set up logger with custom formatting and levels. Args: name: Logger name verbose: Enable verbose logging Returns: Configured logger instance """ logger = logging.getLogger(name) logger.setLevel(logging.DEBUG if verbose else logging.INFO) # Remove existing handlers logger.handlers = [] # Create console handler with formatting handler = logging.StreamHandler() handler.setLevel(logging.DEBUG if verbose else logging.INFO) # Use colored formatter formatter = ColoredFormatter("%(levelname)s: %(message)s") handler.setFormatter(formatter) logger.addHandler(handler) return logger def getLogger(name: str, verbose: bool = False) -> logging.Logger: """Get a logger with custom scitex formatting. This is a convenience wrapper around setup_logger that provides a similar interface to logging.getLogger() from stdlib. Args: name: Logger name (typically __name__) verbose: Enable verbose logging (default: False) Returns: Configured logger instance with custom levels and colors """ return setup_logger(name, verbose) # EOF