提交 edea6d65 authored 作者: 陈泽健's avatar 陈泽健

refactor(AutomatedServiceMonitoring): 将监控脚本改为单次执行模式并移除ERROR分析

- 将脚本从循环监控模式改为单次执行模式
- 移除日志ERROR上下文检测功能和相关状态变量
- 简化日志审计功能,仅保留日志暴涨检测
- 更新报告输出内容,移除ERROR相关统计信息
- 优化代码结构,移除监控间隔和报告生成间隔配置
- 更新脚本头部注释说明为单次执行模式
- 移除主循环逻辑,改用简单执行流程
- 添加需求文档中容器信息检测的未实现说明
上级 ea219194
''''bash
# filepath: e:\GithubData\自动化\ubains-module-test\AuxiliaryTool\ScriptTool\自动化服务监测\AutomatedServiceMonitoring.sh
#!/usr/bin/env bash
# filepath: e:\GithubData\自动化\ubains-module-test\AuxiliaryTool\ScriptTool\自动化服务监测\AutomatedServiceMonitoring.sh
########################################
# 自动化服务监测 Shell 脚本(单机版)
# 在哪台服务器上运行,就监控哪台服务器(本机)
# 对齐《自动化服务监测需求文档》:
# 1. 平台识别
# 2. 系统识别
# 3.1 日志审计(暴涨 + ERROR 上下文)
# 3.2 内存资源消耗
# 3.3 MySQL 连接数
# 4. 监测日志审计(中文日志)
# 5. 监测报告输出(本脚本内生成 Markdown 报告)
# 自动化服务监测 Shell 脚本(单机版,单次执行)
########################################
set -u # 未定义变量直接报错
# 如需调试可打开:set -x
set -u
#################### 全局配置 ####################
# 监控间隔(秒)
INTERVAL_SECONDS=60
# 报告生成间隔(秒),例如 600 = 每 10 分钟写一份 MD 报告
REPORT_INTERVAL_SECONDS=600
# MySQL 账号(与需求文档一致)
MYSQL_USER="root"
MYSQL_PASSWORD="dNrprU&2S"
# 日志文件(监测运行过程)
LOG_FILE="./AutomatedServiceMonitoring.sh.log"
# 报告输出目录
REPORT_DIR="./monitor_reports"
# 当前主机标识
HOST_NAME="$(hostname)"
#################### 简单日志函数(✅ 中文) ####################
#################### 日志 ####################
log() {
# $1: 级别 INFO/WARN/ERROR
# $2+: 消息
local level="$1"; shift
local ts
ts="$(date '+%Y-%m-%d %H:%M:%S')"
......@@ -51,7 +25,7 @@ log() {
echo "$msg" >>"$LOG_FILE"
}
#################### 1. 平台识别(✅ 已实现) ####################
#################### 1. 平台识别 ####################
detect_platform() {
if [ -d "/data/services" ]; then
PLATFORM_TYPE="new"
......@@ -62,12 +36,12 @@ detect_platform() {
fi
}
#################### 2. 系统识别(✅ 已实现) ####################
#################### 2. 系统识别 ####################
detect_systems() {
HAS_UJAVA=0
HAS_UPYTHON=0
HAS_UPYTHON_VOICE=0
SYSTEMS=() # meeting / ops / transcription
SYSTEMS=()
local names
names="$(docker ps --format '{{.Names}}' 2>/dev/null || true)"
......@@ -86,8 +60,7 @@ detect_systems() {
fi
}
#################### 3.1 日志审计(✅ 已实现) ####################
# 目标解析(只按照文档里的预定系统日志)
#################### 3.1 日志审计(只保留暴涨,不做 ERROR 分析) ####################
resolve_log_targets() {
LOG_TARGET_SYS=()
LOG_TARGET_PATH=()
......@@ -113,26 +86,17 @@ resolve_log_targets() {
fi
}
# ========= 日志暴涨与 ERROR 审计的状态,供报告使用 =========
# 暴涨状态:key = "sys_name|path"
declare -A BURST_LAST_TOTAL
declare -A BURST_LAST_TS
declare -A BURST_LAST_RESULT # 最近一次判定结果:OK / BURST
declare -A BURST_LAST_DESC # 最近一次描述(窗口/增量/速率/时间段)
# ERROR 状态:key = "sys_name|path"
declare -A ERROR_LAST_COUNT
declare -A ERROR_LAST_TIME_RANGE # "start ~ end"
declare -A BURST_LAST_RESULT
declare -A BURST_LAST_DESC
# 工具函数:构造 key
make_log_key() {
local sys_name="$1"
local log_path="$2"
echo "${sys_name}|${log_path}"
}
# 3.1.1 日志暴涨检测(窗口增量法)
monitor_log_burst_once() {
local sys_name="$1"
local log_path="$2"
......@@ -151,10 +115,9 @@ monitor_log_burst_once() {
return
fi
local out
out="$(wc -l < "$log_path" 2>/dev/null || echo 0)"
local total_lines
total_lines=$(echo "$out" | tr -d ' ')
total_lines="$(wc -l < "$log_path" 2>/dev/null || echo 0)"
total_lines=$(echo "$total_lines" | tr -d ' ')
if ! [[ "$total_lines" =~ ^[0-9]+$ ]]; then
log INFO "[日志暴涨审计] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path 无法获取总行数"
......@@ -179,10 +142,10 @@ monitor_log_burst_once() {
fi
local elapsed=$(( now_ts - last_ts ))
if (( elapsed <= 0 )); then elapsed=1; fi
(( elapsed <= 0 )) && elapsed=1
local delta_lines=$(( total_lines - last_total ))
if (( delta_lines < 0 )); then delta_lines=0; fi
(( delta_lines < 0 )) && delta_lines=0
BURST_LAST_TOTAL["$key"]="$total_lines"
BURST_LAST_TS["$key"]="$now_ts"
......@@ -199,7 +162,7 @@ monitor_log_burst_once() {
local start_ts_human end_ts_human
start_ts_human="$(date -d @"$last_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
end_ts_human="$(date -d @"$now_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
end_ts_human="$(date -d @"$now_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
local desc="窗口=${elapsed}s 新增行数=${delta_lines} 速率=${rate}行/秒 时间段=[${start_ts_human} ~ ${end_ts_human}]"
if (( delta_lines >= min_lines_threshold )) || awk -v r="$rate" -v th="$rate_threshold_per_sec" 'BEGIN{exit !(r>=th)}'; then
......@@ -213,77 +176,7 @@ monitor_log_burst_once() {
fi
}
# 3.1.2 ERROR 上下文检测(记录 ERROR 上下 50 行的时间段)
monitor_log_errors_once() {
local sys_name="$1"
local log_path="$2"
local max_context=50
local max_sections=3
local key
key="$(make_log_key "$sys_name" "$log_path")"
if [ ! -f "$log_path" ]; then
log INFO "[ERROR审计] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path 文件不存在"
ERROR_LAST_COUNT["$key"]=0
ERROR_LAST_TIME_RANGE["$key"]="日志文件不存在"
return
fi
local tail_out
tail_out="$(tail -n 5000 "$log_path" 2>/dev/null || true)"
if [[ -z "${tail_out//[[:space:]]/}" ]]; then
log INFO "[ERROR审计] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path 最近5000行无内容"
ERROR_LAST_COUNT["$key"]=0
ERROR_LAST_TIME_RANGE["$key"]="最近5000行无内容"
return
fi
local cnt
cnt="$(echo "$tail_out" | grep -c "ERROR" || true)"
if ! [[ "$cnt" =~ ^[0-9]+$ ]]; then
cnt=0
fi
if (( cnt == 0 )); then
log INFO "[ERROR审计] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path 最近段落未发现 ERROR"
ERROR_LAST_COUNT["$key"]=0
ERROR_LAST_TIME_RANGE["$key"]="未发现 ERROR"
return
fi
local ctx
ctx="$(echo "$tail_out" | nl -ba | \
awk '{if($0 ~ /ERROR/) print $1}' | tail -n "$max_sections" | \
while read -r ln; do
start=$((ln - max_context)); end=$((ln + max_context))
if [ "$start" -lt 1 ]; then start=1; fi
echo "$tail_out" | sed -n "${start},${end}p"
echo
echo "---- 上下文分隔线 (行号: $ln) ----"
echo
done
)"
local start_ts end_ts
start_ts="$(echo "$ctx" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' | head -n1)"
end_ts="$(echo "$ctx" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' | tail -n1)"
if [[ -n "$start_ts" || -n "$end_ts" ]]; then
log WARN "[ERROR出现] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path 最近5000行 ERROR数量=$cnt 发生时间段=[$start_ts ~ $end_ts]"
ERROR_LAST_TIME_RANGE["$key"]="${start_ts} ~ ${end_ts}"
else
log WARN "[ERROR出现] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path 最近5000行 ERROR数量=$cnt"
ERROR_LAST_TIME_RANGE["$key"]="时间戳未解析成功"
fi
ERROR_LAST_COUNT["$key"]="$cnt"
log INFO "[ERROR上下文] 主机=$HOST_NAME 系统=$sys_name 日志=$log_path
$ctx"
}
#################### 3.2 内存资源消耗(✅ 已实现) ####################
#################### 3.2 内存 ####################
MEM_SAMPLES=0
MEM_SUM_USED_MB=0
MEM_PEAK_USED_MB=0
......@@ -311,7 +204,6 @@ monitor_mem_once() {
used_mb=$(awk -v t="$total_kb" -v a="$avail_kb" 'BEGIN{u=(t-a)/1024; if(u<0)u=0; printf "%.0f",u}')
MEM_LAST_USED_MB="$used_mb"
MEM_SAMPLES=$((MEM_SAMPLES + 1))
MEM_SUM_USED_MB=$((MEM_SUM_USED_MB + used_mb))
if (( used_mb > MEM_PEAK_USED_MB )); then
......@@ -319,18 +211,16 @@ monitor_mem_once() {
MEM_PEAK_TS="$(date +%s)"
fi
local avg_used
avg_used=$(( MEM_SUM_USED_MB / MEM_SAMPLES ))
local avg_used=$(( MEM_SUM_USED_MB / MEM_SAMPLES ))
local peak_human="N/A"
if [[ "$MEM_PEAK_TS" != "0" && -n "$MEM_PEAK_TS" ]]; then
peak_human="$(date -d @"$MEM_PEAK_TS" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
fi
log INFO "[内存监测] $HOST_NAME 当前使用=${used_mb}MB 总=${total_mb}MB 平均=${avg_used}MB 峰值=${MEM_PEAK_USED_MB}MB@$peak_human"
log INFO "[内存监测] $HOST_NAME 当前使用=${used_mb}MB 平均=${avg_used}MB 峰值=${MEM_PEAK_USED_MB}MB@$peak_human"
}
#################### 3.3 MySQL 连接数(✅ 已实现) ####################
#################### 3.3 MySQL ####################
MYSQL_SAMPLES=0
MYSQL_SUM_CONN=0
MYSQL_PEAK_CONN=0
......@@ -423,15 +313,13 @@ monitor_mysql_once() {
MYSQL_PEAK_TS="$now_ts"
fi
local avg_conn
avg_conn=$(( MYSQL_SUM_CONN / MYSQL_SAMPLES ))
local avg_conn=$(( MYSQL_SUM_CONN / MYSQL_SAMPLES ))
local peak_human="N/A"
if [[ -n "$MYSQL_PEAK_TS" && "$MYSQL_PEAK_TS" != "0" ]]; then
peak_human="$(date -d @"$MYSQL_PEAK_TS" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
fi
log INFO "[MySQL监测] $HOST_NAME 当前连接数=$conn 平均=$avg_conn 峰值=${MYSQL_PEAK_CONN}@$peak_human"
log INFO "[MySQL监测] $HOST_NAME 当前连接数=$conn 平均=${avg_conn} 峰值=${MYSQL_PEAK_CONN}@$peak_human"
local window_seconds=300
local min_burst_conn=200
......@@ -446,9 +334,9 @@ monitor_mysql_once() {
fi
local elapsed=$(( now_ts - MYSQL_LAST_TS ))
if (( elapsed <= 0 )); then elapsed=1; fi
(( elapsed <= 0 )) && elapsed=1
local delta_conn=$(( conn - MYSQL_LAST_TOTAL ))
if (( delta_conn < 0 )); then delta_conn=0; fi
(( delta_conn < 0 )) && delta_conn=0
MYSQL_LAST_TOTAL="$conn"
MYSQL_LAST_TS="$now_ts"
......@@ -458,7 +346,7 @@ monitor_mysql_once() {
rate=$(awk -v d="$delta_conn" -v e="$elapsed" 'BEGIN{ if(e<=0){e=1}; printf "%.2f", d/e }')
local start_ts_human end_ts_human
start_ts_human="$(date -d @"$((now_ts - elapsed))" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
end_ts_human="$(date -d @"$now_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
end_ts_human="$(date -d @"$now_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
local desc="窗口=${elapsed}s 增量=${delta_conn} 速率=${rate}/s 时间段=[${start_ts_human} ~ ${end_ts_human}]"
if (( delta_conn >= min_burst_conn )) || awk -v r="$rate" -v th="$rate_threshold_per_sec" 'BEGIN{exit !(r>=th)}'; then
......@@ -476,8 +364,7 @@ monitor_mysql_once() {
fi
}
#################### 5. 监测报告输出(md 文件) ####################
#################### 5. 报告输出(md) ####################
write_md_report() {
mkdir -p "$REPORT_DIR" 2>/dev/null || true
......@@ -494,23 +381,19 @@ write_md_report() {
fi
local systems_text="无"
if ((${#SYSTEMS[@]} > 0)); then
systems_text="${SYSTEMS[*]}"
fi
((${#SYSTEMS[@]} > 0)) && systems_text="${SYSTEMS[*]}"
local mem_avg_used="N/A"
if (( MEM_SAMPLES > 0 )); then
mem_avg_used=$(( MEM_SUM_USED_MB / MEM_SAMPLES ))
fi
(( MEM_SAMPLES > 0 )) && mem_avg_used=$(( MEM_SUM_USED_MB / MEM_SAMPLES ))
local mem_peak_time="N/A"
if [[ "$MEM_PEAK_TS" != "0" && -n "$MEM_PEAK_TS" ]]; then
mem_peak_time="$(date -d @"$MEM_PEAK_TS" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
fi
local mysql_avg_conn="N/A"
if (( MYSQL_SAMPLES > 0 )); then
mysql_avg_conn=$(( MYSQL_SUM_CONN / MYSQL_SAMPLES ))
fi
(( MYSQL_SAMPLES > 0 )) && mysql_avg_conn=$(( MYSQL_SUM_CONN / MYSQL_SAMPLES ))
local mysql_peak_time="N/A"
if [[ -n "$MYSQL_PEAK_TS" && "$MYSQL_PEAK_TS" != "0" ]]; then
mysql_peak_time="$(date -d @"$MYSQL_PEAK_TS" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
......@@ -525,9 +408,8 @@ write_md_report() {
echo "- 系统识别:ujava=${HAS_UJAVA},upython=${HAS_UPYTHON},upython_voice=${HAS_UPYTHON_VOICE}"
echo "- 系统列表:${systems_text}"
echo
echo "## 一、日志审计概览"
echo "## 一、日志审计概览(仅暴涨情况,不含 ERROR 详情)"
echo
resolve_log_targets
if ((${#LOG_TARGET_SYS[@]} == 0)); then
echo "- 当前未匹配到需要审计的日志目标(例如未识别到会议预定系统 ujava 容器)。"
else
......@@ -539,16 +421,12 @@ write_md_report() {
local burst_status="${BURST_LAST_RESULT[$key]-未采集}"
local burst_desc="${BURST_LAST_DESC[$key]-无}"
local err_cnt="${ERROR_LAST_COUNT[$key]-0}"
local err_range="${ERROR_LAST_TIME_RANGE[$key]-无}"
echo "### 日志:${sys_name}"
echo
echo "- 日志路径:\`${log_path}\`"
echo "- 日志暴涨状态:**${burst_status}**"
echo "- 日志暴涨详情:${burst_desc}"
echo "- 最近 ERROR 数量:**${err_cnt}**"
echo "- 最近 ERROR 时间段:${err_range}"
echo
done
fi
......@@ -569,55 +447,45 @@ write_md_report() {
echo "- 最近暴涨判定状态:**${MYSQL_LAST_BURST_STATUS}**"
echo "- 暴涨详情:${MYSQL_LAST_BURST_DESC}"
echo
echo "> 说明:本报告由 \`AutomatedServiceMonitoring.sh\` 自动生成,仅反映最近一段时间的监测结果。"
echo "> 说明:本报告由 \`AutomatedServiceMonitoring.sh\` 自动生成,仅反映本次执行时刻的监测结果(当前版本未启用 ERROR 上下文分析)。"
echo
} > "$report_file"
log INFO "[报告输出] 已生成监测报告:${report_file}"
}
#################### 主循环:监控本机 ####################
main_loop() {
log INFO "[启动] 自动化服务监测 Shell 脚本,目标服务器(本机)=${HOST_NAME}"
#################### 主流程:单次执行 ####################
main_run_once() {
log INFO "[启动] 自动化服务监测 Shell 脚本(单次执行模式),目标服务器(本机)=${HOST_NAME}"
detect_platform
detect_systems
log INFO "[平台识别] $HOST_NAME => 平台类型=$([[ "$PLATFORM_TYPE" == "new" ]] && echo 新统一平台(/data/services) || echo 传统平台(/var/www)) 基路径=${BASE_PATH}"
local platform_text
if [[ "$PLATFORM_TYPE" == "new" ]]; then
platform_text="新统一平台(/data/services)"
else
platform_text="传统平台(/var/www)"
fi
log INFO "[平台识别] $HOST_NAME => 平台类型=${platform_text} 基路径=${BASE_PATH}"
log INFO "[系统识别] $HOST_NAME => ujava=${HAS_UJAVA} upython=${HAS_UPYTHON} upython_voice=${HAS_UPYTHON_VOICE} 系统=(${SYSTEMS[*]:-})"
local last_report_ts
last_report_ts="$(date +%s)"
while true; do
log INFO "[心跳] $HOST_NAME: 平台=$([[ "$PLATFORM_TYPE" == "new" ]] && echo || echo ) 基路径=${BASE_PATH} 系统=${SYSTEMS[*]:-}"
# 日志审计
resolve_log_targets
for ((i=0; i<${#LOG_TARGET_SYS[@]}; i++)); do
local sys_name="${LOG_TARGET_SYS[$i]}"
local log_path="${LOG_TARGET_PATH[$i]}"
monitor_log_burst_once "$sys_name" "$log_path"
monitor_log_errors_once "$sys_name" "$log_path"
done
# 内存监测
monitor_mem_once
# MySQL 监测
monitor_mysql_once
# 报告输出节奏控制
local now_ts
now_ts="$(date +%s)"
local elapsed=$(( now_ts - last_report_ts ))
if (( elapsed >= REPORT_INTERVAL_SECONDS )); then
write_md_report
last_report_ts="$now_ts"
fi
log INFO "[心跳] $HOST_NAME: 平台=$([[ "$PLATFORM_TYPE" == "new" ]] && echo || echo ) 基路径=${BASE_PATH} 系统=${SYSTEMS[*]:-}"
sleep "$INTERVAL_SECONDS"
resolve_log_targets
for ((i=0; i<${#LOG_TARGET_SYS[@]}; i++)); do
local sys_name="${LOG_TARGET_SYS[$i]}"
local log_path="${LOG_TARGET_PATH[$i]}"
monitor_log_burst_once "$sys_name" "$log_path"
done
monitor_mem_once
monitor_mysql_once
write_md_report
log INFO "[结束] 本次监测已完成,报告已生成。"
}
#################### 脚本入口 ####################
main_loop
\ No newline at end of file
main_run_once
\ No newline at end of file
......@@ -58,6 +58,8 @@
先检查mysql容器名称,然后通过进入mysql容器内部进行查询,mysql账号为root,密码为dNrprU&2S
3.4、emqx连接数(未实现):
根据平台类型持续监测EMQX连接数量峰值、平均值,以及是否存在暴涨情况,或是判断一直没断开的异常连接。
3.5、容器信息检测(未实现):
针对当前服务器上存在的运行和未运行的容器进行查询检测,分别记录运行的容器信息和未运行的容器信息。
##### 4、监测日志审计(✅ 已实现):
需要丰富日志体系,日志需要用中文打印
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论