#!/bin/bash # 状态检查脚本 - 检查应用运行状态(优化版) # 作者: Qwen Assistant # 功能: 检查应用运行状态、系统资源使用情况、日志分析 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # 打印带颜色的消息 print_message() { local color=$1 local message=$2 echo -e "${color}${message}${NC}" } # 日志记录函数 log_message() { local level=$1 local message=$2 local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] [$level] $message" | tee -a "status.log" } print_message $BLUE "🔍 WordMaster Pro 系统状态检查 (优化版)" echo "==============================================" # 记录状态检查 log_message "INFO" "开始系统状态检查" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # 加载环境变量 if [ -f ".env" ]; then export $(grep -v '^#' .env | xargs) BACKEND_PORT=${BACKEND_PORT:-8888} FRONTEND_PORT=${FRONTEND_PORT:-3008} else BACKEND_PORT=8888 FRONTEND_PORT=3008 fi # 显示系统信息 print_message $BLUE "🖥️ 系统信息:" print_message $CYAN " 操作系统: $(uname -s)" print_message $CYAN " 主机名: $(hostname)" print_message $CYAN " 当前时间: $(date)" echo "" # 检查系统资源 print_message $BLUE "📊 系统资源状态:" if command -v free &> /dev/null; then mem_total=$(free -m | awk 'NR==2{printf "%.1f", $2/1024}') mem_used=$(free -m | awk 'NR==2{printf "%.1f", $3/1024}') mem_available=$(free -m | awk 'NR==2{printf "%.1f", $7/1024}') mem_percent=$(free | awk 'NR==2{printf "%.1f", $3*100/$2}') print_message $CYAN " 内存: 已用 ${mem_total}GB / 总计 ${mem_total}GB (${mem_percent:-N/A}% 使用率)" print_message $CYAN " 可用内存: ${mem_available:-N/A}GB" else # 适用于 macOS 的内存检查 if command -v vm_stat &> /dev/null; then page_size=$(vm_stat | grep "page size" | awk '{print $6}' | sed 's/bytes//') free_pages=$(vm_stat | grep free | awk '{print $3}' | sed 's/\.//') inactive_pages=$(vm_stat | grep inactive | awk '{print $3}' | sed 's/\.//') free_memory=$(( (free_pages + inactive_pages) * page_size / 1024 / 1024 / 1024 )) print_message $CYAN " 可用内存 (估算): ${free_memory}GB" fi fi if command -v df &> /dev/null; then disk_usage=$(df -h . | awk 'NR==2 {print $5}' | sed 's/%//') disk_total=$(df -h . | awk 'NR==2 {print $2}') disk_used=$(df -h . | awk 'NR==2 {print $3}') disk_available=$(df -h . | awk 'NR==2 {print $4}') print_message $CYAN " 磁盘: 已用 ${disk_used} / 总计 ${disk_total} (${disk_usage:-N/A}% 使用率)" print_message $CYAN " 可用磁盘: ${disk_available}" fi # 适用于 macOS 的 CPU 检查 if command -v top &> /dev/null; then cpu_usage=$(top -l 1 | grep "CPU usage" | awk '{print $3}' | sed 's/%//' | cut -d'.' -f1) print_message $CYAN " CPU 使用率: ${cpu_usage:-N/A}%" fi echo "" # 检查后端状态 print_message $BLUE "📡 后端服务状态 (端口: $BACKEND_PORT):" if [ -f ".backend.pid" ]; then BACKEND_PID=$(cat .backend.pid) if [ ! -z "$BACKEND_PID" ] && ps -p $BACKEND_PID > /dev/null 2>&1; then print_message $GREEN " ✅ 后端进程运行中 (PID: $BACKEND_PID)" # 检查进程详细信息 backend_cpu=$(ps -p $BACKEND_PID -o %cpu --no-headers 2>/dev/null | xargs || echo "N/A") backend_mem=$(ps -p $BACKEND_PID -o %mem --no-headers 2>/dev/null | xargs || echo "N/A") print_message $CYAN " CPU使用率: ${backend_cpu}%, 内存使用率: ${backend_mem}%" # 尝试访问API文档 if curl -s --max-time 10 "http://localhost:$BACKEND_PORT/docs" > /dev/null 2>&1; then print_message $GREEN " ✅ API服务可访问" else print_message $YELLOW " ⚠️ API服务可能未就绪" fi # 检查端口监听状态 if lsof -i :$BACKEND_PORT > /dev/null 2>&1; then print_message $GREEN " ✅ 端口 $BACKEND_PORT 正在监听" else print_message $RED " ❌ 端口 $BACKEND_PORT 未监听" fi else print_message $RED " ❌ 后端进程未运行 (PID: $BACKEND_PID)" fi else print_message $RED " ❌ 后端进程未启动" # 查找可能的后端进程 possible_pids=$(pgrep -f "uvicorn.*main:app" 2>/dev/null || echo "") if [ ! -z "$possible_pids" ]; then print_message $YELLOW " ⚠️ 检测到可能的后端进程: $possible_pids (但没有 PID 文件)" fi fi echo "" # 检查前端状态 print_message $BLUE "🎨 前端服务状态 (端口: $FRONTEND_PORT):" if [ -f ".frontend.pid" ]; then FRONTEND_PID=$(cat .frontend.pid) if [ ! -z "$FRONTEND_PID" ] && ps -p $FRONTEND_PID > /dev/null 2>&1; then print_message $GREEN " ✅ 前端进程运行中 (PID: $FRONTEND_PID)" # 检查进程详细信息 frontend_cpu=$(ps -p $FRONTEND_PID -o %cpu --no-headers 2>/dev/null | xargs || echo "N/A") frontend_mem=$(ps -p $FRONTEND_PID -o %mem --no-headers 2>/dev/null | xargs || echo "N/A") print_message $CYAN " CPU使用率: ${frontend_cpu}%, 内存使用率: ${frontend_mem}%" # 尝试访问前端 if curl -s --max-time 10 "http://localhost:$FRONTEND_PORT" > /dev/null 2>&1; then print_message $GREEN " ✅ 前端服务可访问" else print_message $YELLOW " ⚠️ 前端服务可能未就绪" fi # 检查端口监听状态 if lsof -i :$FRONTEND_PID > /dev/null 2>&1; then print_message $GREEN " ✅ 端口 $FRONTEND_PID 正在监听" else print_message $RED " ❌ 端口 $FRONTEND_PID 未监听" fi else print_message $RED " ❌ 前端进程未运行 (PID: $FRONTEND_PID)" fi else print_message $RED " ❌ 前端进程未启动" # 查找可能的前端进程 possible_pids=$(pgrep -f "vite" 2>/dev/null || echo "") if [ ! -z "$possible_pids" ]; then print_message $YELLOW " ⚠️ 检测到可能的前端进程: $possible_pids (但没有 PID 文件)" fi fi echo "" # 检查所有相关进程 print_message $BLUE "📋 系统中所有相关进程:" all_backend_pids=$(pgrep -f "uvicorn.*main:app" 2>/dev/null) all_frontend_pids=$(pgrep -f "vite" 2>/dev/null) if [ ! -z "$all_backend_pids" ]; then print_message $CYAN " 后端相关进程 (uvicorn):" for pid in $all_backend_pids; do cmd=$(ps -p $pid -o args --no-headers 2>/dev/null || echo "Unknown") print_message $CYAN " PID $pid: $cmd" done else print_message $YELLOW " 未找到后端相关进程 (uvicorn)" fi if [ ! -z "$all_frontend_pids" ]; then print_message $CYAN " 前端相关进程 (vite):" for pid in $all_frontend_pids; do cmd=$(ps -p $pid -o args --no-headers 2>/dev/null || echo "Unknown") print_message $CYAN " PID $pid: $cmd" done else print_message $YELLOW " 未找到前端相关进程 (vite)" fi echo "" # 检查网络端口状态 print_message $BLUE "🌐 网络端口状态:" print_message $CYAN " 后端端口 $BACKEND_PORT: $(if lsof -i :$BACKEND_PORT > /dev/null 2>&1; then echo "✅ 监听中"; else echo "❌ 未监听"; fi)" print_message $CYAN " 前端端口 $FRONTEND_PORT: $(if lsof -i :$FRONTEND_PORT > /dev/null 2>&1; then echo "✅ 监听中"; else echo "❌ 未监听"; fi)" echo "" # 检查日志文件 print_message $BLUE "📋 日志文件信息:" log_files=("backend.log" "frontend.log" "startup.log" "stop.log" "status.log") for log_file in "${log_files[@]}"; do if [ -f "$log_file" ]; then log_size=$(du -h "$log_file" 2>/dev/null | cut -f1 || echo "N/A") log_lines=$(wc -l < "$log_file" 2>/dev/null || echo "0") print_message $CYAN " $log_file: $log_size ($log_lines 行)" # 显示最后5行日志 if [ $log_lines -gt 0 ]; then print_message $CYAN " 最后5行日志:" tail -5 "$log_file" | sed 's/^/ /' fi else print_message $YELLOW " $log_file: 不存在" fi echo "" done # 检查数据库连接 (如果配置了PostgreSQL) if command -v psql &> /dev/null && [[ "$DATABASE_URL" == *"postgresql://"* ]]; then DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@//p' | cut -d':' -f1) DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*://p' | cut -d'/' -f1) print_message $BLUE "🗄️ PostgreSQL 数据库状态 (Host: $DB_HOST, Port: $DB_PORT):" if [ "$DB_HOST" == "localhost" ] || [ "$DB_HOST" == "127.0.0.1" ]; then if lsof -i :$DB_PORT | grep LISTEN > /dev/null 2>&1; then print_message $GREEN " ✅ PostgreSQL 服务运行正常" # 尝试连接数据库 if echo "SELECT 1;" | psql "$DATABASE_URL" -tA > /dev/null 2>&1; then print_message $GREEN " ✅ 数据库连接正常" else print_message $RED " ❌ 数据库连接失败" fi else print_message $YELLOW " ⚠️ PostgreSQL 服务未运行" fi else print_message $GREEN " ✅ 数据库配置: $DATABASE_URL" fi elif [[ "$DATABASE_URL" == *"sqlite://"* ]]; then DB_PATH=$(echo $DATABASE_URL | sed 's/sqlite:\/\///') print_message $BLUE "🗄️ SQLite 数据库状态:" if [ -f "$DB_PATH" ]; then db_size=$(du -h "$DB_PATH" 2>/dev/null | cut -f1 || echo "N/A") print_message $GREEN " ✅ SQLite 数据库文件存在: $DB_PATH ($db_size)" else print_message $YELLOW " ⚠️ SQLite 数据库文件不存在: $DB_PATH" fi fi echo "" # 端口检查(检查是否其他应用占用预期端口) print_message $BLUE "🔍 检查端口占用情况:" occupied_ports=() if lsof -i :$BACKEND_PORT > /dev/null 2>&1; then port_user=$(lsof -i :$BACKEND_PORT | tail -n +2 | head -n 1 | awk '{print $1}') port_pid=$(lsof -i :$BACKEND_PORT | tail -n +2 | head -n 1 | awk '{print $2}') print_message $YELLOW " ⚠️ 后端端口 $BACKEND_PORT 被进程 $port_pid ($port_user) 占用" occupied_ports+=("$BACKEND_PORT") fi if lsof -i :$FRONTEND_PORT > /dev/null 2>&1; then port_user=$(lsof -i :$FRONTEND_PORT | tail -n +2 | head -n 1 | awk '{print $1}') port_pid=$(lsof -i :$FRONTEND_PORT | tail -n +2 | head -n 1 | awk '{print $2}') print_message $YELLOW " ⚠️ 前端端口 $FRONTEND_PORT 被进程 $port_pid ($port_user) 占用" occupied_ports+=("$FRONTEND_PORT") fi if [ ${#occupied_ports[@]} -eq 0 ]; then print_message $GREEN " ✅ 无端口冲突" else print_message $YELLOW " 提示: 如需使用这些端口,请先停止占用进程" fi echo "" # 服务健康度评分 print_message $BLUE "💯 服务健康度评估:" score=0 total_checks=0 # 检查后端 total_checks=$((total_checks + 1)) if [ -f ".backend.pid" ] && ps -p $(cat .backend.pid) > /dev/null 2>&1; then if curl -s --max-time 5 "http://localhost:$BACKEND_PORT/docs" > /dev/null 2>&1; then score=$((score + 1)) fi fi # 检查前端 total_checks=$((total_checks + 1)) if [ -f ".frontend.pid" ] && ps -p $(cat .frontend.pid) > /dev/null 2>&1; then if curl -s --max-time 5 "http://localhost:$FRONTEND_PORT" > /dev/null 2>&1; then score=$((score + 1)) fi fi # 计算健康度百分比 health_percentage=$((score * 100 / total_checks)) health_status="" if [ $health_percentage -ge 80 ]; then health_status="✅ 健康" print_message $GREEN " $health_status: ${health_percentage}% ($score/$total_checks)" elif [ $health_percentage -ge 50 ]; then health_status="⚠️ 部分正常" print_message $YELLOW " $health_status: ${health_percentage}% ($score/$total_checks)" else health_status="❌ 不健康" print_message $RED " $health_status: ${health_percentage}% ($score/$total_checks)" fi echo "" print_message $GREEN "🎉 状态检查完成!" log_message "INFO" "系统状态检查完成,健康度: ${health_percentage}%"