#!/bin/bash # 优化版:监控 gunicorn 主进程及其子进程资源变化(表格+彩色输出) PROC_NAME="gunicorn" LOG_DIR="/data/sh/monitor/logs" LOG_FILE="$LOG_DIR/proc_monitor.log" DATA_FILE="$LOG_DIR/last_snapshot.txt" mkdir -p "$LOG_DIR" # 颜色定义 RED='\033[1;31m' GREEN='\033[1;32m' YELLOW='\033[1;33m' BLUE='\033[1;34m' NC='\033[0m' # 无色 # 获取系统内存概况 get_sys_mem() { free -h | awk '/Mem:/ {printf "系统内存概况:总 %s | 已用 %s | 空闲 %s | 可用 %s", $2, $3, $4, $7}' } # 获取时间 format_time() { date "+%Y-%m-%d %H:%M:%S" } # 获取 gunicorn 主进程和子进程信息 get_proc_info() { ps -eo pid,ppid,comm,%mem,%cpu,rss --no-headers | awk -v pname="$PROC_NAME" '$3 == pname {print $1, $2, $3, $4, $5, $6}' } # 保存当前状态快照 save_snapshot() { get_proc_info | awk '{print $1,$3,$4,$5}' > "$DATA_FILE" } # 打印表格头 print_table_header() { printf "%-10s %-12s %-12s %-12s %-12s\n" "PID" "进程名" "内存(Gi)" "CPU(%)" "备注" } # 打印分隔线 print_line() { printf "%s\n" "---------------------------------------------------------------" } # 获取主进程 PID MAIN_PID=$(pgrep -f "$PROC_NAME" | head -n 1) if [ -z "$MAIN_PID" ]; then echo -e "${RED}未找到进程:$PROC_NAME${NC}" exit 1 fi TIMESTAMP=$(format_time) echo "==== $TIMESTAMP ====" >> "$LOG_FILE" echo "$(get_sys_mem)" >> "$LOG_FILE" echo "主进程名:$PROC_NAME | PID: $MAIN_PID" >> "$LOG_FILE" # 写表格头 print_table_header >> "$LOG_FILE" print_line >> "$LOG_FILE" # 获取当前进程信息 CUR_INFO=$(get_proc_info) echo "$CUR_INFO" | while read -r pid ppid name mem cpu rss; do mem_gi=$(awk "BEGIN {printf \"%.2f\", $rss/1024/1024}") # KB -> Gi printf "%-10s %-12s %-12s %-12s\n" "$pid" "$name" "${mem_gi}Gi" "${cpu}%" >> "$LOG_FILE" done print_line >> "$LOG_FILE" # 若无上次记录,跳过变化分析 if [ ! -f "$DATA_FILE" ]; then echo "暂无上次记录,跳过变化分析。" >> "$LOG_FILE" save_snapshot echo "==== $TIMESTAMP ====" >> "$LOG_FILE" exit 0 fi # 对比分析部分 declare -A CUR_MEM CUR_CPU PRE_MEM PRE_CPU while read -r pid name mem cpu; do CUR_MEM["$pid"]=$mem CUR_CPU["$pid"]=$cpu done < <(get_proc_info | awk '{print $1,$3,$4,$5}') while read -r pid name mem cpu; do PRE_MEM["$pid"]=$mem PRE_CPU["$pid"]=$cpu done < "$DATA_FILE" CUR_PIDS=$(printf "%s\n" "${!CUR_MEM[@]}" | sort) PRE_PIDS=$(printf "%s\n" "${!PRE_MEM[@]}" | sort) NEW_PIDS=$(comm -23 <(echo "$CUR_PIDS") <(echo "$PRE_PIDS")) OLD_PIDS=$(comm -13 <(echo "$CUR_PIDS") <(echo "$PRE_PIDS")) echo "分析变化:" >> "$LOG_FILE" # 新旧进程分析 if [ -n "$NEW_PIDS" ]; then echo -e " ${GREEN}新出现的子进程:${NC}" >> "$LOG_FILE" for pid in $NEW_PIDS; do echo " $PROC_NAME (PID:$pid)" >> "$LOG_FILE" done fi if [ -n "$OLD_PIDS" ]; then echo -e " ${YELLOW}已消失的子进程:${NC}" >> "$LOG_FILE" for pid in $OLD_PIDS; do echo " $PROC_NAME (PID:$pid)" >> "$LOG_FILE" done fi # 资源变化分析 echo " 子进程资源变化:" >> "$LOG_FILE" for pid in $CUR_PIDS; do if [ -n "${PRE_MEM[$pid]}" ]; then cpu_diff=$(awk "BEGIN {printf \"%.1f\", ${CUR_CPU[$pid]} - ${PRE_CPU[$pid]}}") mem_diff=$(awk "BEGIN {printf \"%.2f\", ${CUR_MEM[$pid]} - ${PRE_MEM[$pid]}}") color_start="" color_end="$NC" if (( $(echo "$mem_diff > 0.2" | bc -l) )); then color_start=$RED elif (( $(echo "$mem_diff < -0.2" | bc -l) )); then color_start=$GREEN else color_start=$YELLOW fi echo -e " ${color_start}$PROC_NAME (PID:$pid): CPU变化 ${cpu_diff}% | 内存变化 ${mem_diff}%${color_end}" >> "$LOG_FILE" fi done # 当前最高占用进程 top_cpu_pid=$(ps -eo pid,comm,%cpu --no-headers | grep "$PROC_NAME" | sort -k3 -nr | head -n 1 | awk '{print $1}') top_mem_pid=$(ps -eo pid,comm,%mem --no-headers | grep "$PROC_NAME" | sort -k3 -nr | head -n 1 | awk '{print $1}') if [ -n "$top_cpu_pid" ]; then echo -e " ${BLUE}当前占用最高CPU的进程:${NC} $PROC_NAME (PID:$top_cpu_pid)" >> "$LOG_FILE" fi if [ -n "$top_mem_pid" ]; then echo -e " ${BLUE}当前占用最高内存的进程:${NC} $PROC_NAME (PID:$top_mem_pid)" >> "$LOG_FILE" fi save_snapshot echo "==== $TIMESTAMP ====" >> "$LOG_FILE"