feat: 添加进程监控脚本 proc_monitor.sh
- 监控指定进程名或 PID - 每 10 秒检测一次(可配置) - 进程消失时执行指定命令 - 支持日志记录和后台守护模式
This commit is contained in:
@@ -28,7 +28,7 @@ tools/
|
||||
|
||||
| 名称 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| - | - | 待添加 |
|
||||
| proc_monitor.sh | scripts/proc_monitor.sh | 进程监控脚本,进程消失时执行指定命令 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
240
scripts/proc_monitor.sh
Executable file
240
scripts/proc_monitor.sh
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# 进程监控脚本
|
||||
# 监控指定进程,当进程消失时执行指定命令
|
||||
#
|
||||
# 用法:
|
||||
# ./proc_monitor.sh -p <进程名> -c "<命令>" [-i 10] [-l /path/to/log]
|
||||
# ./proc_monitor.sh --pid <PID> -c "<命令>" [-i 10] [-l /path/to/log]
|
||||
#
|
||||
# 参数:
|
||||
# -p, --process 要监控的进程名
|
||||
# --pid 要监控的进程 PID
|
||||
# -c, --command 进程消失后要执行的命令(必填)
|
||||
# -i, --interval 检测间隔(秒,默认 10)
|
||||
# -l, --log 日志文件路径(可选)
|
||||
# -d, --daemon 后台运行模式
|
||||
# -h, --help 显示帮助
|
||||
#
|
||||
# 示例:
|
||||
# ./proc_monitor.sh -p "myapp" -c "systemctl restart myapp" -i 10
|
||||
# ./proc_monitor.sh --pid 1234 -c "echo 'Process died' >> /tmp/alert.log" -d
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# 默认配置
|
||||
INTERVAL=10
|
||||
LOG_FILE=""
|
||||
DAEMON_MODE=false
|
||||
PROCESS_NAME=""
|
||||
TARGET_PID=""
|
||||
EXEC_COMMAND=""
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
||||
echo -e "$msg"
|
||||
if [[ -n "$LOG_FILE" ]]; then
|
||||
echo -e "$msg" >> "$LOG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
log_info() {
|
||||
log "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
log "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
log "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 显示帮助
|
||||
show_help() {
|
||||
sed -n '/^# ==/,/^# ==/p' "$0" | sed 's/^# //' | sed 's/^#//'
|
||||
}
|
||||
|
||||
# 解析参数
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-p|--process)
|
||||
PROCESS_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--pid)
|
||||
TARGET_PID="$2"
|
||||
shift 2
|
||||
;;
|
||||
-c|--command)
|
||||
EXEC_COMMAND="$2"
|
||||
shift 2
|
||||
;;
|
||||
-i|--interval)
|
||||
INTERVAL="$2"
|
||||
shift 2
|
||||
;;
|
||||
-l|--log)
|
||||
LOG_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-d|--daemon)
|
||||
DAEMON_MODE=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "未知参数: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 验证参数
|
||||
validate_args() {
|
||||
if [[ -z "$PROCESS_NAME" && -z "$TARGET_PID" ]]; then
|
||||
log_error "必须指定进程名 (-p) 或 PID (--pid)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "$PROCESS_NAME" && -n "$TARGET_PID" ]]; then
|
||||
log_error "不能同时指定进程名和 PID,请二选一"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$EXEC_COMMAND" ]]; then
|
||||
log_error "必须指定要执行的命令 (-c)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$INTERVAL" =~ ^[0-9]+$ ]] || [[ "$INTERVAL" -lt 1 ]]; then
|
||||
log_error "检测间隔必须是正整数(秒)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查进程是否存在
|
||||
check_process() {
|
||||
if [[ -n "$TARGET_PID" ]]; then
|
||||
# 通过 PID 检查
|
||||
kill -0 "$TARGET_PID" 2>/dev/null
|
||||
else
|
||||
# 通过进程名检查
|
||||
pgrep -x "$PROCESS_NAME" >/dev/null 2>&1 || \
|
||||
pgrep -f "$PROCESS_NAME" >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取进程信息
|
||||
get_process_info() {
|
||||
if [[ -n "$TARGET_PID" ]]; then
|
||||
echo "PID: $TARGET_PID"
|
||||
else
|
||||
local pid
|
||||
pid=$(pgrep -x "$PROCESS_NAME" 2>/dev/null | head -1 || \
|
||||
pgrep -f "$PROCESS_NAME" 2>/dev/null | head -1 || echo "unknown")
|
||||
echo "进程名: $PROCESS_NAME (PID: $pid)"
|
||||
fi
|
||||
}
|
||||
|
||||
# 监控循环
|
||||
monitor() {
|
||||
log_info "开始监控 $(get_process_info)"
|
||||
log_info "检测间隔: ${INTERVAL}秒"
|
||||
log_info "触发命令: $EXEC_COMMAND"
|
||||
log_info "按 Ctrl+C 停止监控"
|
||||
echo "---"
|
||||
|
||||
local check_count=0
|
||||
local start_time
|
||||
start_time=$(date +%s)
|
||||
|
||||
while true; do
|
||||
check_count=$((check_count + 1))
|
||||
|
||||
if ! check_process; then
|
||||
log_warn "检测到进程已消失!"
|
||||
log_info "执行命令: $EXEC_COMMAND"
|
||||
|
||||
# 执行命令并记录结果
|
||||
if eval "$EXEC_COMMAND"; then
|
||||
log_info "命令执行成功"
|
||||
else
|
||||
log_error "命令执行失败,退出码: $?"
|
||||
fi
|
||||
|
||||
# 统计信息
|
||||
local end_time
|
||||
end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
log_info "监控时长: ${duration}秒,共检测 ${check_count} 次"
|
||||
|
||||
break
|
||||
fi
|
||||
|
||||
# 每 6 次检测(约 1 分钟)输出一次存活确认
|
||||
if [[ $((check_count % 6)) -eq 0 ]]; then
|
||||
log_info "进程正常运行中... (已检测 ${check_count} 次)"
|
||||
fi
|
||||
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
}
|
||||
|
||||
# 后台运行模式
|
||||
run_daemon() {
|
||||
local script_path
|
||||
script_path=$(realpath "$0")
|
||||
local args=""
|
||||
|
||||
# 重新构建参数(去掉 -d)
|
||||
if [[ -n "$PROCESS_NAME" ]]; then
|
||||
args="-p '$PROCESS_NAME'"
|
||||
elif [[ -n "$TARGET_PID" ]]; then
|
||||
args="--pid '$TARGET_PID'"
|
||||
fi
|
||||
|
||||
args="$args -c '$EXEC_COMMAND' -i $INTERVAL"
|
||||
[[ -n "$LOG_FILE" ]] && args="$args -l '$LOG_FILE'"
|
||||
|
||||
log_info "以守护模式启动..."
|
||||
log_info "日志将输出到: ${LOG_FILE:-stdout}"
|
||||
|
||||
# 使用 nohup 后台运行
|
||||
eval "nohup bash $script_path $args >/dev/null 2>&1 &"
|
||||
|
||||
local pid=$!
|
||||
log_info "守护进程 PID: $pid"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
parse_args "$@"
|
||||
validate_args
|
||||
|
||||
if [[ "$DAEMON_MODE" == true ]]; then
|
||||
run_daemon
|
||||
else
|
||||
monitor
|
||||
fi
|
||||
}
|
||||
|
||||
# 捕获信号
|
||||
trap 'log_info "监控已停止"; exit 0' INT TERM
|
||||
|
||||
# 运行主函数
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user