后台管理页面导航栏修改为侧边
This commit is contained in:
34
scripts/flask-app.service
Normal file
34
scripts/flask-app.service
Normal file
@@ -0,0 +1,34 @@
|
||||
[Unit]
|
||||
Description=Flask Prompt Master Application
|
||||
After=network.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=renjianbo
|
||||
Group=renjianbo
|
||||
WorkingDirectory=/home/renjianbo/aitsc
|
||||
Environment=PATH=/home/renjianbo/miniconda3/envs/myenv/bin
|
||||
ExecStart=/home/renjianbo/aitsc/scripts/port_manager.sh start
|
||||
ExecStop=/home/renjianbo/aitsc/scripts/port_manager.sh stop
|
||||
ExecReload=/home/renjianbo/aitsc/scripts/port_manager.sh restart
|
||||
PIDFile=/home/renjianbo/aitsc/logs/gunicorn.pid
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StartLimitInterval=60
|
||||
StartLimitBurst=3
|
||||
|
||||
# 安全设置
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/home/renjianbo/aitsc/logs /home/renjianbo/aitsc/data
|
||||
|
||||
# 日志设置
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=flask-app
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
328
scripts/port_manager.sh
Executable file
328
scripts/port_manager.sh
Executable file
@@ -0,0 +1,328 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 端口管理脚本
|
||||
# 用于管理Flask应用的端口占用问题
|
||||
|
||||
# 配置
|
||||
PORT=5002
|
||||
APP_NAME="flask_prompt_master"
|
||||
PID_FILE="logs/gunicorn.pid"
|
||||
LOG_DIR="logs"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
echo -e "${BLUE}[DEBUG]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查端口是否被占用
|
||||
check_port() {
|
||||
log_info "检查端口 $PORT 占用情况..."
|
||||
|
||||
if ss -tlnp | grep -q ":$PORT "; then
|
||||
log_warn "端口 $PORT 已被占用"
|
||||
ss -tlnp | grep ":$PORT "
|
||||
return 1
|
||||
else
|
||||
log_info "端口 $PORT 未被占用"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取占用端口的进程
|
||||
get_port_processes() {
|
||||
log_info "获取占用端口 $PORT 的进程信息..."
|
||||
|
||||
local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u)
|
||||
|
||||
if [ -n "$processes" ]; then
|
||||
log_warn "占用端口 $PORT 的进程:"
|
||||
for pid in $processes; do
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
ps -p $pid -o pid,ppid,cmd --no-headers
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
else
|
||||
log_info "没有进程占用端口 $PORT"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理端口占用
|
||||
clean_port() {
|
||||
log_info "清理端口 $PORT 占用..."
|
||||
|
||||
local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u)
|
||||
|
||||
if [ -n "$processes" ]; then
|
||||
log_warn "发现占用端口 $PORT 的进程,正在清理..."
|
||||
|
||||
for pid in $processes; do
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
local cmd=$(ps -p $pid -o cmd --no-headers)
|
||||
log_info "终止进程 $pid: $cmd"
|
||||
kill -TERM $pid
|
||||
|
||||
# 等待进程终止
|
||||
local count=0
|
||||
while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
# 强制终止
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_warn "强制终止进程 $pid"
|
||||
kill -KILL $pid
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 验证清理结果
|
||||
sleep 2
|
||||
if check_port; then
|
||||
log_info "端口 $PORT 清理成功"
|
||||
return 0
|
||||
else
|
||||
log_error "端口 $PORT 清理失败"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_info "端口 $PORT 未被占用,无需清理"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查Gunicorn进程
|
||||
check_gunicorn() {
|
||||
log_info "检查Gunicorn进程状态..."
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
local pid=$(cat "$PID_FILE")
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_info "Gunicorn主进程 $pid 正在运行"
|
||||
local workers=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | wc -l)
|
||||
log_info "工作进程数量: $workers"
|
||||
return 0
|
||||
else
|
||||
log_warn "PID文件存在但进程不存在: $pid"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_warn "PID文件不存在: $PID_FILE"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 启动应用
|
||||
start_app() {
|
||||
log_info "启动Flask应用..."
|
||||
|
||||
# 切换到项目目录
|
||||
cd "$PROJECT_DIR" || {
|
||||
log_error "无法切换到项目目录: $PROJECT_DIR"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 激活conda环境
|
||||
if command -v conda > /dev/null 2>&1; then
|
||||
log_info "激活conda环境..."
|
||||
eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv
|
||||
fi
|
||||
|
||||
# 检查端口
|
||||
if ! check_port; then
|
||||
log_warn "端口被占用,尝试清理..."
|
||||
if ! clean_port; then
|
||||
log_error "无法清理端口占用,启动失败"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 启动Gunicorn
|
||||
log_info "启动Gunicorn服务..."
|
||||
nohup gunicorn -c gunicorn.conf.py run_dev:app > "$LOG_DIR/gunicorn_startup.log" 2>&1 &
|
||||
|
||||
# 等待启动
|
||||
sleep 5
|
||||
|
||||
# 验证启动
|
||||
if check_gunicorn; then
|
||||
log_info "应用启动成功"
|
||||
return 0
|
||||
else
|
||||
log_error "应用启动失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 停止应用
|
||||
stop_app() {
|
||||
log_info "停止Flask应用..."
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
local pid=$(cat "$PID_FILE")
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_info "停止Gunicorn主进程 $pid"
|
||||
kill -TERM $pid
|
||||
|
||||
# 等待进程终止
|
||||
local count=0
|
||||
while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
# 强制终止
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_warn "强制终止进程 $pid"
|
||||
kill -KILL $pid
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 清理所有相关进程
|
||||
local gunicorn_pids=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | awk '{print $2}')
|
||||
if [ -n "$gunicorn_pids" ]; then
|
||||
log_info "清理Gunicorn工作进程..."
|
||||
for pid in $gunicorn_pids; do
|
||||
kill -TERM $pid 2>/dev/null
|
||||
done
|
||||
fi
|
||||
|
||||
log_info "应用停止完成"
|
||||
}
|
||||
|
||||
# 重启应用
|
||||
restart_app() {
|
||||
log_info "重启Flask应用..."
|
||||
stop_app
|
||||
sleep 2
|
||||
start_app
|
||||
}
|
||||
|
||||
# 状态检查
|
||||
status() {
|
||||
log_info "=== Flask应用状态检查 ==="
|
||||
|
||||
echo "1. 端口占用检查:"
|
||||
if check_port; then
|
||||
echo " ✅ 端口 $PORT 可用"
|
||||
else
|
||||
echo " ❌ 端口 $PORT 被占用"
|
||||
get_port_processes
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "2. Gunicorn进程检查:"
|
||||
if check_gunicorn; then
|
||||
echo " ✅ Gunicorn正在运行"
|
||||
else
|
||||
echo " ❌ Gunicorn未运行"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "3. 服务响应检查:"
|
||||
if curl -s http://localhost:$PORT/ > /dev/null 2>&1; then
|
||||
echo " ✅ 服务正常响应"
|
||||
else
|
||||
echo " ❌ 服务无响应"
|
||||
fi
|
||||
}
|
||||
|
||||
# 监控模式
|
||||
monitor() {
|
||||
log_info "启动端口监控模式..."
|
||||
|
||||
while true; do
|
||||
if ! check_gunicorn; then
|
||||
log_warn "检测到Gunicorn进程异常,尝试重启..."
|
||||
restart_app
|
||||
fi
|
||||
|
||||
if ! curl -s http://localhost:$PORT/ > /dev/null 2>&1; then
|
||||
log_warn "检测到服务无响应,尝试重启..."
|
||||
restart_app
|
||||
fi
|
||||
|
||||
sleep 30
|
||||
done
|
||||
}
|
||||
|
||||
# 帮助信息
|
||||
show_help() {
|
||||
echo "端口管理脚本使用方法:"
|
||||
echo ""
|
||||
echo " $0 check - 检查端口占用情况"
|
||||
echo " $0 clean - 清理端口占用"
|
||||
echo " $0 start - 启动应用"
|
||||
echo " $0 stop - 停止应用"
|
||||
echo " $0 restart - 重启应用"
|
||||
echo " $0 status - 查看应用状态"
|
||||
echo " $0 monitor - 启动监控模式"
|
||||
echo " $0 help - 显示帮助信息"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 status # 检查当前状态"
|
||||
echo " $0 restart # 重启应用"
|
||||
echo " $0 monitor # 后台监控"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
case "${1:-help}" in
|
||||
check)
|
||||
check_port
|
||||
;;
|
||||
clean)
|
||||
clean_port
|
||||
;;
|
||||
start)
|
||||
start_app
|
||||
;;
|
||||
stop)
|
||||
stop_app
|
||||
;;
|
||||
restart)
|
||||
restart_app
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
monitor)
|
||||
monitor
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
log_error "未知命令: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
399
scripts/port_monitor.py
Executable file
399
scripts/port_monitor.py
Executable file
@@ -0,0 +1,399 @@
|
||||
#!/home/renjianbo/miniconda3/envs/myenv/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
端口监控脚本
|
||||
用于监控Flask应用的端口占用和服务状态
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import subprocess
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# 配置
|
||||
PORT = 5002
|
||||
APP_NAME = "flask_prompt_master"
|
||||
PID_FILE = "logs/gunicorn.pid"
|
||||
LOG_FILE = "logs/port_monitor.log"
|
||||
CONFIG_FILE = "logs/monitor_config.json"
|
||||
ALERT_FILE = "logs/port_alerts.log"
|
||||
|
||||
# 日志配置
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(LOG_FILE),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class PortMonitor:
|
||||
def __init__(self):
|
||||
self.project_dir = Path(__file__).parent.parent
|
||||
self.pid_file = self.project_dir / PID_FILE
|
||||
self.config_file = self.project_dir / CONFIG_FILE
|
||||
self.alert_file = self.project_dir / ALERT_FILE
|
||||
|
||||
# 确保日志目录存在
|
||||
self.project_dir.mkdir(exist_ok=True)
|
||||
(self.project_dir / "logs").mkdir(exist_ok=True)
|
||||
|
||||
# 加载配置
|
||||
self.config = self.load_config()
|
||||
|
||||
def load_config(self):
|
||||
"""加载监控配置"""
|
||||
default_config = {
|
||||
"check_interval": 30, # 检查间隔(秒)
|
||||
"max_restart_attempts": 3, # 最大重启尝试次数
|
||||
"alert_threshold": 2, # 告警阈值
|
||||
"port_timeout": 5, # 端口检查超时时间
|
||||
"enable_alerts": True, # 启用告警
|
||||
"auto_restart": True, # 自动重启
|
||||
}
|
||||
|
||||
if self.config_file.exists():
|
||||
try:
|
||||
with open(self.config_file, 'r', encoding='utf-8') as f:
|
||||
config = json.load(f)
|
||||
default_config.update(config)
|
||||
except Exception as e:
|
||||
logger.error("加载配置文件失败: {}".format(e))
|
||||
|
||||
return default_config
|
||||
|
||||
def save_config(self):
|
||||
"""保存监控配置"""
|
||||
try:
|
||||
with open(self.config_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.config, f, indent=2, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
logger.error("保存配置文件失败: {}".format(e))
|
||||
|
||||
def run_command(self, cmd, timeout=10):
|
||||
"""执行命令"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout
|
||||
)
|
||||
return result.returncode == 0, result.stdout, result.stderr
|
||||
except subprocess.TimeoutExpired:
|
||||
return False, "", "命令执行超时"
|
||||
except Exception as e:
|
||||
return False, "", str(e)
|
||||
|
||||
def check_port_usage(self):
|
||||
"""检查端口占用情况"""
|
||||
cmd = f"ss -tlnp | grep ':{PORT} '"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if success and stdout.strip():
|
||||
# 解析进程信息
|
||||
processes = []
|
||||
for line in stdout.strip().split('\n'):
|
||||
if line:
|
||||
parts = line.split()
|
||||
if len(parts) >= 7:
|
||||
pid_info = parts[6]
|
||||
if 'pid=' in pid_info:
|
||||
pid = pid_info.split('pid=')[1].split(',')[0]
|
||||
processes.append(pid)
|
||||
|
||||
return True, processes
|
||||
else:
|
||||
return False, []
|
||||
|
||||
def check_gunicorn_process(self):
|
||||
"""检查Gunicorn进程状态"""
|
||||
if not self.pid_file.exists():
|
||||
return False, "PID文件不存在"
|
||||
|
||||
try:
|
||||
with open(self.pid_file, 'r') as f:
|
||||
pid = f.read().strip()
|
||||
|
||||
if not pid:
|
||||
return False, "PID文件为空"
|
||||
|
||||
# 检查进程是否存在
|
||||
cmd = f"ps -p {pid}"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if success and stdout.strip():
|
||||
# 检查工作进程数量
|
||||
cmd = "ps aux | grep 'gunicorn.*run_dev:app' | grep -v grep | wc -l"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
worker_count = int(stdout.strip())
|
||||
return True, f"主进程 {pid}, 工作进程 {worker_count}"
|
||||
|
||||
return False, f"进程 {pid} 不存在"
|
||||
|
||||
except Exception as e:
|
||||
return False, "检查进程失败: {}".format(e)
|
||||
|
||||
def check_service_response(self):
|
||||
"""检查服务响应"""
|
||||
cmd = f"curl -s -o /dev/null -w '%{{http_code}}' http://localhost:{PORT}/"
|
||||
success, stdout, stderr = self.run_command(cmd, timeout=self.config['port_timeout'])
|
||||
|
||||
if success and stdout.strip() == '200':
|
||||
return True, "服务正常响应"
|
||||
else:
|
||||
return False, "服务无响应 (HTTP: {})".format(stdout.strip())
|
||||
|
||||
def get_system_info(self):
|
||||
"""获取系统信息"""
|
||||
info = {}
|
||||
|
||||
# CPU使用率
|
||||
cmd = "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
info['cpu_usage'] = float(stdout.strip())
|
||||
|
||||
# 内存使用率
|
||||
cmd = "free | grep Mem | awk '{printf \"%.2f\", $3/$2 * 100.0}'"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
info['memory_usage'] = float(stdout.strip())
|
||||
|
||||
# 磁盘使用率
|
||||
cmd = "df / | tail -1 | awk '{print $5}' | sed 's/%//'"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
info['disk_usage'] = float(stdout.strip())
|
||||
|
||||
return info
|
||||
|
||||
def log_alert(self, message, level="WARNING"):
|
||||
"""记录告警信息"""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
alert_msg = f"[{timestamp}] [{level}] {message}"
|
||||
|
||||
logger.warning(alert_msg)
|
||||
|
||||
if self.config['enable_alerts']:
|
||||
try:
|
||||
with open(self.alert_file, 'a', encoding='utf-8') as f:
|
||||
f.write(alert_msg + '\n')
|
||||
except Exception as e:
|
||||
logger.error("写入告警文件失败: {}".format(e))
|
||||
|
||||
def restart_service(self):
|
||||
"""重启服务"""
|
||||
logger.info("尝试重启服务...")
|
||||
|
||||
# 停止服务
|
||||
cmd = f"cd {self.project_dir} && ./scripts/port_manager.sh stop"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if not success:
|
||||
logger.error("停止服务失败: {}".format(stderr))
|
||||
return False
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
# 启动服务
|
||||
cmd = f"cd {self.project_dir} && ./scripts/port_manager.sh start"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if not success:
|
||||
logger.error("启动服务失败: {}".format(stderr))
|
||||
return False
|
||||
|
||||
logger.info("服务重启成功")
|
||||
return True
|
||||
|
||||
def generate_report(self):
|
||||
"""生成监控报告"""
|
||||
report = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"port_usage": {},
|
||||
"gunicorn_status": {},
|
||||
"service_response": {},
|
||||
"system_info": {},
|
||||
"recommendations": []
|
||||
}
|
||||
|
||||
# 检查端口占用
|
||||
port_occupied, processes = self.check_port_usage()
|
||||
report["port_usage"] = {
|
||||
"occupied": port_occupied,
|
||||
"processes": processes
|
||||
}
|
||||
|
||||
# 检查Gunicorn进程
|
||||
gunicorn_running, status = self.check_gunicorn_process()
|
||||
report["gunicorn_status"] = {
|
||||
"running": gunicorn_running,
|
||||
"status": status
|
||||
}
|
||||
|
||||
# 检查服务响应
|
||||
service_ok, response = self.check_service_response()
|
||||
report["service_response"] = {
|
||||
"ok": service_ok,
|
||||
"response": response
|
||||
}
|
||||
|
||||
# 获取系统信息
|
||||
report["system_info"] = self.get_system_info()
|
||||
|
||||
# 生成建议
|
||||
if not port_occupied:
|
||||
report["recommendations"].append("端口未被占用,可能需要启动服务")
|
||||
|
||||
if not gunicorn_running:
|
||||
report["recommendations"].append("Gunicorn进程未运行,需要重启服务")
|
||||
|
||||
if not service_ok:
|
||||
report["recommendations"].append("服务无响应,需要检查服务状态")
|
||||
|
||||
# 检查系统资源
|
||||
sys_info = report["system_info"]
|
||||
if sys_info.get('cpu_usage', 0) > 80:
|
||||
report["recommendations"].append("CPU使用率过高,建议优化或扩容")
|
||||
|
||||
if sys_info.get('memory_usage', 0) > 90:
|
||||
report["recommendations"].append("内存使用率过高,建议增加内存或优化应用")
|
||||
|
||||
if sys_info.get('disk_usage', 0) > 85:
|
||||
report["recommendations"].append("磁盘使用率过高,建议清理日志或扩容")
|
||||
|
||||
return report
|
||||
|
||||
def monitor_loop(self):
|
||||
"""监控主循环"""
|
||||
logger.info("开始端口监控...")
|
||||
|
||||
restart_count = 0
|
||||
last_restart_time = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
# 生成报告
|
||||
report = self.generate_report()
|
||||
|
||||
# 检查是否需要重启
|
||||
need_restart = False
|
||||
|
||||
if not report["gunicorn_status"]["running"]:
|
||||
logger.warning("Gunicorn进程未运行")
|
||||
need_restart = True
|
||||
|
||||
if not report["service_response"]["ok"]:
|
||||
logger.warning("服务无响应")
|
||||
need_restart = True
|
||||
|
||||
# 执行重启
|
||||
if need_restart and self.config['auto_restart']:
|
||||
current_time = time.time()
|
||||
|
||||
# 检查重启限制
|
||||
if (current_time - last_restart_time > 300 and # 5分钟内不重复重启
|
||||
restart_count < self.config['max_restart_attempts']):
|
||||
|
||||
self.log_alert("检测到服务异常,尝试自动重启")
|
||||
|
||||
if self.restart_service():
|
||||
restart_count += 1
|
||||
last_restart_time = current_time
|
||||
else:
|
||||
self.log_alert("自动重启失败", "ERROR")
|
||||
else:
|
||||
self.log_alert("达到重启限制,跳过自动重启", "ERROR")
|
||||
|
||||
# 记录状态
|
||||
status_msg = f"端口占用: {report['port_usage']['occupied']}, " \
|
||||
f"Gunicorn: {report['gunicorn_status']['running']}, " \
|
||||
f"服务响应: {report['service_response']['ok']}"
|
||||
logger.info(status_msg)
|
||||
|
||||
# 等待下次检查
|
||||
time.sleep(self.config['check_interval'])
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("监控被用户中断")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"监控过程中发生错误: {e}")
|
||||
time.sleep(self.config['check_interval'])
|
||||
|
||||
def show_status(self):
|
||||
"""显示当前状态"""
|
||||
report = self.generate_report()
|
||||
|
||||
print("=== Flask应用监控状态 ===")
|
||||
print(f"检查时间: {report['timestamp']}")
|
||||
print()
|
||||
|
||||
print("1. 端口占用检查:")
|
||||
if report['port_usage']['occupied']:
|
||||
print(f" ✅ 端口 {PORT} 被占用")
|
||||
print(f" 进程: {', '.join(report['port_usage']['processes'])}")
|
||||
else:
|
||||
print(f" ❌ 端口 {PORT} 未被占用")
|
||||
|
||||
print()
|
||||
print("2. Gunicorn进程检查:")
|
||||
if report['gunicorn_status']['running']:
|
||||
print(f" ✅ {report['gunicorn_status']['status']}")
|
||||
else:
|
||||
print(f" ❌ {report['gunicorn_status']['status']}")
|
||||
|
||||
print()
|
||||
print("3. 服务响应检查:")
|
||||
if report['service_response']['ok']:
|
||||
print(f" ✅ {report['service_response']['response']}")
|
||||
else:
|
||||
print(f" ❌ {report['service_response']['response']}")
|
||||
|
||||
print()
|
||||
print("4. 系统资源:")
|
||||
sys_info = report['system_info']
|
||||
print(f" CPU使用率: {sys_info.get('cpu_usage', 'N/A')}%")
|
||||
print(f" 内存使用率: {sys_info.get('memory_usage', 'N/A')}%")
|
||||
print(f" 磁盘使用率: {sys_info.get('disk_usage', 'N/A')}%")
|
||||
|
||||
if report['recommendations']:
|
||||
print()
|
||||
print("5. 建议:")
|
||||
for i, rec in enumerate(report['recommendations'], 1):
|
||||
print(f" {i}. {rec}")
|
||||
|
||||
def main():
|
||||
monitor = PortMonitor()
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
command = sys.argv[1]
|
||||
|
||||
if command == "status":
|
||||
monitor.show_status()
|
||||
elif command == "report":
|
||||
report = monitor.generate_report()
|
||||
print(json.dumps(report, indent=2, ensure_ascii=False))
|
||||
elif command == "restart":
|
||||
monitor.restart_service()
|
||||
elif command == "monitor":
|
||||
monitor.monitor_loop()
|
||||
elif command == "config":
|
||||
print(json.dumps(monitor.config, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print("用法: python port_monitor.py [status|report|restart|monitor|config]")
|
||||
else:
|
||||
monitor.monitor_loop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user