Files
Work-configuration-file/proc_monitor.sh
2025-10-24 18:18:40 +08:00

152 lines
4.2 KiB
Bash

#!/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"