diff --git a/gateway/run.py b/gateway/run.py index 81018722c..19f994ed5 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 a88552e2e..b83c22f53 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 a420aafcc..3344dae04 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)")