Implement database connection pooling with context manager pattern

- Added DBUtils PooledDB for intelligent connection pooling
- Created db_pool.py with lazy-initialized connection pool (max 20 connections)
- Added db_connection_context() context manager for safe connection handling
- Refactored all 19 database operations to use context manager pattern
- Ensures proper connection cleanup and exception handling
- Prevents connection exhaustion on POST requests
- Added logging configuration for debugging

Changes:
- py_app/app/db_pool.py: New connection pool manager
- py_app/app/logging_config.py: Centralized logging
- py_app/app/__init__.py: Updated to use connection pool
- py_app/app/routes.py: Refactored all DB operations to use context manager
- py_app/app/settings.py: Updated settings handlers
- py_app/requirements.txt: Added DBUtils dependency

This solves the connection timeout issues experienced with the fgscan page.
This commit is contained in:
Quality App System
2026-01-22 22:07:06 +02:00
parent fd801ab78d
commit 64b67b2979
9 changed files with 1928 additions and 920 deletions

View File

@@ -0,0 +1,142 @@
"""
Logging Configuration for Trasabilitate Application
Centralizes all logging setup for the application
"""
import logging
import logging.handlers
import os
import sys
from datetime import datetime
def setup_logging(app=None, log_dir='/srv/quality_app/logs'):
"""
Configure comprehensive logging for the application
Args:
app: Flask app instance (optional)
log_dir: Directory to store log files
"""
# Ensure log directory exists
os.makedirs(log_dir, exist_ok=True)
# Create formatters
detailed_formatter = logging.Formatter(
'[%(asctime)s] [%(name)s] [%(levelname)s] %(filename)s:%(lineno)d - %(funcName)s() - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
simple_formatter = logging.Formatter(
'[%(asctime)s] [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# Create logger
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
# Remove any existing handlers to avoid duplicates
for handler in root_logger.handlers[:]:
root_logger.removeHandler(handler)
# ========================================================================
# File Handler - All logs (DEBUG and above)
# ========================================================================
all_log_file = os.path.join(log_dir, f'application_{datetime.now().strftime("%Y%m%d")}.log')
file_handler_all = logging.handlers.RotatingFileHandler(
all_log_file,
maxBytes=10 * 1024 * 1024, # 10 MB
backupCount=10
)
file_handler_all.setLevel(logging.DEBUG)
file_handler_all.setFormatter(detailed_formatter)
root_logger.addHandler(file_handler_all)
# ========================================================================
# File Handler - Error logs (ERROR and above)
# ========================================================================
error_log_file = os.path.join(log_dir, f'errors_{datetime.now().strftime("%Y%m%d")}.log')
file_handler_errors = logging.handlers.RotatingFileHandler(
error_log_file,
maxBytes=5 * 1024 * 1024, # 5 MB
backupCount=5
)
file_handler_errors.setLevel(logging.ERROR)
file_handler_errors.setFormatter(detailed_formatter)
root_logger.addHandler(file_handler_errors)
# ========================================================================
# Console Handler - INFO and above (for Docker logs)
# ========================================================================
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(simple_formatter)
root_logger.addHandler(console_handler)
# ========================================================================
# Database-specific logger
# ========================================================================
db_logger = logging.getLogger('trasabilitate.db')
db_logger.setLevel(logging.DEBUG)
db_log_file = os.path.join(log_dir, f'database_{datetime.now().strftime("%Y%m%d")}.log')
db_file_handler = logging.handlers.RotatingFileHandler(
db_log_file,
maxBytes=10 * 1024 * 1024, # 10 MB
backupCount=10
)
db_file_handler.setLevel(logging.DEBUG)
db_file_handler.setFormatter(detailed_formatter)
db_logger.addHandler(db_file_handler)
# ========================================================================
# Routes-specific logger
# ========================================================================
routes_logger = logging.getLogger('trasabilitate.routes')
routes_logger.setLevel(logging.DEBUG)
routes_log_file = os.path.join(log_dir, f'routes_{datetime.now().strftime("%Y%m%d")}.log')
routes_file_handler = logging.handlers.RotatingFileHandler(
routes_log_file,
maxBytes=10 * 1024 * 1024, # 10 MB
backupCount=10
)
routes_file_handler.setLevel(logging.DEBUG)
routes_file_handler.setFormatter(detailed_formatter)
routes_logger.addHandler(routes_file_handler)
# ========================================================================
# Settings-specific logger
# ========================================================================
settings_logger = logging.getLogger('trasabilitate.settings')
settings_logger.setLevel(logging.DEBUG)
settings_log_file = os.path.join(log_dir, f'settings_{datetime.now().strftime("%Y%m%d")}.log')
settings_file_handler = logging.handlers.RotatingFileHandler(
settings_log_file,
maxBytes=5 * 1024 * 1024, # 5 MB
backupCount=5
)
settings_file_handler.setLevel(logging.DEBUG)
settings_file_handler.setFormatter(detailed_formatter)
settings_logger.addHandler(settings_file_handler)
# Log initialization
root_logger.info("=" * 80)
root_logger.info("Trasabilitate Application - Logging Initialized")
root_logger.info("=" * 80)
root_logger.info(f"Log directory: {log_dir}")
root_logger.info(f"Main log file: {all_log_file}")
root_logger.info(f"Error log file: {error_log_file}")
root_logger.info(f"Database log file: {db_log_file}")
root_logger.info(f"Routes log file: {routes_log_file}")
root_logger.info(f"Settings log file: {settings_log_file}")
root_logger.info("=" * 80)
return root_logger
def get_logger(name):
"""Get a logger with the given name"""
return logging.getLogger(f'trasabilitate.{name}')