98 lines
3.9 KiB
Python
98 lines
3.9 KiB
Python
import datetime
|
|
import logging
|
|
import os
|
|
from functools import wraps
|
|
|
|
from fastapi import HTTPException
|
|
from fastapi.security import OAuth2PasswordBearer
|
|
|
|
date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
|
|
logger = logging.getLogger('discord_app')
|
|
|
|
# date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
|
|
# log_level = logger.info if os.environ.get('LOG_LEVEL') == 'INFO' else 'WARN'
|
|
# logging.basicConfig(
|
|
# filename=f'logs/database/{date}.log',
|
|
# format='%(asctime)s - sba-database - %(levelname)s - %(message)s',
|
|
# level=log_level
|
|
# )
|
|
|
|
|
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
|
priv_help = False if not os.environ.get('PRIVATE_IN_SCHEMA') else os.environ.get('PRIVATE_IN_SCHEMA').upper()
|
|
PRIVATE_IN_SCHEMA = True if priv_help == 'TRUE' else False
|
|
|
|
|
|
def valid_token(token):
|
|
return token == os.environ.get('API_TOKEN')
|
|
|
|
|
|
def handle_db_errors(func):
|
|
"""
|
|
Decorator to handle database connection errors and transaction rollbacks.
|
|
Ensures proper cleanup of database connections and provides consistent error handling.
|
|
Includes comprehensive logging with function context, timing, and stack traces.
|
|
"""
|
|
@wraps(func)
|
|
async def wrapper(*args, **kwargs):
|
|
import time
|
|
import traceback
|
|
from .db_engine import db # Import here to avoid circular imports
|
|
|
|
start_time = time.time()
|
|
func_name = f"{func.__module__}.{func.__name__}"
|
|
|
|
# Sanitize arguments for logging (exclude sensitive data)
|
|
safe_args = []
|
|
safe_kwargs = {}
|
|
|
|
try:
|
|
# Log sanitized arguments (avoid logging tokens, passwords, etc.)
|
|
for i, arg in enumerate(args):
|
|
if hasattr(arg, '__dict__') and hasattr(arg, 'url'): # FastAPI Request object
|
|
safe_args.append(f"Request({getattr(arg, 'method', 'UNKNOWN')} {getattr(arg, 'url', 'unknown')})")
|
|
else:
|
|
safe_args.append(str(arg)[:100]) # Truncate long values
|
|
|
|
for key, value in kwargs.items():
|
|
if key.lower() in ['token', 'password', 'secret', 'key']:
|
|
safe_kwargs[key] = '[REDACTED]'
|
|
else:
|
|
safe_kwargs[key] = str(value)[:100] # Truncate long values
|
|
|
|
logger.info(f"Starting {func_name} - args: {safe_args}, kwargs: {safe_kwargs}")
|
|
|
|
result = await func(*args, **kwargs)
|
|
|
|
elapsed_time = time.time() - start_time
|
|
logger.info(f"Completed {func_name} successfully in {elapsed_time:.3f}s")
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
elapsed_time = time.time() - start_time
|
|
error_trace = traceback.format_exc()
|
|
|
|
logger.error(f"Database error in {func_name} after {elapsed_time:.3f}s")
|
|
logger.error(f"Function args: {safe_args}")
|
|
logger.error(f"Function kwargs: {safe_kwargs}")
|
|
logger.error(f"Exception: {str(e)}")
|
|
logger.error(f"Full traceback:\n{error_trace}")
|
|
|
|
try:
|
|
logger.info(f"Attempting database rollback for {func_name}")
|
|
db.rollback()
|
|
logger.info(f"Database rollback successful for {func_name}")
|
|
except Exception as rollback_error:
|
|
logger.error(f"Rollback failed in {func_name}: {rollback_error}")
|
|
finally:
|
|
try:
|
|
db.close()
|
|
logger.info(f"Database connection closed for {func_name}")
|
|
except Exception as close_error:
|
|
logger.error(f"Error closing database connection in {func_name}: {close_error}")
|
|
|
|
raise HTTPException(status_code=500, detail=f'Database error in {func_name}: {str(e)}')
|
|
|
|
return wrapper
|