mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-30 10:52:15 +00:00
feat(cli): add global verbose/quiet logging flags
New log_config.py with setup_logging() configuring the openjarvis logger (WARNING default, DEBUG on --verbose, ERROR on --quiet). RotatingFileHandler (5MB, 3 backups) enabled in verbose mode. Flags added to root CLI group and forwarded via click context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
d1d113c1b1
commit
390deeefd0
@@ -28,8 +28,17 @@ from openjarvis.cli.workflow_cmd import workflow
|
||||
|
||||
@click.group(help="OpenJarvis — modular AI assistant backend")
|
||||
@click.version_option(version=openjarvis.__version__, prog_name="jarvis")
|
||||
def cli() -> None:
|
||||
@click.option("--verbose", is_flag=True, default=False, help="Enable debug logging")
|
||||
@click.option("--quiet", is_flag=True, default=False, help="Suppress non-error output")
|
||||
@click.pass_context
|
||||
def cli(ctx: click.Context, verbose: bool, quiet: bool) -> None:
|
||||
"""Top-level CLI group."""
|
||||
from openjarvis.cli.log_config import setup_logging
|
||||
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj["verbose"] = verbose
|
||||
ctx.obj["quiet"] = quiet
|
||||
setup_logging(verbose=verbose, quiet=quiet)
|
||||
|
||||
|
||||
cli.add_command(init, "init")
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Global logging configuration for the OpenJarvis CLI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def setup_logging(
|
||||
verbose: bool = False,
|
||||
quiet: bool = False,
|
||||
log_file: Optional[Union[str, Path]] = None,
|
||||
) -> logging.Logger:
|
||||
"""Configure the ``openjarvis`` logger.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
verbose:
|
||||
Set log level to DEBUG.
|
||||
quiet:
|
||||
Set log level to ERROR (overrides verbose if both set).
|
||||
log_file:
|
||||
Path for a rotating file handler. When *verbose* is ``True``
|
||||
and no *log_file* is given, defaults to
|
||||
``~/.openjarvis/cli.log``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The configured ``openjarvis`` logger.
|
||||
"""
|
||||
logger = logging.getLogger("openjarvis")
|
||||
|
||||
# Clear existing handlers to avoid duplication across calls
|
||||
logger.handlers.clear()
|
||||
|
||||
if quiet:
|
||||
level = logging.ERROR
|
||||
elif verbose:
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = logging.WARNING
|
||||
|
||||
logger.setLevel(level)
|
||||
|
||||
# Console handler
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(level)
|
||||
fmt = logging.Formatter("%(levelname)s %(name)s: %(message)s")
|
||||
console_handler.setFormatter(fmt)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
# File handler (verbose or explicit path)
|
||||
if verbose or log_file is not None:
|
||||
if log_file is None:
|
||||
log_dir = Path.home() / ".openjarvis"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
log_file = log_dir / "cli.log"
|
||||
file_handler = RotatingFileHandler(
|
||||
str(log_file), maxBytes=5 * 1024 * 1024, backupCount=3,
|
||||
)
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_fmt = logging.Formatter(
|
||||
"%(asctime)s %(levelname)s %(name)s: %(message)s"
|
||||
)
|
||||
file_handler.setFormatter(file_fmt)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
return logger
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Tests for CLI log configuration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from openjarvis.cli.log_config import setup_logging
|
||||
|
||||
|
||||
class TestSetupLogging:
|
||||
def test_default_level_is_warning(self):
|
||||
logger = setup_logging(verbose=False, quiet=False)
|
||||
assert logger.level == logging.WARNING
|
||||
|
||||
def test_verbose_sets_debug(self):
|
||||
logger = setup_logging(verbose=True, quiet=False)
|
||||
assert logger.level == logging.DEBUG
|
||||
|
||||
def test_quiet_sets_error(self):
|
||||
logger = setup_logging(verbose=False, quiet=True)
|
||||
assert logger.level == logging.ERROR
|
||||
|
||||
def test_returns_logger(self):
|
||||
logger = setup_logging(verbose=False, quiet=False)
|
||||
assert isinstance(logger, logging.Logger)
|
||||
assert logger.name == "openjarvis"
|
||||
|
||||
def test_log_file_handler_on_verbose(self, tmp_path):
|
||||
log_file = tmp_path / "cli.log"
|
||||
logger = setup_logging(verbose=True, quiet=False, log_file=log_file)
|
||||
# Should have at least one file handler
|
||||
file_handlers = [
|
||||
h for h in logger.handlers
|
||||
if hasattr(h, "baseFilename")
|
||||
]
|
||||
assert len(file_handlers) >= 1
|
||||
# Clean up
|
||||
for h in logger.handlers[:]:
|
||||
logger.removeHandler(h)
|
||||
h.close()
|
||||
Reference in New Issue
Block a user