feat(logging): add configurable logging with file output support

Introduce --log-level and --log-file CLI arguments.
Add execution time tracking and detailed logs across all modules.
This commit is contained in:
2026-04-02 10:40:39 +08:00
parent eef3464257
commit 0bdebd5368
8 changed files with 248 additions and 15 deletions

View File

@@ -2,12 +2,17 @@ from __future__ import annotations
from argparse import ArgumentParser
from pathlib import Path
import logging
from .config import Settings
from .gemini import GeminiAnalyzer
from .logging_utils import configure_logging
from .pipeline import ProjectPipeline
logger = logging.getLogger(__name__)
def build_parser() -> ArgumentParser:
parser = ArgumentParser(description="Extract and explain UiPath project dependencies.")
parser.add_argument("project_dir", type=Path, help="UiPath project root directory")
@@ -22,6 +27,13 @@ def build_parser() -> ArgumentParser:
parser.add_argument("--model", help="Override GEMINI_MODEL")
parser.add_argument("--skip-analysis", action="store_true", help="Skip Gemini analysis and only prepare files")
parser.add_argument("--force", action="store_true", help="Overwrite the output directory if it already exists")
parser.add_argument(
"--log-level",
default="INFO",
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
help="Logging verbosity",
)
parser.add_argument("--log-file", type=Path, help="Optional file path to write logs to")
return parser
@@ -37,16 +49,37 @@ def main(argv: list[str] | None = None) -> int:
if not output_dir.is_absolute():
output_dir = Path.cwd() / output_dir
settings = Settings.from_env(args.env_file if args.env_file.exists() else None, model_override=args.model)
analyzer = None if args.skip_analysis else GeminiAnalyzer(settings)
log_file = args.log_file.expanduser() if args.log_file else None
if log_file is not None and not log_file.is_absolute():
log_file = Path.cwd() / log_file
configure_logging(level_name=args.log_level, log_file=log_file)
pipeline = ProjectPipeline(
project_root=project_root,
output_root=output_dir,
entry_name=args.entry,
force=args.force,
logger.info(
"Starting CLI run: project_root=%s output_dir=%s entry=%s analysis=%s",
project_root,
output_dir,
args.entry,
not args.skip_analysis,
)
report = pipeline.run(analyzer=analyzer)
env_file = args.env_file if args.env_file.exists() else None
if args.env_file and env_file is None:
logger.warning("Environment file not found, falling back to default dotenv lookup: %s", args.env_file)
try:
settings = Settings.from_env(env_file, model_override=args.model)
analyzer = None if args.skip_analysis else GeminiAnalyzer(settings)
pipeline = ProjectPipeline(
project_root=project_root,
output_root=output_dir,
entry_name=args.entry,
force=args.force,
)
report = pipeline.run(analyzer=analyzer)
except Exception:
logger.exception("CLI run failed")
return 1
print(f"Output written to: {report.output_root}")
print(f"Code written to: {report.code_root}")