Download src/common/logging.py from hembad/reranker: direct link, hf CLI and curl.
- Browser
- Download file 6.77 kB
-
https://huggingface.co/spaces/hembad/reranker/resolve/main/src/common/logging.py
- Command line
-
hf download hf://spaces/hembad/reranker/src/common/logging.py
-
curl -L -o logging.py https://huggingface.co/spaces/hembad/reranker/resolve/main/src/common/logging.py
6.77 kB
| """Structured logging: colored console renderer + the `step()` stage timer. | |
| Logging standard for this project: every pipeline stage runs inside ``with step("<concern>.<action>") as | |
| metrics:`` — it logs ``step.start`` then ``step.end`` with the elapsed seconds and whatever you attach via | |
| ``metrics["key"] = value``. No ``print()`` in the engine; no engine/library names in user-facing strings. | |
| Configuration is read from the environment (so this module has no dependency on the settings layer yet): | |
| ``RERANKER_LOG_LEVEL`` (default ``INFO``), ``RERANKER_LOG`` (set ``0`` to silence), ``NO_COLOR`` to drop | |
| ANSI. The stdlib ``import logging`` below is an ABSOLUTE import — Python resolves top-level imports against | |
| ``sys.path``, never this same-named sibling — so ``logging.INFO`` references the standard library correctly. | |
| """ | |
| from __future__ import annotations | |
| import contextlib | |
| import logging | |
| import os | |
| import sys | |
| import time | |
| from contextlib import contextmanager | |
| from typing import Any | |
| import structlog | |
| from structlog.typing import EventDict | |
| _log_configured = False | |
| # this module's own functions to skip when locating the real caller (logging plumbing, not user code) | |
| _CALLSITE_SKIP = {"step", "get_logger", "_callsite", "_configure_logging"} | |
| _ANSI = { | |
| "reset": "\033[0m", "bold": "\033[1m", "gray": "\033[90m", "red": "\033[31m", | |
| "green": "\033[32m", "yellow": "\033[33m", "blue": "\033[94m", "magenta": "\033[35m", "cyan": "\033[36m", | |
| } | |
| _LEVEL_COLOR = {"debug": "blue", "info": "green", "warning": "yellow", "error": "red", "critical": "red"} | |
| def _callsite(_logger: Any, _method_name: str, event_dict: EventDict) -> EventDict: | |
| """Add ``at`` (file:line) + ``func`` to each line, pointing at the code that opened the step.""" | |
| frame: Any = sys._getframe() | |
| while frame is not None: | |
| filename = frame.f_code.co_filename | |
| func = frame.f_code.co_name | |
| skip = ( | |
| "structlog" in filename | |
| or "contextlib" in filename | |
| or (os.path.basename(filename) == "logging.py" and func in _CALLSITE_SKIP) | |
| ) | |
| if not skip: | |
| event_dict["at"] = f"{os.path.basename(filename)}:{frame.f_lineno}" | |
| event_dict["func"] = func | |
| break | |
| frame = frame.f_back | |
| return event_dict | |
| def _make_console_renderer(colors: bool): | |
| """Build a renderer: ``time [level] [step] [file:line func] event key=value …``.""" | |
| def paint(text: str, *styles: str) -> str: | |
| if not colors: | |
| return text | |
| prefix = "".join(_ANSI[style] for style in styles) | |
| return f"{prefix}{text}{_ANSI['reset']}" | |
| def render(_logger: Any, _method: str, event_dict: EventDict) -> str: | |
| extra = dict(event_dict) | |
| timestamp = str(extra.pop("timestamp", "")) | |
| level = str(extra.pop("level", "info")) | |
| event = str(extra.pop("event", "")) | |
| name = extra.pop("step", None) or extra.pop("logger", None) | |
| extra.pop("logger", None) | |
| location = f"{extra.pop('at', '')} {extra.pop('func', '')}".strip() | |
| blocks = [paint(timestamp, "gray"), paint(f"[{level:<7}]", "bold", _LEVEL_COLOR.get(level, "green"))] | |
| if name: | |
| blocks.append(paint(f"[{name}]", "cyan")) | |
| if location: | |
| blocks.append(paint(f"[{location}]", "yellow")) | |
| blocks.append(paint(event, "bold", "blue")) | |
| header_line = " ".join(block for block in blocks if block) | |
| pairs = " ".join( | |
| f"{paint(key, 'magenta')}={paint(str(value), 'green')}" for key, value in extra.items() | |
| ) | |
| return f"{header_line} {pairs}".rstrip() | |
| return render | |
| def _configure_logging(force: bool = False) -> None: | |
| """Configure structlog once from the environment (idempotent).""" | |
| global _log_configured | |
| if _log_configured and not force: | |
| return | |
| if os.environ.get("RERANKER_LOG", "1") == "0": | |
| # Silence: filter at CRITICAL so info/warning/error are dropped (the engine never logs CRITICAL). | |
| # NOTE: structlog only accepts standard levels here — CRITICAL+1 raises KeyError. | |
| structlog.configure( | |
| wrapper_class=structlog.make_filtering_bound_logger(logging.CRITICAL), | |
| cache_logger_on_first_use=True, | |
| ) | |
| _log_configured = True | |
| return | |
| with contextlib.suppress(Exception): | |
| sys.stdout.reconfigure(encoding="utf-8", line_buffering=True) # type: ignore[union-attr] | |
| colors = "NO_COLOR" not in os.environ | |
| if colors: | |
| with contextlib.suppress(Exception): # wrap stdout so ANSI works on legacy Windows consoles | |
| import colorama | |
| colorama.init() | |
| level = getattr(logging, os.environ.get("RERANKER_LOG_LEVEL", "INFO").upper(), logging.INFO) | |
| structlog.configure( | |
| processors=[ | |
| structlog.contextvars.merge_contextvars, | |
| structlog.processors.add_log_level, | |
| structlog.processors.TimeStamper(fmt="%H:%M:%S", utc=False), | |
| _callsite, | |
| _make_console_renderer(colors), | |
| ], | |
| wrapper_class=structlog.make_filtering_bound_logger(level), | |
| cache_logger_on_first_use=True, | |
| ) | |
| _log_configured = True | |
| def get_logger(name: str | None = None): | |
| """Return a configured structlog logger, with the concern ``name`` bound as ``logger=``.""" | |
| _configure_logging() | |
| log = structlog.get_logger(name) | |
| return log.bind(logger=name) if name else log | |
| def _phase_banner(text: str) -> None: | |
| """A plain full-width divider line bracketing every phase, for grep/scroll tracing in a long log stream | |
| (``grep -A20 "PHASE START: rank.explain"``). Bypasses the structured renderer on purpose — this is a visual | |
| marker, not a parseable event — but still respects ``RERANKER_LOG=0`` silencing.""" | |
| if os.environ.get("RERANKER_LOG", "1") == "0": | |
| return | |
| print(f"--------------------------- {text} ---------------------------") | |
| def step(label: str, **context: Any): | |
| """Log ``step.start`` / ``step.end`` (+seconds, +metrics), bracketed by PHASE banners. Yields a mutable | |
| metrics dict.""" | |
| _phase_banner(f"PHASE START: {label}") | |
| log = get_logger("step").bind(step=label, **context) | |
| log.info("step.start") | |
| metrics: dict[str, Any] = {} | |
| start = time.perf_counter() | |
| try: | |
| yield metrics | |
| except Exception as exc: | |
| log.error("step.fail", seconds=round(time.perf_counter() - start, 3), error=str(exc)) | |
| _phase_banner(f"PHASE FAILED: {label} ({round(time.perf_counter() - start, 3)}s)") | |
| raise | |
| else: | |
| log.info("step.end", seconds=round(time.perf_counter() - start, 3), **metrics) | |
| _phase_banner(f"PHASE END: {label} ({round(time.perf_counter() - start, 3)}s)") | |