- Remove console StreamHandler from get_logger() — say() already handles console output via click.echo(); having both caused every message to appear twice - Move GRM_LOG_LEVEL filtering into ui.say() via _console_level() so console verbosity is still user-controllable while the log file always captures everything at DEBUG - Remove [GRM] prefix from say() calls — no longer needed without duplicate logger output, giving cleaner user-facing messages - Update test_logging_config.py: remove console handler tests and _level_from_env tests (now in test_ui.py), expect 1 handler only - Add test_ui.py coverage for _console_level and say() level filtering - Update README to document single-path console output via click.echo - 116 tests, 100% coverage, pyright clean, ruff clean
40 lines
1.3 KiB
Python
40 lines
1.3 KiB
Python
"""User-facing output utilities for GRM.
|
|
|
|
Console messages are colorised via ``click.style`` for visual feedback.
|
|
The persistent log file always receives plain text (no ANSI codes).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
|
|
import click
|
|
|
|
|
|
def _console_level() -> int:
|
|
"""Return the minimum level for console output from ``GRM_LOG_LEVEL``."""
|
|
value = os.getenv("GRM_LOG_LEVEL", "INFO")
|
|
try:
|
|
return getattr(logging, value.upper())
|
|
except AttributeError:
|
|
return logging.INFO
|
|
|
|
|
|
def say(msg: str, level: int = logging.INFO, err: bool = False, color: str | None = None) -> None:
|
|
"""Output a message to the user and also log it for auditing.
|
|
|
|
Console output goes via ``click.echo`` (handles encoding, CliRunner,
|
|
Windows colorama) only when *level* is at least ``GRM_LOG_LEVEL``.
|
|
The same message is always sent to the ``grm`` logger so it appears
|
|
in the persistent log file regardless of console verbosity.
|
|
|
|
The optional *color* parameter is passed to ``click.style`` so the
|
|
console line is tinted (e.g. ``color="green"``). The log file always
|
|
stores the raw plain text.
|
|
"""
|
|
if level >= _console_level():
|
|
styled = click.style(msg, fg=color) if color else msg
|
|
click.echo(styled, err=err)
|
|
logging.getLogger("grm").log(level, msg)
|