feat: Enhance logging configuration and improve Langfuse initialization logging
Some checks are pending
CI/CD Pipeline / test (push) Waiting to run

This commit is contained in:
Ireneusz Bachanowicz 2025-07-13 20:36:45 +02:00
parent f3c70b9b0f
commit a3551d4233
3 changed files with 57 additions and 34 deletions

View File

@ -23,23 +23,23 @@ class LangfuseConfig(BaseSettings):
def __init__(self, **data): def __init__(self, **data):
try: try:
logger.info("Initializing LangfuseConfig with data: %s", data) logger.info("Initializing LangfuseConfig with data: {}", data)
logger.info("Environment variables:") logger.info("Environment variables:")
logger.info("LANGFUSE_PUBLIC_KEY: %s", os.getenv('LANGFUSE_PUBLIC_KEY')) logger.info("LANGFUSE_PUBLIC_KEY: {}", os.getenv('LANGFUSE_PUBLIC_KEY'))
logger.info("LANGFUSE_SECRET_KEY: %s", os.getenv('LANGFUSE_SECRET_KEY')) logger.info("LANGFUSE_SECRET_KEY: {}", os.getenv('LANGFUSE_SECRET_KEY'))
logger.info("LANGFUSE_HOST: %s", os.getenv('LANGFUSE_HOST')) logger.info("LANGFUSE_HOST: {}", os.getenv('LANGFUSE_HOST'))
super().__init__(**data) super().__init__(**data)
logger.info("LangfuseConfig initialized successfully") logger.info("LangfuseConfig initialized successfully")
logger.info("Public Key: %s", self.public_key) logger.info("Public Key: {}", self.public_key)
logger.info("Secret Key: %s", self.secret_key) logger.info("Secret Key: {}", self.secret_key)
logger.info("Host: %s", self.host) logger.info("Host: {}", self.host)
except Exception as e: except Exception as e:
logger.error("Failed to initialize LangfuseConfig: %s", e) logger.error("Failed to initialize LangfuseConfig: {}", e)
logger.error("Current environment variables:") logger.error("Current environment variables:")
logger.error("LANGFUSE_PUBLIC_KEY: %s", os.getenv('LANGFUSE_PUBLIC_KEY')) logger.error("LANGFUSE_PUBLIC_KEY: {}", os.getenv('LANGFUSE_PUBLIC_KEY'))
logger.error("LANGFUSE_SECRET_KEY: %s", os.getenv('LANGFUSE_SECRET_KEY')) logger.error("LANGFUSE_SECRET_KEY: {}", os.getenv('LANGFUSE_SECRET_KEY'))
logger.error("LANGFUSE_HOST: %s", os.getenv('LANGFUSE_HOST')) logger.error("LANGFUSE_HOST: {}", os.getenv('LANGFUSE_HOST'))
raise raise
model_config = ConfigDict( model_config = ConfigDict(
@ -89,15 +89,15 @@ class Settings:
try: try:
logger.info("Initializing LogConfig") logger.info("Initializing LogConfig")
self.log = LogConfig() self.log = LogConfig()
logger.info("LogConfig initialized: %s", self.log.model_dump()) logger.info("LogConfig initialized: {}", self.log.model_dump())
logger.info("Initializing LLMConfig") logger.info("Initializing LLMConfig")
self.llm = LLMConfig() self.llm = LLMConfig()
logger.info("LLMConfig initialized: %s", self.llm.model_dump()) logger.info("LLMConfig initialized: {}", self.llm.model_dump())
logger.info("Initializing LangfuseConfig") logger.info("Initializing LangfuseConfig")
self.langfuse = LangfuseConfig() self.langfuse = LangfuseConfig()
logger.info("LangfuseConfig initialized: %s", self.langfuse.model_dump()) logger.info("LangfuseConfig initialized: {}", self.langfuse.model_dump())
logger.info("Validating configuration") logger.info("Validating configuration")
self._validate() self._validate()
@ -107,15 +107,15 @@ class Settings:
self._init_langfuse() self._init_langfuse()
logger.info("Configuration initialized successfully") logger.info("Configuration initialized successfully")
except Exception as e: except Exception as e:
logger.error(f"Configuration initialization failed: {e}") logger.error("Configuration initialization failed: {}", e)
logger.error("Current configuration state:") logger.error("Current configuration state:")
logger.error("LogConfig: %s", self.log.model_dump() if hasattr(self, 'log') else 'Not initialized') logger.error("LogConfig: {}", self.log.model_dump() if hasattr(self, 'log') else 'Not initialized')
logger.error("LLMConfig: %s", self.llm.model_dump() if hasattr(self, 'llm') else 'Not initialized') logger.error("LLMConfig: {}", self.llm.model_dump() if hasattr(self, 'llm') else 'Not initialized')
logger.error("LangfuseConfig: %s", self.langfuse.model_dump() if hasattr(self, 'langfuse') else 'Not initialized') logger.error("LangfuseConfig: {}", self.langfuse.model_dump() if hasattr(self, 'langfuse') else 'Not initialized')
raise raise
def _validate(self): def _validate(self):
logger.info(f"LLM mode set to: '{self.llm.mode}'") logger.info("LLM mode set to: '{}'", self.llm.mode)
if self.llm.mode == 'openai': if self.llm.mode == 'openai':
if not self.llm.openai_api_key: if not self.llm.openai_api_key:
@ -140,6 +140,11 @@ class Settings:
if not all([self.langfuse.public_key, self.langfuse.secret_key, self.langfuse.host]): if not all([self.langfuse.public_key, self.langfuse.secret_key, self.langfuse.host]):
raise ValueError("Missing required Langfuse credentials") raise ValueError("Missing required Langfuse credentials")
logger.debug("Initializing Langfuse client with:")
logger.debug("Public Key: {}", self.langfuse.public_key)
logger.debug("Secret Key: {}", self.langfuse.secret_key)
logger.debug("Host: {}", self.langfuse.host)
# Initialize Langfuse client # Initialize Langfuse client
self.langfuse_client = Langfuse( self.langfuse_client = Langfuse(
public_key=self.langfuse.public_key, public_key=self.langfuse.public_key,
@ -147,6 +152,14 @@ class Settings:
host=self.langfuse.host host=self.langfuse.host
) )
# Test Langfuse connection
try:
self.langfuse_client.auth_check()
logger.debug("Langfuse connection test successful")
except Exception as e:
logger.error("Langfuse connection test failed: {}", e)
raise
# Initialize CallbackHandler # Initialize CallbackHandler
self.langfuse_handler = CallbackHandler( self.langfuse_handler = CallbackHandler(
public_key=self.langfuse.public_key, public_key=self.langfuse.public_key,
@ -156,10 +169,10 @@ class Settings:
logger.info("Langfuse client and handler initialized successfully") logger.info("Langfuse client and handler initialized successfully")
except ValueError as e: except ValueError as e:
logger.warning(f"Langfuse configuration error: {e}. Disabling Langfuse.") logger.warning("Langfuse configuration error: {}. Disabling Langfuse.", e)
self.langfuse.enabled = False self.langfuse.enabled = False
except Exception as e: except Exception as e:
logger.error(f"Failed to initialize Langfuse: {e}") logger.error("Failed to initialize Langfuse: {}", e)
self.langfuse.enabled = False self.langfuse.enabled = False
def _start_watcher(self): def _start_watcher(self):
@ -173,7 +186,7 @@ class Settings:
self._validate() self._validate()
logger.info("Configuration reloaded successfully") logger.info("Configuration reloaded successfully")
except Exception as e: except Exception as e:
logger.error(f"Error reloading configuration: {e}") logger.error("Error reloading configuration: {}", e)
Thread(target=watch_config, daemon=True).start() Thread(target=watch_config, daemon=True).start()
@ -181,6 +194,6 @@ class Settings:
try: try:
settings = Settings() settings = Settings()
except ValueError as e: except ValueError as e:
logger.error(f"FATAL: {e}") logger.error("FATAL: {}", e)
logger.error("Application shutting down due to configuration error.") logger.error("Application shutting down due to configuration error.")
sys.exit(1) sys.exit(1)

View File

@ -1,3 +1,6 @@
from dotenv import load_dotenv
load_dotenv()
from fastapi import FastAPI, Request, HTTPException from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel from pydantic import BaseModel
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
@ -14,6 +17,9 @@ from webhooks.handlers import JiraWebhookHandler
from llm.models import JiraWebhookPayload from llm.models import JiraWebhookPayload
from logging_config import configure_logging from logging_config import configure_logging
# Initialize logging first
configure_logging(log_level="DEBUG")
try: try:
app = FastAPI() app = FastAPI()
logger.info("FastAPI application initialized") logger.info("FastAPI application initialized")
@ -21,9 +27,6 @@ except Exception as e:
logger.error(f"Error initializing FastAPI: {str(e)}") logger.error(f"Error initializing FastAPI: {str(e)}")
raise raise
# Initialize logging
configure_logging(log_level=settings.log.level)
def retry(max_retries: int = 3, delay: float = 1.0): def retry(max_retries: int = 3, delay: float = 1.0):
"""Decorator for retrying failed operations""" """Decorator for retrying failed operations"""
def decorator(func): def decorator(func):

View File

@ -1,13 +1,13 @@
import sys import sys
from loguru import logger
logger.configure(
extra={"request_id": "N/A"}
)
import os import os
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
from typing import Optional from typing import Optional
from loguru import logger
# Initialize logger with default configuration
logger.remove()
logger.add(sys.stderr, level="WARNING", format="{message}")
def configure_logging(log_level: str = "INFO", log_dir: Optional[str] = None): def configure_logging(log_level: str = "INFO", log_dir: Optional[str] = None):
"""Configure structured logging for the application""" """Configure structured logging for the application"""
@ -22,7 +22,7 @@ def configure_logging(log_level: str = "INFO", log_dir: Optional[str] = None):
# Log file path with timestamp # Log file path with timestamp
log_file = Path(log_dir) / f"jira-webhook-llm_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" log_file = Path(log_dir) / f"jira-webhook-llm_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
# Remove default logger # Remove any existing loggers
logger.remove() logger.remove()
# Add console logger # Add console logger
@ -30,7 +30,9 @@ def configure_logging(log_level: str = "INFO", log_dir: Optional[str] = None):
sys.stdout, sys.stdout,
level=log_level, level=log_level,
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {extra[request_id]} | {message}", format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {extra[request_id]} | {message}",
colorize=True colorize=True,
backtrace=True,
diagnose=True
) )
# Add file logger # Add file logger
@ -40,7 +42,12 @@ def configure_logging(log_level: str = "INFO", log_dir: Optional[str] = None):
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {extra[request_id]} | {message}", format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {extra[request_id]} | {message}",
rotation="100 MB", rotation="100 MB",
retention="30 days", retention="30 days",
compression="zip" compression="zip",
backtrace=True,
diagnose=True
) )
# Configure default extras
logger.configure(extra={"request_id": "N/A"})
logger.info("Logging configured successfully") logger.info("Logging configured successfully")