mirror of https://github.com/pyodide/pyodide.git
149 lines
3.7 KiB
Python
149 lines
3.7 KiB
Python
import logging
|
|
import os
|
|
from collections.abc import Generator
|
|
from contextlib import contextmanager
|
|
|
|
from rich.console import Console
|
|
from rich.highlighter import NullHighlighter
|
|
from rich.logging import RichHandler
|
|
from rich.theme import Theme
|
|
|
|
IN_CI = "CI" in os.environ
|
|
|
|
COLOR_THEME = Theme(
|
|
{
|
|
"debug": "",
|
|
"info": "",
|
|
"warning": "bold yellow",
|
|
"error": "bold red",
|
|
"critical": "bold red",
|
|
}
|
|
)
|
|
|
|
LEVEL_STDOUT = logging.INFO - 5
|
|
LEVEL_STDERR = logging.INFO + 5
|
|
|
|
|
|
# Note: it seems like rich's auto terminal detection mechanism doesn't work well for CircleCI.
|
|
# so we manually disable it when running in CI.
|
|
class CIAwareConsole(Console):
|
|
@property
|
|
def is_terminal(self) -> bool:
|
|
"""Check if the console is writing to a terminal."""
|
|
return not IN_CI and super().is_terminal
|
|
|
|
|
|
class StdoutFilter(logging.Filter):
|
|
def filter(self, record):
|
|
return record.levelno in (LEVEL_STDOUT, logging.DEBUG, logging.INFO)
|
|
|
|
|
|
class StderrFilter(logging.Filter):
|
|
def filter(self, record):
|
|
return record.levelno in (
|
|
LEVEL_STDERR,
|
|
logging.WARNING,
|
|
logging.ERROR,
|
|
logging.CRITICAL,
|
|
)
|
|
|
|
|
|
class _Logger(logging.Logger):
|
|
def success(self, msg, *args, **kwargs):
|
|
self.info("[bold green]%s[/bold green]", msg, *args, **kwargs)
|
|
|
|
def stdout(self, msg, *args, **kwargs):
|
|
self.log(LEVEL_STDOUT, msg, *args, **kwargs)
|
|
|
|
def stderr(self, msg, *args, **kwargs):
|
|
self.log(LEVEL_STDERR, msg, *args, **kwargs)
|
|
|
|
|
|
class RichFormatter(logging.Formatter):
|
|
"""Colorize log messages based on log level."""
|
|
|
|
def format(self, records: logging.LogRecord) -> str:
|
|
levelname = records.levelname.lower()
|
|
records.msg = f"[{levelname}]{records.msg}[/{levelname}]"
|
|
|
|
formatted = super().format(records)
|
|
return formatted
|
|
|
|
|
|
console_stdout = CIAwareConsole(theme=COLOR_THEME)
|
|
console_stderr = CIAwareConsole(stderr=True, theme=COLOR_THEME)
|
|
|
|
|
|
def _get_logger(log_level: int) -> _Logger:
|
|
logger = _Logger(__name__)
|
|
logger.setLevel(log_level)
|
|
|
|
rich_handler_stdout = RichHandler(
|
|
console=console_stdout,
|
|
highlighter=NullHighlighter(),
|
|
show_time=False,
|
|
show_level=False,
|
|
show_path=False,
|
|
markup=True,
|
|
)
|
|
rich_handler_stdout.setFormatter(RichFormatter("%(message)s"))
|
|
rich_handler_stderr = RichHandler(
|
|
console=console_stderr,
|
|
highlighter=NullHighlighter(),
|
|
show_time=False,
|
|
show_level=False,
|
|
show_path=False,
|
|
markup=True,
|
|
)
|
|
rich_handler_stderr.setFormatter(RichFormatter("%(message)s"))
|
|
|
|
rich_handler_stdout.addFilter(StdoutFilter())
|
|
rich_handler_stderr.addFilter(StderrFilter())
|
|
|
|
logger.addHandler(rich_handler_stdout)
|
|
logger.addHandler(rich_handler_stderr)
|
|
|
|
return logger
|
|
|
|
|
|
logger = _get_logger(logging.INFO)
|
|
|
|
|
|
@contextmanager
|
|
def set_log_level(
|
|
_logger: logging.Logger, log_level: int | bool
|
|
) -> Generator[None, None, None]:
|
|
"""Set the log level.
|
|
|
|
Parameters
|
|
----------
|
|
logger
|
|
The logger to set the log level for.
|
|
|
|
log_level
|
|
If True, set the log level to DEBUG (verbose mode).
|
|
If given an integer, set the log level to that value.
|
|
"""
|
|
|
|
original_log_level = logger.level
|
|
|
|
if isinstance(log_level, bool):
|
|
log_level = logging.DEBUG if log_level else original_log_level
|
|
|
|
_logger.setLevel(log_level)
|
|
|
|
yield
|
|
|
|
_logger.setLevel(original_log_level)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# For testing the colors
|
|
logger.debug("debug")
|
|
logger.info("info")
|
|
logger.stdout("stdout")
|
|
logger.warning("warning")
|
|
logger.error("error")
|
|
logger.success("success")
|
|
logger.stderr("stderr")
|