from logging.config import dictConfig from flask import Flask from flask_socketio import SocketIO from .models import db from .utils import init_password_generator, init_serializer from .auth import init_auth from .seed_db import seed_courses socketio = SocketIO(async_mode='eventlet', cors_allowed_origins="*") def create_app(): # Configure logging BEFORE creating the application object dictConfig({ 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'default': { 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', }, 'plain': { 'format': '%(message)s', } }, 'handlers': { # Console handler (keeps logs visible in terminal) 'wsgi': { 'class': 'logging.StreamHandler', 'stream': 'ext://flask.logging.wsgi_errors_stream', 'formatter': 'default' }, # File handler for Application Logs (slides.log) 'slides_file': { 'class': 'logging.handlers.RotatingFileHandler', 'filename': 'slides.log', 'maxBytes': 1024 * 1024 * 10, # 10 MB 'backupCount': 5, 'formatter': 'default', 'level': 'INFO', 'encoding': 'utf8' }, # File handler for Request Logs (requests.log) 'requests_file': { 'class': 'logging.handlers.RotatingFileHandler', 'filename': 'requests.log', 'maxBytes': 1024 * 1024 * 10, # 10 MB 'backupCount': 5, 'formatter': 'plain', # Requests already have timestamps/formatting 'level': 'INFO', 'encoding': 'utf8' } }, 'root': { 'level': 'INFO', 'handlers': ['wsgi', 'slides_file'] }, 'loggers': { # Isolate the Werkzeug request logger 'werkzeug': { 'level': 'INFO', 'handlers': ['wsgi', 'requests_file'], 'propagate': False # Prevent requests from leaking into slides.log } } }) app = Flask(__name__, static_folder='static', static_url_path='/static') app.config.from_object('config.Config') db.init_app(app) with app.app_context(): db.create_all() seed_courses() init_password_generator() init_serializer(app) init_auth(app) socketio.init_app(app) from .routes import main app.register_blueprint(main) return app