Source code for ai_essay_evaluator.evaluator.async_logger
# src/ai_essay_evaluator/evaluator/async_logger.py
import asyncio
import logging
import os
from datetime import datetime
[docs]
class AsyncLogger:
"""Async wrapper for logging that allows concurrent log operations"""
def __init__(self, enabled=False, log_directory="logs"):
self.enabled = enabled
self.log_directory = log_directory
self.logger = None
self.handler = None
self.log_file = None
if enabled:
self._setup_logger()
def _setup_logger(self):
"""Setup the logger with file handler"""
os.makedirs(self.log_directory, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
self.log_file = os.path.join(self.log_directory, f"ai_evaluator_{timestamp}.log")
# Create file handler
self.handler = logging.FileHandler(self.log_file)
self.handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
# Configure root logger
root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO)
root_logger.addHandler(self.handler)
# Set httpx logger to WARNING level to suppress INFO messages
logging.getLogger("httpx").setLevel(logging.WARNING)
# Set OpenAI logger to INFO to capture relevant OpenAI errors
logging.getLogger("openai").setLevel(logging.INFO)
self.logger = logging.getLogger(__name__)
[docs]
async def log(self, level, message, module=None, exc_info=False):
"""Asynchronously log a message"""
if not self.enabled or not self.logger:
return
logger_name = module or __name__
logger = logging.getLogger(logger_name)
await asyncio.to_thread(logger.log, level, message, exc_info=exc_info)
[docs]
def get_log_file(self) -> str | None:
"""Return the log file path if logging is enabled"""
return self.log_file if self.enabled else None
[docs]
def close(self):
"""Close the log handler"""
if self.enabled and self.handler:
self.logger.info("Closing log file")
self.handler.close()
root_logger = logging.getLogger()
root_logger.removeHandler(self.handler)