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