Spaces:
Sleeping
Sleeping
| import sys | |
| import logging | |
| import colorlog | |
| import time | |
| from pathlib import Path | |
| from datetime import datetime | |
| from typing import Optional, Union, Dict, Any, Callable | |
| from logging.handlers import RotatingFileHandler | |
| from functools import wraps, lru_cache | |
| from contextlib import contextmanager | |
| from proglog import ProgressBarLogger | |
| def silence_logging(): | |
| logging.disable() | |
| try: | |
| yield | |
| finally: | |
| logging.disable(logging.NOTSET) | |
| # Log format | |
| LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" | |
| # Log colors mapping | |
| LOG_COLOR_MAP = { | |
| "DEBUG": "cyan", | |
| "INFO": "green", | |
| "WARNING": "yellow", | |
| "ERROR": "red", | |
| "CRITICAL": "bold_red", | |
| } | |
| # Log levels mapping | |
| LOG_LEVEL_MAP = { | |
| "debug": logging.DEBUG, | |
| "info": logging.INFO, | |
| "warning": logging.WARNING, | |
| "error": logging.ERROR, | |
| "critical": logging.CRITICAL | |
| } | |
| def get_logger( | |
| name: Optional[str] = None, | |
| ) -> logging.Logger: | |
| """Get a configured color logger | |
| Args: | |
| name: Logger name | |
| Returns: | |
| Logger instance | |
| """ | |
| # Get calling module name | |
| if name is None: | |
| frame = sys._getframe(1) | |
| name = frame.f_globals.get("__name__", "__main__") | |
| # Logger config | |
| level = "debug" | |
| do_console = True | |
| do_file = False | |
| log_dir = "logs" | |
| date_format = "%Y-%m-%d %H:%M:%S" | |
| # Create logger | |
| logger = logging.getLogger(name) | |
| # Set logging level | |
| level = LOG_LEVEL_MAP.get(level.lower(), logging.INFO) | |
| logger.setLevel(level) | |
| logger.propagate = False # Prevent propagation to root logger | |
| logger.handlers.clear() # Clear existing handlers | |
| # Add console handler | |
| if do_console: | |
| console_handler = colorlog.StreamHandler() | |
| console_handler.setLevel(level) | |
| colored_formatter = colorlog.ColoredFormatter( | |
| f"%(log_color)s{LOG_FORMAT}", | |
| datefmt=date_format, | |
| log_colors=LOG_COLOR_MAP | |
| ) | |
| console_handler.setFormatter(colored_formatter) | |
| logger.addHandler(console_handler) | |
| # Add file handler | |
| if do_file: | |
| # Create log directory | |
| log_path = Path(log_dir) | |
| log_path.mkdir(parents=True, exist_ok=True) | |
| # Create log filename | |
| module_name = name.split(".")[-1] | |
| timestamp = datetime.now().strftime("%Y-%m-%d") | |
| filename_template = "{timestamp}.log" | |
| log_file = log_path / filename_template.format( | |
| module=module_name, | |
| timestamp=timestamp | |
| ) | |
| # Setup file handler | |
| file_handler = RotatingFileHandler( | |
| log_file, | |
| maxBytes=10 * 1024 * 1024, | |
| backupCount=5, | |
| encoding="utf-8" | |
| ) | |
| file_handler.setLevel(level) | |
| file_formatter = logging.Formatter(LOG_FORMAT, datefmt=date_format) | |
| file_handler.setFormatter(file_formatter) | |
| logger.addHandler(file_handler) | |
| return logger | |
| def log_exception(func=None, logger=None, level=logging.ERROR): | |
| def decorator(fn): | |
| nonlocal logger | |
| if logger is None: | |
| logger = get_logger(name=fn.__module__) | |
| def wrapper(*args, **kwargs): | |
| try: | |
| return fn(*args, **kwargs) | |
| except Exception as e: | |
| logger.log(level, f"Exception in {fn.__name__}: {str(e)}", exc_info=True) | |
| raise # Re-raise exception | |
| return wrapper | |
| # Support direct @log_exception usage | |
| if func is not None: | |
| return decorator(func) | |
| return decorator | |
| def log_time(func=None, logger=None, level=logging.DEBUG): | |
| def decorator(fn): | |
| nonlocal logger | |
| if logger is None: | |
| logger = get_logger(name=fn.__module__) | |
| def wrapper(*args, **kwargs): | |
| start_time = time.perf_counter() | |
| result = fn(*args, **kwargs) | |
| elapsed_time = time.perf_counter() - start_time | |
| logger.log(level, f"Function {fn.__name__} ellapsed: {elapsed_time:.3f}s") | |
| return result | |
| return wrapper | |
| if func is not None: | |
| return decorator(func) | |
| return decorator | |
| from proglog import TqdmProgressBarLogger | |
| class MCPMoviePyLogger(TqdmProgressBarLogger): | |
| def __init__(self, report: Callable[[float, Optional[float], Optional[str]], None]): | |
| super().__init__(logged_bars="all", leave_bars=False, print_messages=True) | |
| self._report = report | |
| self._last_ts = 0.0 | |
| self._last_p = -1.0 | |
| self._seen = set() | |
| def bars_callback(self, bar, attr, value, old_value=None): | |
| super().bars_callback(bar, attr, value, old_value) | |
| if bar not in ("frame_index", "t", "chunk"): | |
| return | |
| if attr != "index": | |
| return | |
| st = self.bars.get(bar) or {} | |
| idx, tot = st.get("index"), st.get("total") | |
| if idx is None or not tot: | |
| return | |
| p = float(idx) / float(tot) | |
| p = max(0.0, min(1.0, p)) | |
| now = time.monotonic() | |
| if p < 1.0 and (now - self._last_ts) < 0.2 and (p - self._last_p) < 0.002: | |
| return | |
| self._last_ts, self._last_p = now, p | |
| self._report(float(idx), float(tot), f"rendering {p*100:.1f}%") | |
| if __name__ == "__main__": | |
| # Create logger with configuration | |
| logger = get_logger() | |
| logger.debug("Debug message") | |
| logger.info("Info message") | |
| # Test logging decorators | |
| def sample_function(x, y): | |
| import time | |
| time.sleep(0.1) | |
| return x + y | |
| # Test function logging | |
| result = sample_function(10, 20) | |
| logger.info(f"Function result: {result}") | |
| # Test exception logging | |
| def dumb_func(): | |
| return 1 / 0 | |
| try: | |
| dumb_func() | |
| except ZeroDivisionError: | |
| logger.info("Exception was logged") | |