|
|
|
|
|
|
|
|
import logging |
|
|
import os |
|
|
from datetime import datetime |
|
|
from pathlib import Path |
|
|
from typing import Optional |
|
|
|
|
|
def setup_logging(log_level: str = "INFO", log_to_file: bool = True, log_dir: Optional[str] = None) -> logging.Logger: |
|
|
"""Set up logging configuration for the AI Co-Scientist system. |
|
|
|
|
|
Args: |
|
|
log_level: The logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
|
|
log_to_file: Whether to log to a file in addition to console |
|
|
log_dir: Optional directory for log files. If None, logs are stored in 'logs' |
|
|
directory in the project root |
|
|
|
|
|
Returns: |
|
|
The configured logger instance |
|
|
""" |
|
|
|
|
|
numeric_level = getattr(logging, log_level.upper(), logging.INFO) |
|
|
|
|
|
|
|
|
logger = logging.getLogger() |
|
|
logger.setLevel(numeric_level) |
|
|
|
|
|
|
|
|
for handler in logger.handlers[:]: |
|
|
logger.removeHandler(handler) |
|
|
|
|
|
|
|
|
console_handler = logging.StreamHandler() |
|
|
console_handler.setLevel(numeric_level) |
|
|
|
|
|
|
|
|
formatter = logging.Formatter( |
|
|
'%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
|
|
datefmt='%Y-%m-%d %H:%M:%S' |
|
|
) |
|
|
console_handler.setFormatter(formatter) |
|
|
|
|
|
|
|
|
logger.addHandler(console_handler) |
|
|
|
|
|
|
|
|
if log_to_file: |
|
|
if log_dir is None: |
|
|
|
|
|
project_root = Path(__file__).parents[2] |
|
|
log_dir = project_root / "logs" |
|
|
else: |
|
|
log_dir = Path(log_dir) |
|
|
|
|
|
|
|
|
os.makedirs(log_dir, exist_ok=True) |
|
|
|
|
|
|
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
|
|
log_file = log_dir / f"ai_coscientist_{timestamp}.log" |
|
|
|
|
|
|
|
|
file_handler = logging.FileHandler(log_file) |
|
|
file_handler.setLevel(numeric_level) |
|
|
file_handler.setFormatter(formatter) |
|
|
|
|
|
|
|
|
logger.addHandler(file_handler) |
|
|
logger.info(f"Logging to file: {log_file}") |
|
|
|
|
|
logger.info(f"Logging initialized at level {log_level}") |
|
|
return logger |
|
|
|