import json import logging import time from flask import Blueprint, render_template, request, Response, stream_with_context, jsonify from lib.log_handler import subscribe, unsubscribe, get_all_logs, query_logs pages_bp = Blueprint('pages', __name__) logger = logging.getLogger(__name__) @pages_bp.route('/') def index(): return render_template('index.html') @pages_bp.route('/db-manager') def db_manager(): return render_template('db_manager.html') @pages_bp.route('/logs') def logs_page(): return render_template('logs.html') @pages_bp.route('/api/logs/stream') def logs_stream(): sub_id, q = subscribe() def generate(): try: for entry in get_all_logs(): yield f"data: {json.dumps(entry, ensure_ascii=False)}\n\n" while True: if q: while q: entry = q.popleft() yield f"data: {json.dumps(entry, ensure_ascii=False)}\n\n" else: time.sleep(0.1) except GeneratorExit: pass finally: unsubscribe(sub_id) return Response( stream_with_context(generate()), mimetype='text/event-stream', headers={ 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no', 'Connection': 'keep-alive', } ) @pages_bp.route('/api/logs', methods=['GET']) def logs_poll(): """SPA 兼容的轮询接口:按 after_id 增量返回,并支持 level/source/q 过滤。""" after_id = request.args.get('after_id', 0) limit = request.args.get('limit', 200) level = request.args.get('level') or None source = request.args.get('source') or None keyword = request.args.get('q') or None result = query_logs(after_id=after_id, level=level, source=source, keyword=keyword, limit=limit) return jsonify({'success': True, **result}) @pages_bp.route('/api/logs/history') def logs_history(): source = request.args.get('source', 'all') level = request.args.get('level', 'all') keyword = request.args.get('keyword', '') logs = get_all_logs() if source != 'all': logs = [l for l in logs if l.get('source') == source] if level != 'all': logs = [l for l in logs if l.get('level') == level] if keyword: logs = [l for l in logs if keyword.lower() in l.get('message', '').lower()] return jsonify({'success': True, 'data': logs})