From 5bd01b838cf1b04f620862d7eaa1a822289aa470 Mon Sep 17 00:00:00 2001 From: Alan Justino Date: Wed, 1 Apr 2026 11:27:23 -0300 Subject: [PATCH] fix(gateway): wire -v/-q flags to stderr logging By default 'hermes gateway run' now prints WARNING+ to stderr so connection errors and startup failures are visible in the terminal without having to tail ~/.hermes/logs/gateway.log. - gateway/run.py: start_gateway() accepts verbosity: Optional[int]=0. When not None, attaches a StreamHandler to stderr with level mapped from the count (0=WARNING, 1=INFO, 2+=DEBUG). Root logger level is also lowered when DEBUG is requested so records are not swallowed. - hermes_cli/gateway.py: run_gateway() gains verbose: int and quiet: bool params. -q translates to verbosity=None (no stderr handler). Wired through gateway_command(). - hermes_cli/main.py: -v changed from store_true to action=count so -v/-vv/-vvv each increment the level. -q/--quiet added as a new flag. Behaviour summary: hermes gateway run -> WARNING+ on stderr (default) hermes gateway run -q -> silent hermes gateway run -v -> INFO+ hermes gateway run -vv -> DEBUG --- gateway/run.py | 17 ++++++++++++++++- hermes_cli/gateway.py | 13 ++++++++----- hermes_cli/main.py | 5 ++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/gateway/run.py b/gateway/run.py index 81018722cf..19f994ed58 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -6186,7 +6186,7 @@ def _start_cron_ticker(stop_event: threading.Event, adapters=None, interval: int logger.info("Cron ticker stopped") -async def start_gateway(config: Optional[GatewayConfig] = None, replace: bool = False) -> bool: +async def start_gateway(config: Optional[GatewayConfig] = None, replace: bool = False, verbosity: Optional[int] = 0) -> bool: """ Start the gateway and run until interrupted. @@ -6288,6 +6288,21 @@ async def start_gateway(config: Optional[GatewayConfig] = None, replace: bool = logging.getLogger().addHandler(file_handler) logging.getLogger().setLevel(logging.INFO) + # Optional stderr handler — level driven by -v/-q flags on the CLI. + # verbosity=None (-q/--quiet): no stderr output + # verbosity=0 (default): WARNING and above + # verbosity=1 (-v): INFO and above + # verbosity=2+ (-vv/-vvv): DEBUG + if verbosity is not None: + _stderr_level = {0: logging.WARNING, 1: logging.INFO}.get(verbosity, logging.DEBUG) + _stderr_handler = logging.StreamHandler() + _stderr_handler.setLevel(_stderr_level) + _stderr_handler.setFormatter(logging.Formatter('%(levelname)s %(name)s: %(message)s')) + logging.getLogger().addHandler(_stderr_handler) + # Lower root logger level if needed so DEBUG records can reach the handler + if _stderr_level < logging.getLogger().level: + logging.getLogger().setLevel(_stderr_level) + # Separate errors-only log for easy debugging error_handler = RotatingFileHandler( log_dir / 'errors.log', diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index a88552e2ee..b83c22f539 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -1092,11 +1092,12 @@ def launchd_status(deep: bool = False): # Gateway Runner # ============================================================================= -def run_gateway(verbose: bool = False, replace: bool = False): +def run_gateway(verbose: int = 0, quiet: bool = False, replace: bool = False): """Run the gateway in foreground. Args: - verbose: Enable verbose logging output. + verbose: Stderr log verbosity count added on top of default WARNING (0=WARNING, 1=INFO, 2+=DEBUG). + quiet: Suppress all stderr log output. replace: If True, kill any existing gateway instance before starting. This prevents systemd restart loops when the old process hasn't fully exited yet. @@ -1115,7 +1116,8 @@ def run_gateway(verbose: bool = False, replace: bool = False): # Exit with code 1 if gateway fails to connect any platform, # so systemd Restart=on-failure will retry on transient errors - success = asyncio.run(start_gateway(replace=replace)) + verbosity = None if quiet else verbose + success = asyncio.run(start_gateway(replace=replace, verbosity=verbosity)) if not success: sys.exit(1) @@ -1889,9 +1891,10 @@ def gateway_command(args): # Default to run if no subcommand if subcmd is None or subcmd == "run": - verbose = getattr(args, 'verbose', False) + verbose = getattr(args, 'verbose', 0) + quiet = getattr(args, 'quiet', False) replace = getattr(args, 'replace', False) - run_gateway(verbose, replace=replace) + run_gateway(verbose, quiet=quiet, replace=replace) return if subcmd == "setup": diff --git a/hermes_cli/main.py b/hermes_cli/main.py index a420aafcc6..3344dae040 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -3857,7 +3857,10 @@ For more help on a command: # gateway run (default) gateway_run = gateway_subparsers.add_parser("run", help="Run gateway in foreground") - gateway_run.add_argument("-v", "--verbose", action="store_true") + gateway_run.add_argument("-v", "--verbose", action="count", default=0, + help="Increase stderr log verbosity (-v=INFO, -vv=DEBUG)") + gateway_run.add_argument("-q", "--quiet", action="store_true", + help="Suppress all stderr log output") gateway_run.add_argument("--replace", action="store_true", help="Replace any existing gateway instance (useful for systemd)")