Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

logger_helper.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env python3
  2. import sys
  3. import time
  4. from enum import Enum
  5. class LogLevel(Enum):
  6. """Log levels with associated colors and symbols."""
  7. DEBUG = ("🔍", "\033[90m") # Gray
  8. INFO = ("ℹ️ ", "\033[94m") # Blue
  9. SUCCESS = ("✅", "\033[92m") # Green
  10. WARNING = ("⚠️ ", "\033[93m") # Yellow
  11. ERROR = ("❌", "\033[91m") # Red
  12. STEP = ("🚀", "\033[96m") # Cyan
  13. PROGRESS = ("📋", "\033[95m") # Magenta
  14. class Logger:
  15. """Logger class for formatted console output."""
  16. def __init__(self, name: str | None = None, use_colors: bool = True):
  17. """Initialize logger.
  18. Args:
  19. name: Optional name for the logger (e.g., script name)
  20. use_colors: Whether to use ANSI color codes
  21. """
  22. self.name = name
  23. self.use_colors = use_colors and sys.stdout.isatty()
  24. self._reset_color = "\033[0m" if self.use_colors else ""
  25. def _format_message(self, level: LogLevel, message: str, indent: int = 0) -> str:
  26. """Format a log message with level, color, and indentation.
  27. Args:
  28. level: Log level
  29. message: Message to log
  30. indent: Number of spaces to indent
  31. Returns:
  32. Formatted message string
  33. """
  34. symbol, color = level.value
  35. color = color if self.use_colors else ""
  36. reset = self._reset_color
  37. prefix = " " * indent
  38. if self.name and level in [LogLevel.STEP, LogLevel.ERROR]:
  39. return f"{prefix}{color}{symbol} [{self.name}] {message}{reset}"
  40. else:
  41. return f"{prefix}{color}{symbol} {message}{reset}"
  42. def debug(self, message: str, indent: int = 0) -> None:
  43. """Log debug message."""
  44. print(self._format_message(LogLevel.DEBUG, message, indent))
  45. def info(self, message: str, indent: int = 0) -> None:
  46. """Log info message."""
  47. print(self._format_message(LogLevel.INFO, message, indent))
  48. def success(self, message: str, indent: int = 0) -> None:
  49. """Log success message."""
  50. print(self._format_message(LogLevel.SUCCESS, message, indent))
  51. def warning(self, message: str, indent: int = 0) -> None:
  52. """Log warning message."""
  53. print(self._format_message(LogLevel.WARNING, message, indent))
  54. def error(self, message: str, indent: int = 0) -> None:
  55. """Log error message."""
  56. print(self._format_message(LogLevel.ERROR, message, indent), file=sys.stderr)
  57. def step(self, message: str, indent: int = 0) -> None:
  58. """Log a step in a process."""
  59. print(self._format_message(LogLevel.STEP, message, indent))
  60. def progress(self, message: str, indent: int = 0) -> None:
  61. """Log progress information."""
  62. print(self._format_message(LogLevel.PROGRESS, message, indent))
  63. def separator(self, char: str = "-", length: int = 60) -> None:
  64. """Print a separator line."""
  65. print(char * length)
  66. def header(self, title: str, width: int = 60) -> None:
  67. """Print a formatted header."""
  68. if self.use_colors:
  69. print(f"\n\033[1m{'=' * width}\033[0m") # Bold
  70. print(f"\033[1m{title.center(width)}\033[0m")
  71. print(f"\033[1m{'=' * width}\033[0m\n")
  72. else:
  73. print(f"\n{'=' * width}")
  74. print(title.center(width))
  75. print(f"{'=' * width}\n")
  76. def box(self, title: str, width: int = 60) -> None:
  77. """Print a title in a box."""
  78. border = "═" * (width - 2)
  79. if self.use_colors:
  80. print(f"\033[1m╔{border}╗\033[0m")
  81. print(f"\033[1m║{title.center(width - 2)}║\033[0m")
  82. print(f"\033[1m╚{border}╝\033[0m")
  83. else:
  84. print(f"╔{border}╗")
  85. print(f"║{title.center(width - 2)}║")
  86. print(f"╚{border}╝")
  87. def list_item(self, item: str, indent: int = 2) -> None:
  88. """Print a list item."""
  89. prefix = " " * indent
  90. print(f"{prefix}• {item}")
  91. def key_value(self, key: str, value: str, indent: int = 2) -> None:
  92. """Print a key-value pair."""
  93. prefix = " " * indent
  94. if self.use_colors:
  95. print(f"{prefix}\033[1m{key}:\033[0m {value}")
  96. else:
  97. print(f"{prefix}{key}: {value}")
  98. def spinner_start(self, message: str) -> None:
  99. """Start a spinner (simple implementation)."""
  100. sys.stdout.write(f"\r{message}... ")
  101. sys.stdout.flush()
  102. def spinner_stop(self, success: bool = True, message: str | None = None) -> None:
  103. """Stop the spinner and show result."""
  104. if success:
  105. symbol = "✅" if message else "Done"
  106. sys.stdout.write(f"\r{symbol} {message or ''}\n")
  107. else:
  108. symbol = "❌" if message else "Failed"
  109. sys.stdout.write(f"\r{symbol} {message or ''}\n")
  110. sys.stdout.flush()
  111. class ProgressLogger:
  112. """Logger for tracking progress through multiple steps."""
  113. def __init__(self, total_steps: int, logger: Logger | None = None):
  114. """Initialize progress logger.
  115. Args:
  116. total_steps: Total number of steps
  117. logger: Logger instance to use (creates new if None)
  118. """
  119. self.total_steps = total_steps
  120. self.current_step = 0
  121. self.logger = logger or Logger()
  122. self.start_time = time.time()
  123. def next_step(self, description: str) -> None:
  124. """Move to next step and log it."""
  125. self.current_step += 1
  126. elapsed = time.time() - self.start_time
  127. if self.logger.use_colors:
  128. progress_bar = self._create_progress_bar()
  129. print(f"\n\033[1m[Step {self.current_step}/{self.total_steps}]\033[0m {progress_bar}")
  130. self.logger.step(f"{description} (Elapsed: {elapsed:.1f}s)")
  131. else:
  132. print(f"\n[Step {self.current_step}/{self.total_steps}]")
  133. self.logger.step(f"{description} (Elapsed: {elapsed:.1f}s)")
  134. def _create_progress_bar(self, width: int = 20) -> str:
  135. """Create a simple progress bar."""
  136. filled = int(width * self.current_step / self.total_steps)
  137. bar = "█" * filled + "░" * (width - filled)
  138. percentage = int(100 * self.current_step / self.total_steps)
  139. return f"[{bar}] {percentage}%"
  140. def complete(self) -> None:
  141. """Mark progress as complete."""
  142. elapsed = time.time() - self.start_time
  143. self.logger.success(f"All steps completed! Total time: {elapsed:.1f}s")
  144. # Create default logger instance
  145. logger = Logger()
  146. # Convenience functions using default logger
  147. def debug(message: str, indent: int = 0) -> None:
  148. """Log debug message using default logger."""
  149. logger.debug(message, indent)
  150. def info(message: str, indent: int = 0) -> None:
  151. """Log info message using default logger."""
  152. logger.info(message, indent)
  153. def success(message: str, indent: int = 0) -> None:
  154. """Log success message using default logger."""
  155. logger.success(message, indent)
  156. def warning(message: str, indent: int = 0) -> None:
  157. """Log warning message using default logger."""
  158. logger.warning(message, indent)
  159. def error(message: str, indent: int = 0) -> None:
  160. """Log error message using default logger."""
  161. logger.error(message, indent)
  162. def step(message: str, indent: int = 0) -> None:
  163. """Log step using default logger."""
  164. logger.step(message, indent)
  165. def progress(message: str, indent: int = 0) -> None:
  166. """Log progress using default logger."""
  167. logger.progress(message, indent)