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

feat(service-monitor): 新增 10 个检测模块

系统检测(5 个):
- 05_oom_check: OOM 和内核异常检测
- 06_process_check: 进程检测
- 07_network_check: 网络检测
- 11_scheduled_tasks: 计划任务检测
- 12_port_check: 端口检测

服务深度检测(3 个):
- 21_docker_deep: Docker 深度检测
- 23_mysql_depth: MySQL 深度检测
- 25_redis_depth: Redis 深度检测

业务容器监测(2 个):
- 37_ustorage_check: UStorage 容器监测
- 38_utracker_check: UTracker 容器监测

- check_modules.py: ALL_MODULES 从 7→17 个
- display_names.py: 新增 ~150 个 KEY 中文显示名
- config.sh.template: 新增 ustorge/utracker 容器匹配模式
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 b0b61d2e
...@@ -21,6 +21,8 @@ CONTAINERS[nginx]="nginx" ...@@ -21,6 +21,8 @@ CONTAINERS[nginx]="nginx"
CONTAINERS[nacos]="nacos" CONTAINERS[nacos]="nacos"
CONTAINERS[python]="python" CONTAINERS[python]="python"
CONTAINERS[python_voice]="python_voice" CONTAINERS[python_voice]="python_voice"
CONTAINERS[ustorage]="ustorage|storage"
CONTAINERS[utracker]="utracker|tracker"
# ==================== 凭据(占位符,渲染时注入;值由 Python 端做 shell 安全引用) ==================== # ==================== 凭据(占位符,渲染时注入;值由 Python 端做 shell 安全引用) ====================
MYSQL_PASSWORD=__MYSQL_PASSWORD__ MYSQL_PASSWORD=__MYSQL_PASSWORD__
......
#!/bin/bash
# Redis深度检测脚本
# 使用方法: ./redis_depth_check.sh
REDIS_PASSWORD="dNrprU&2S"
CONTAINER="uredis"
# 基础信息
REDIS_VERSION=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO server 2>&1 | grep redis_version | cut -d: -f2 | tr -d '\r')
if [ -n "$REDIS_VERSION" ]; then
echo "REDIS_VERSION:$REDIS_VERSION"
else
echo "REDIS_VERSION:N/A"
fi
# 运行时间(天)
UPTIME_DAYS=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO server 2>&1 | grep uptime_in_days | cut -d: -f2 | tr -d '\r')
if [ -n "$UPTIME_DAYS" ]; then
echo "UPTIME_DAYS:$UPTIME_DAYS"
else
echo "UPTIME_DAYS:N/A"
fi
# 键数量
KEY_COUNT=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" DBSIZE 2>&1 | grep -v "Warning")
if [ -n "$KEY_COUNT" ] && [[ "$KEY_COUNT" =~ ^[0-9]+$ ]]; then
echo "KEY_COUNT:$KEY_COUNT"
else
echo "KEY_COUNT:0"
fi
# 内存使用
MEMORY_INFO=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO memory 2>&1 | grep -E "used_memory_human:|mem_fragmentation_ratio:" | tr -d '\r' | tr '\n' '|' | sed 's/|$//')
if [ -n "$MEMORY_INFO" ]; then
echo "MEMORY_INFO:$MEMORY_INFO"
else
echo "MEMORY_INFO:N/A"
fi
# 客户端连接数
CLIENT_COUNT=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO clients 2>&1 | grep connected_clients | cut -d: -f2 | tr -d '\r')
if [ -n "$CLIENT_COUNT" ]; then
echo "CLIENT_COUNT:$CLIENT_COUNT"
else
echo "CLIENT_COUNT:0"
fi
# ========== 高优先级功能补充 ==========
# Keyspace信息(各数据库键和过期键统计)
KEYSPACE_INFO=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO keyspace 2>&1 | grep -v "Warning" | grep "^db" | tr -d '\r')
if [ -n "$KEYSPACE_INFO" ]; then
TOTAL_KEYS=0
TOTAL_EXPIRES=0
while IFS=: read -r db_key info; do
if [[ "$info" =~ keys=([0-9]+) ]]; then
keys=${BASH_REMATCH[1]}
TOTAL_KEYS=$((TOTAL_KEYS + keys))
fi
if [[ "$info" =~ expires=([0-9]+) ]]; then
expires=${BASH_REMATCH[1]}
TOTAL_EXPIRES=$((TOTAL_EXPIRES + expires))
fi
done <<< "$KEYSPACE_INFO"
echo "KEYSPACE_DETAIL:Total:$TOTAL_KEYS,Expires:$TOTAL_EXPIRES"
else
echo "KEYSPACE_DETAIL:N/A"
fi
# 键类型分布采样(采样前100个键)
KEY_TYPE_SAMPLE=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" --scan --count 100 2>&1 | head -100 | xargs -I {} docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" TYPE {} 2>&1 | grep -v "Warning" | sort | uniq -c | awk '{print $2":"$1}' | tr '\n' '|' | sed 's/|$//' | sed 's/ /:/g')
if [ -n "$KEY_TYPE_SAMPLE" ]; then
echo "KEY_TYPE_DISTRIBUTION:$KEY_TYPE_SAMPLE"
else
echo "KEY_TYPE_DISTRIBUTION:N/A"
fi
# ========== 中优先级功能补充 ==========
# 持久化信息
PERSISTENCE_INFO=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO persistence 2>&1 | grep -v "Warning" | grep -E "rdb_last_cow_size:|aof_enabled:|rdb_last_save_time:" | tr -d '\r' | tr '\n' '|' | sed 's/|$//')
if [ -n "$PERSISTENCE_INFO" ]; then
# 解析持久化状态
RDB_COW=$(echo "$PERSISTENCE_INFO" | grep -oP 'rdb_last_cow_size:\K\d+' | head -1)
AOF_ENABLED=$(echo "$PERSISTENCE_INFO" | grep -oP 'aof_enabled:\K\d+' | head -1)
RDB_STATUS="空闲"
if [ "$RDB_COW" -gt 0 ] 2>/dev/null; then
RDB_STATUS="备份中"
fi
AOF_STATUS="未启用"
if [ "$AOF_ENABLED" = "1" ]; then
AOF_STATUS="已启用"
fi
echo "PERSISTENCE_STATUS:RDB:$RDB_STATUS,AOF:$AOF_STATUS"
else
echo "PERSISTENCE_STATUS:N/A"
fi
# 复制信息
REPL_INFO=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO replication 2>&1 | grep -v "Warning" | grep -E "role:|connected_slaves:|master_link_status:" | tr -d '\r' | tr '\n' '|' | sed 's/|$//')
if [ -n "$REPL_INFO" ]; then
ROLE=$(echo "$REPL_INFO" | grep -oP 'role:\K\w+' | head -1)
CONNECTED_SLAVES=$(echo "$REPL_INFO" | grep -oP 'connected_slaves:\K\d+' | head -1)
MASTER_LINK=$(echo "$REPL_INFO" | grep -oP 'master_link_status:\K\w+' | head -1)
if [ "$ROLE" = "master" ]; then
echo "REPLICATION_STATUS:Role:$ROLE,Slaves:${CONNECTED_SLAVES:-0}"
elif [ "$ROLE" = "slave" ]; then
echo "REPLICATION_STATUS:Role:$ROLE,MasterLink:${MASTER_LINK:-unknown}"
else
echo "REPLICATION_STATUS:Role:$ROLE"
fi
else
echo "REPLICATION_STATUS:N/A"
fi
# 慢日志TOP10
SLOW_LOG=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" SLOWLOG GET 10 2>&1 | grep -v "Warning" | head -40)
if [ -n "$SLOW_LOG" ]; then
# SLOWLOG输出格式:每4行一个记录 (ID, timestamp, duration, command)
# 我们需要获取所有记录的第3行(持续时间)
SLOW_COUNT=0
SLOWEST_TIME=0
line_num=0
while IFS= read -r line; do
line_num=$((line_num + 1))
# 每第3行是持续时间
if [ $((line_num % 4)) -eq 3 ]; then
if [[ "$line" =~ ^[0-9]+$ ]]; then
duration=$line
if [ $duration -gt $SLOWEST_TIME ]; then
SLOWEST_TIME=$duration
fi
SLOW_COUNT=$((SLOW_COUNT + 1))
fi
fi
done <<< "$SLOW_LOG"
if [ $SLOW_COUNT -gt 0 ]; then
echo "SLOW_LOG_TOP10:Count:$SLOW_COUNT,Slowest:${SLOWEST_TIME}us"
else
echo "SLOW_LOG_TOP10:Count:0"
fi
else
echo "SLOW_LOG_TOP10:Count:0"
fi
# 命令统计TOP5
CMD_STATS=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO commandstats 2>&1 | grep -v "Warning" | grep "cmdstat_" | tr -d '\r')
if [ -n "$CMD_STATS" ]; then
# 提取命令调用次数TOP5
TOP_COMMANDS=$(echo "$CMD_STATS" | grep -oP 'cmdstat_\K[a-z]+(?=:calls=\d+)' | head -5 | tr '\n' ',' | sed 's/,$//')
TOP_CALLS=$(echo "$CMD_STATS" | grep -oP 'cmdstat_[a-z]+:calls=\K\d+' | head -5 | tr '\n' ',' | sed 's/,$//')
if [ -n "$TOP_COMMANDS" ]; then
# 组合命令和调用次数
CMD_DETAIL=""
IFS=',' read -ra CMDS <<< "$TOP_COMMANDS"
IFS=',' read -ra CALLS <<< "$TOP_CALLS"
for i in "${!CMDS[@]}"; do
if [ -n "$CMD_DETAIL" ]; then
CMD_DETAIL="$CMD_DETAIL,"
fi
CMD_DETAIL="$CMD_DETAIL${CMDS[$i]}:${CALLS[$i]}"
done
echo "COMMAND_STATS_TOP5:$CMD_DETAIL"
else
echo "COMMAND_STATS_TOP5:N/A"
fi
else
echo "COMMAND_STATS_TOP5:N/A"
fi
# 客户端列表摘要
CLIENT_LIST=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" CLIENT LIST 2>&1 | grep -v "Warning" | grep "id=" | tr -d '\r')
if [ -n "$CLIENT_LIST" ]; then
TOTAL_CLIENTS=$(echo "$CLIENT_LIST" | wc -l)
IDLE_CLIENTS=0
BLOCKING_CLIENTS=0
while IFS='=' read -r key value; do
if [[ "$value" =~ idle=([0-9]+) ]]; then
idle_time=${BASH_REMATCH[1]}
if [ "$idle_time" -gt 300 ]; then
IDLE_CLIENTS=$((IDLE_CLIENTS + 1))
fi
fi
if [[ "$value" =~ blocking=1 ]]; then
BLOCKING_CLIENTS=$((BLOCKING_CLIENTS + 1))
fi
done <<< "$CLIENT_LIST"
echo "CLIENT_DETAIL:Total:$TOTAL_CLIENTS,IdleOver5min:$IDLE_CLIENTS,Blocking:$BLOCKING_CLIENTS"
else
echo "CLIENT_DETAIL:N/A"
fi
# 缓存命中率
STATS_INFO=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" INFO stats 2>&1 | grep -v "Warning" | grep -E "keyspace_hits:|keyspace_misses:|rejected_connections:" | tr -d '\r')
if [ -n "$STATS_INFO" ]; then
HITS=$(echo "$STATS_INFO" | grep keyspace_hits | cut -d: -f2)
MISSES=$(echo "$STATS_INFO" | grep keyspace_misses | cut -d: -f2)
REJECTED=$(echo "$STATS_INFO" | grep rejected_connections | cut -d: -f2)
if [ -n "$HITS" ] && [ -n "$MISSES" ]; then
TOTAL_REQ=$((HITS + MISSES))
if [ "$TOTAL_REQ" -gt 0 ]; then
HIT_RATE=$(awk "BEGIN {printf \"%.2f\", ($HITS * 100) / $TOTAL_REQ}")
else
HIT_RATE="0.00"
fi
echo "CACHE_HIT_RATE:Hits:$HITS,Misses:$MISSES,Rate:$HIT_RATE%"
else
echo "CACHE_HIT_RATE:N/A"
fi
if [ -n "$REJECTED" ]; then
echo "REJECTED_CONNECTIONS:$REJECTED"
fi
else
echo "CACHE_HIT_RATE:N/A"
echo "REJECTED_CONNECTIONS:0"
fi
# 配置检查
CONFIG_MAXCLIENTS=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" CONFIG GET maxclients 2>&1 | grep -v "Warning" | tail -1 | tr -d '\r')
CONFIG_TIMEOUT=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" CONFIG GET timeout 2>&1 | grep -v "Warning" | tail -1 | tr -d '\r')
CONFIG_SAVE=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" CONFIG GET save 2>&1 | grep -v "Warning" | tail -1 | tr -d '\r')
echo "CONFIG_CHECK:MaxClients:$CONFIG_MAXCLIENTS,Timeout:${CONFIG_TIMEOUT}s,Save:$CONFIG_SAVE"
# ========== 补充:集群状态检测 ==========
CLUSTER_INFO=$(docker exec $CONTAINER redis-cli -a "$REDIS_PASSWORD" CLUSTER INFO 2>&1 | grep -v "Warning")
if [ -n "$CLUSTER_INFO" ]; then
# 解析集群状态
CLUSTER_STATE=$(echo "$CLUSTER_INFO" | grep -oP 'cluster_state:\K\w+' | head -1)
CLUSTER_SLOTS_ASSIGNED=$(echo "$CLUSTER_INFO" | grep -oP 'cluster_slots_assigned:\K\d+' | head -1)
CLUSTER_SLOTS_OK=$(echo "$CLUSTER_INFO" | grep -oP 'cluster_slots_ok:\K\d+' | head -1)
CLUSTER_KNOWN_NODES=$(echo "$CLUSTER_INFO" | grep -oP 'cluster_known_nodes:\K\d+' | head -1)
if [ "$CLUSTER_STATE" = "ok" ]; then
echo "CLUSTER_STATUS:State:OK,Nodes:${CLUSTER_KNOWN_NODES:-1},Slots:${CLUSTER_SLOTS_ASSIGNED:-0}/${CLUSTER_SLOTS_OK:-0}"
else
echo "CLUSTER_STATUS:State:${CLUSTER_STATE},Nodes:${CLUSTER_KNOWN_NODES:-1}"
fi
else
# 非集群模式,检测单机状态
echo "CLUSTER_STATUS:Standalone"
fi
#!/bin/bash
################################################################################
# UStorage容器监测模块
# 功能: 检测ustorage容器运行状态、健康检查、存储容量与IO
# 作者: Claude Code
# 日期: 2026-07-20
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# ==================== 检测函数 ====================
# 检测容器运行状态
check_container_status() {
local container_name
container_name=$(resolve_container ustorge 2>/dev/null)
if [ -z "$container_name" ]; then
# 尝试其他可能的名称
container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -iE "ustorage|storage" | head -1)
fi
if [ -z "$container_name" ]; then
output_result "USTORAGE_CONTAINER_STATUS" "未运行"
output_result "USTORAGE_CONTAINER_LEVEL" "严重"
return 1
fi
output_result "USTORAGE_CONTAINER_NAME" "$container_name"
# 检查容器状态
local status
status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null)
if [ "$status" = "running" ]; then
output_result "USTORAGE_CONTAINER_STATUS" "运行中"
output_result "USTORAGE_CONTAINER_LEVEL" "正常"
else
output_result "USTORAGE_CONTAINER_STATUS" "$status"
output_result "USTORAGE_CONTAINER_LEVEL" "严重"
return 1
fi
# 重启次数
local restart_count
restart_count=$(docker inspect --format='{{.RestartCount}}' "$container_name" 2>/dev/null)
output_result "USTORAGE_RESTART_COUNT" "${restart_count:-0}"
if [ "${restart_count:-0}" -gt 3 ]; then
output_result "USTORAGE_RESTART_LEVEL" "警告"
else
output_result "USTORAGE_RESTART_LEVEL" "正常"
fi
# 运行时长(秒)
local start_time
start_time=$(docker inspect --format='{{.State.StartedAt}}' "$container_name" 2>/dev/null)
if [ -n "$start_time" ]; then
local start_epoch uptime_seconds
start_epoch=$(date -d "$start_time" +%s 2>/dev/null || echo "0")
if [ "$start_epoch" -gt 0 ]; then
uptime_seconds=$(( $(date +%s) - start_epoch ))
output_result "USTORAGE_UPTIME_SECONDS" "$uptime_seconds"
fi
fi
return 0
}
# 检测容器资源使用
check_container_resources() {
local container_name
container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -iE "ustorage|storage" | head -1)
if [ -z "$container_name" ]; then
return 1
fi
# CPU使用率
local cpu_percent
cpu_percent=$(docker stats --no-stream --format '{{.CPUPerc}}' "$container_name" 2>/dev/null | tr -d '%')
if [ -n "$cpu_percent" ]; then
output_result "USTORAGE_CPU_USAGE" "$cpu_percent"
fi
# 内存使用
local mem_usage mem_limit mem_percent
mem_usage=$(docker stats --no-stream --format '{{.MemUsage}}' "$container_name" 2>/dev/null)
if [ -n "$mem_usage" ]; then
output_result "USTORAGE_MEMORY_USAGE" "$mem_usage"
fi
mem_percent=$(docker stats --no-stream --format '{{.MemPerc}}' "$container_name" 2>/dev/null | tr -d '%')
if [ -n "$mem_percent" ]; then
output_result "USTORAGE_MEMORY_PERCENT" "$mem_percent"
fi
# 网络IO
local net_io
net_io=$(docker stats --no-stream --format '{{.NetIO}}' "$container_name" 2>/dev/null)
if [ -n "$net_io" ]; then
output_result "USTORAGE_NET_IO" "$net_io"
fi
# 磁盘IO
local block_io
block_io=$(docker stats --no-stream --format '{{.BlockIO}}' "$container_name" 2>/dev/null)
if [ -n "$block_io" ]; then
output_result "USTORAGE_BLOCK_IO" "$block_io"
fi
}
# 检测服务健康状态(HTTP健康检查)
check_health_endpoint() {
local container_name
container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -iE "ustorage|storage" | head -1)
if [ -z "$container_name" ]; then
return 1
fi
# 获取容器IP
local container_ip
container_ip=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name" 2>/dev/null)
if [ -z "$container_ip" ]; then
output_result "USTORAGE_HEALTH_CHECK" "无法获取IP"
return 1
fi
output_result "USTORAGE_CONTAINER_IP" "$container_ip"
# 尝试常见的健康检查端口
local ports="8080 80 9000 3000"
local health_ok=false
local response_time
for port in $ports; do
# 检查端口是否监听
if timeout 5 bash -c "echo >/dev/tcp/$container_ip/$port" 2>/dev/null; then
output_result "USTORAGE_SERVICE_PORT" "$port"
# 尝试健康检查接口
local start_time end_time
start_time=$(date +%s%N 2>/dev/null || echo "0")
if curl -sf "http://$container_ip:$port/health" -o /dev/null --connect-timeout 5 --max-time 10 2>/dev/null; then
health_ok=true
end_time=$(date +%s%N 2>/dev/null || echo "0")
response_time=$(( (end_time - start_time) / 1000000 ))
output_result "USTORAGE_HEALTH_CHECK" "正常"
output_result "USTORAGE_RESPONSE_TIME" "${response_time}ms"
output_result "USTORAGE_HEALTH_LEVEL" "正常"
break
elif curl -sf "http://$container_ip:$port/" -o /dev/null --connect-timeout 5 --max-time 10 2>/dev/null; then
health_ok=true
end_time=$(date +%s%N 2>/dev/null || echo "0")
response_time=$(( (end_time - start_time) / 1000000 ))
output_result "USTORAGE_HEALTH_CHECK" "正常"
output_result "USTORAGE_RESPONSE_TIME" "${response_time}ms"
output_result "USTORAGE_HEALTH_LEVEL" "正常"
break
fi
fi
done
if [ "$health_ok" = false ]; then
output_result "USTORAGE_HEALTH_CHECK" "无法访问"
output_result "USTORAGE_HEALTH_LEVEL" "警告"
fi
}
# 检测存储容量(通过容器内命令)
check_storage_capacity() {
local container_name
container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -iE "ustorage|storage" | head -1)
if [ -z "$container_name" ]; then
return 1
fi
# 检查容器内数据目录大小
local data_dirs="/data /storage /var/lib/storage"
for dir in $data_dirs; do
# 尝试在容器内执行命令
local dir_size
dir_size=$(docker exec "$container_name" du -sh "$dir" 2>/dev/null | awk '{print $1}')
if [ -n "$dir_size" ]; then
output_result "USTORAGE_DATA_SIZE" "$dir_size"
break
fi
done
# 检查磁盘使用率(容器视角)
local disk_usage
disk_usage=$(docker exec "$container_name" df -h / 2>/dev/null | awk 'NR==2 {print $5}' | tr -d '%')
if [ -n "$disk_usage" ]; then
output_result "USTORAGE_DISK_USAGE" "$disk_usage"
if [ "$disk_usage" -gt 90 ]; then
output_result "USTORAGE_DISK_LEVEL" "严重"
elif [ "$disk_usage" -gt 80 ]; then
output_result "USTORAGE_DISK_LEVEL" "警告"
else
output_result "USTORAGE_DISK_LEVEL" "正常"
fi
fi
# 检查inode使用率
local inode_usage
inode_usage=$(docker exec "$container_name" df -i / 2>/dev/null | awk 'NR==2 {print $5}' | tr -d '%')
if [ -n "$inode_usage" ]; then
output_result "USTORAGE_INODE_USAGE" "$inode_usage"
fi
}
# 检测日志大小
check_log_size() {
local container_name
container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -iE "ustorage|storage" | head -1)
if [ -z "$container_name" ]; then
return 1
fi
# 检查容器日志文件大小
local log_path
log_path=$(docker inspect --format='{{.LogPath}}' "$container_name" 2>/dev/null)
if [ -n "$log_path" ] && [ -f "$log_path" ]; then
local log_size
log_size=$(du -sh "$log_path" 2>/dev/null | awk '{print $1}')
if [ -n "$log_size" ]; then
output_result "USTORAGE_LOG_SIZE" "$log_size"
# 检查是否超过500MB
local log_bytes
log_bytes=$(stat -c%s "$log_path" 2>/dev/null || echo "0")
if [ "$log_bytes" -gt 524288000 ]; then
output_result "USTORAGE_LOG_LEVEL" "警告"
else
output_result "USTORAGE_LOG_LEVEL" "正常"
fi
fi
fi
}
# ==================== 主检测流程 ====================
main() {
log_info "开始UStorage容器监测..."
# 执行各项检测
check_container_status && {
check_container_resources
check_health_endpoint
check_storage_capacity
check_log_size
}
log_info "UStorage容器监测完成"
}
# 执行主函数
main
\ No newline at end of file
#!/bin/bash
################################################################################
# OOM和内核异常检测模块
# 功能: 检测OOM Killer事件、Core dump文件、文件系统只读状态等内核异常
# 作者: Claude Code
# 日期: 2026-05-09
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# ==================== 检测函数 ====================
# 检测OOM Killer事件
check_oom_killer() {
local oom_count=0
local oom_recent=0
local oom_output=""
# 从 dmesg 检查OOM记录
if command -v dmesg &> /dev/null; then
# 检查是否有OOM记录
oom_output=$(dmesg -T 2>/dev/null | grep -i "Out of memory\|Killed process" | tail -5)
oom_count=$(echo "$oom_output" | wc -l)
# 检查最近7天的OOM记录
oom_recent=$(dmesg -T 2>/dev/null | grep -i "Out of memory\|Killed process" | grep -E "$(date +%Y-%m-%d --date='7 days ago')|$(date +%Y-%m-%d --date='6 days ago')|$(date +%Y-%m-%d --date='5 days ago')|$(date +%Y-%m-%d --date='4 days ago')|$(date +%Y-%m-%d --date='3 days ago')|$(date +%Y-%m-%d --date='2 days ago')|$(date +%Y-%m-%d --date='1 days ago')|$(date +%Y-%m-%d)" | wc -l)
fi
# 从系统日志检查OOM记录
if [ -r /var/log/messages ]; then
local log_oom=$(grep -i "Out of memory\|Killed process" /var/log/messages 2>/dev/null | tail -5)
if [ -n "$log_oom" ]; then
oom_output="${oom_output}${log_oom}"
fi
elif [ -r /var/log/syslog ]; then
local log_oom=$(grep -i "Out of memory\|Killed process" /var/log/syslog 2>/dev/null | tail -5)
if [ -n "$log_oom" ]; then
oom_output="${oom_output}${log_oom}"
fi
fi
output_result "OOM_COUNT" "$oom_count"
output_result "OOM_RECENT_DAYS" "$oom_recent"
if [ "$oom_count" -gt 0 ]; then
output_result "OOM_STATUS" "严重"
echo "ERROR:检测到OOM Killer事件,系统可能内存不足"
else
output_result "OOM_STATUS" "正常"
fi
}
# 检测Core dump文件
check_core_dumps() {
local core_count=0
local core_files=""
# 在常见目录查找core文件
local search_dirs="/data /tmp /root /var/crash"
for dir in $search_dirs; do
if [ -d "$dir" ]; then
local found=$(find "$dir" -name "core.*" -mtime -7 2>/dev/null)
if [ -n "$found" ]; then
core_files="${core_files}${found}"$'\n'
fi
fi
done
core_count=$(echo "$core_files" | grep -c "core" || echo "0")
if [ "$core_count" -gt 0 ]; then
output_result "CORE_DUMP_COUNT" "$core_count"
output_result "CORE_DUMP_STATUS" "警告"
echo "ERROR:检测到${core_count}个core dump文件,可能有程序崩溃"
else
output_result "CORE_DUMP_COUNT" "0"
output_result "CORE_DUMP_STATUS" "正常"
fi
}
# 检测只读文件系统
check_readonly_fs() {
local ro_fs=0
# 检查 /proc/mounts 中是否有只读挂载的文件系统
ro_fs=$(cat /proc/mounts 2>/dev/null | grep -c 'ro,' || echo "0")
# 排除预期的只读文件系统(如squashfs、iso9660等)
local ro_expected=$(cat /proc/mounts 2>/dev/null | grep -E 'squashfs|iso9660|overlay' | wc -l)
ro_fs=$((ro_fs - ro_expected))
if [ "$ro_fs" -gt 0 ]; then
output_result "READONLY_FS_COUNT" "$ro_fs"
output_result "READONLY_FS_STATUS" "严重"
echo "ERROR:检测到只读文件系统,可能磁盘故障"
else
output_result "READONLY_FS_COUNT" "0"
output_result "READONLY_FS_STATUS" "正常"
fi
}
# 检测内核错误日志
check_kernel_errors() {
local kernel_errors=0
if command -v dmesg &> /dev/null; then
# 检查内核错误
kernel_errors=$(dmesg -T 2>/dev/null | grep -iE "error|failed|warning" | grep -v "ACPI" | wc -l)
fi
output_result "KERNEL_ERRORS" "$kernel_errors"
if [ "$kernel_errors" -gt 50 ]; then
output_result "KERNEL_STATUS" "警告"
else
output_result "KERNEL_STATUS" "正常"
fi
}
# 检测软锁定(Soft Lockup)
check_soft_lockup() {
local lockup_count=0
if command -v dmesg &> /dev/null; then
lockup_count=$(dmesg -T 2>/dev/null | grep -i "soft lockup" | wc -l)
fi
output_result "SOFT_LOCKUP_COUNT" "$lockup_count"
if [ "$lockup_count" -gt 0 ]; then
output_result "SOFT_LOCKUP_STATUS" "严重"
echo "ERROR:检测到软锁定事件"
else
output_result "SOFT_LOCKUP_STATUS" "正常"
fi
}
# 检测硬件错误(MCE)
check_hardware_errors() {
local mce_count=0
if command -v dmesg &> /dev/null; then
mce_count=$(dmesg -T 2>/dev/null | grep -i "machine check" | wc -l)
fi
# 检查 /dev/mcelog 是否存在
if [ -c /dev/mcelog ]; then
output_result "MCE_DEVICE" "存在"
else
output_result "MCE_DEVICE" "不存在"
fi
output_result "HARDWARE_ERRORS" "$mce_count"
if [ "$mce_count" -gt 0 ]; then
output_result "HARDWARE_STATUS" "严重"
echo "ERROR:检测到硬件错误"
else
output_result "HARDWARE_STATUS" "正常"
fi
}
# ==================== 主检测流程 ====================
main() {
log_info "开始OOM和内核异常检测..."
# 执行各项检测
check_oom_killer
check_core_dumps
check_readonly_fs
check_kernel_errors
check_soft_lockup
check_hardware_errors
log_info "OOM和内核异常检测完成"
}
# 执行主函数
main
#!/bin/bash
################################################################################
# 进程状态检测模块
# 功能: 检测僵尸进程、线程总数、文件描述符使用率、进程TOP列表等
# 作者: Claude Code
# 日期: 2026-05-09
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# ==================== 检测函数 ====================
# 检测僵尸进程
check_zombie_processes() {
local zombie_count=0
# 统计僵尸进程数量
zombie_count=$(ps -eo stat,pid,ppid,comm --no-headers 2>/dev/null | grep -c " Z" || echo "0")
output_result "ZOMBIE_COUNT" "$zombie_count"
if [ "$zombie_count" -gt 0 ]; then
output_result "ZOMBIE_STATUS" "严重"
echo "ERROR:检测到${zombie_count}个僵尸进程"
else
output_result "ZOMBIE_STATUS" "正常"
fi
}
# 检测线程总数
check_thread_count() {
local thread_count=0
local status
# 统计线程总数
thread_count=$(ps -eLf --no-headers 2>/dev/null | wc -l)
# 判断状态
if [ "$thread_count" -ge $THREAD_CRITICAL ]; then
status="严重"
elif [ "$thread_count" -ge $THREAD_WARNING ]; then
status="警告"
else
status="正常"
fi
output_result "THREAD_COUNT" "$thread_count"
output_result "THREAD_STATUS" "$status"
if [ "$status" != "正常" ]; then
echo "ERROR:线程总数过多: ${thread_count}"
fi
}
# 检测文件描述符使用率
check_file_descriptors() {
local allocated maximum usage_percent status
# 从 /proc/sys/fs/file-nr 读取文件描述符信息
# 格式: allocated-free maximum
read allocated free maximum < <(cat /proc/sys/fs/file-nr 2>/dev/null)
if [ -n "$maximum" ] && [ "$maximum" -gt 0 ]; then
usage_percent=$(awk "BEGIN {printf \"%.1f\", ($allocated / $maximum) * 100}")
# 判断状态
if (( $(awk "BEGIN {print ($usage_percent >= 90)}") )); then
status="严重"
elif (( $(awk "BEGIN {print ($usage_percent >= 80)}") )); then
status="警告"
else
status="正常"
fi
output_result "FD_ALLOCATED" "$allocated"
output_result "FD_MAXIMUM" "$maximum"
output_result "FD_USAGE" "${usage_percent}%"
output_result "FD_STATUS" "$status"
if [ "$status" != "正常" ]; then
echo "ERROR:文件描述符使用率过高: ${usage_percent}%"
fi
else
output_result "FD_STATUS" "未知"
fi
}
# 检测系统负载
check_system_load() {
local load1 load5 load15
local cpu_cores
# 从 /proc/loadavg 读取负载
read load1 load5 load15 rest < /proc/loadavg
# 获取CPU核心数
cpu_cores=$(nproc)
# 计算负载比例
local load_ratio=$(awk "BEGIN {printf \"%.2f\", $load1 / $cpu_cores}")
output_result "LOAD_1MIN" "$load1"
output_result "LOAD_5MIN" "$load5"
output_result "LOAD_15MIN" "$load15"
output_result "LOAD_CORES" "$cpu_cores"
output_result "LOAD_RATIO" "$load_ratio"
# 判断负载状态
local load_status
if (( $(awk "BEGIN {print ($load1 >= $cpu_cores * 2)}") )); then
load_status="严重"
elif (( $(awk "BEGIN {print ($load1 >= $cpu_cores)}") )); then
load_status="警告"
else
load_status="正常"
fi
output_result "LOAD_STATUS" "$load_status"
if [ "$load_status" != "正常" ]; then
echo "ERROR:系统负载过高: ${load1} (核心数: ${cpu_cores})"
fi
}
# 检测进程CPU TOP10
check_process_top_cpu() {
local top10
top10=$(ps -eo pid,comm,%cpu,%mem --no-headers 2>/dev/null | sort -k3 -rn | head -10)
if [ -n "$top10" ]; then
# 格式化输出
local formatted=""
while IFS= read -r line; do
if [ -n "$line" ]; then
if [ -n "$formatted" ]; then
formatted="${formatted}; ${line}"
else
formatted="${line}"
fi
fi
done <<< "$top10"
output_result "PROCESS_TOP10_CPU" "$formatted"
else
output_result "PROCESS_TOP10_CPU" "获取失败"
fi
}
# 检测进程内存 TOP10
check_process_top_memory() {
local top10
top10=$(ps -eo pid,comm,%mem,%cpu --no-headers 2>/dev/null | sort -k3 -rn | head -10)
if [ -n "$top10" ]; then
# 格式化输出
local formatted=""
while IFS= read -r line; do
if [ -n "$line" ]; then
if [ -n "$formatted" ]; then
formatted="${formatted}; ${line}"
else
formatted="${line}"
fi
fi
done <<< "$top10"
output_result "PROCESS_TOP10_MEMORY" "$formatted"
else
output_result "PROCESS_TOP10_MEMORY" "获取失败"
fi
}
# 检测进程总数
check_process_count() {
local process_count
process_count=$(ps aux --no-headers 2>/dev/null | wc -l)
output_result "PROCESS_COUNT" "$process_count"
}
# 检测运行时间最长的进程
check_longest_running() {
local longest
longest=$(ps -eo pid,comm,etime --no-headers 2>/dev/null | sort -k3 -rn | head -5)
if [ -n "$longest" ]; then
output_result "PROCESS_LONGEST_RUNNING" "已获取"
else
output_result "PROCESS_LONGEST_RUNNING" "获取失败"
fi
}
# 检测D状态不可中断睡眠进程
check_uninterruptible_processes() {
local d_count=0
local d_processes=""
# 统计D状态进程
d_processes=$(ps -eo stat,pid,comm --no-headers 2>/dev/null | grep " D" | head -10)
d_count=$(echo "$d_processes" | wc -l)
if [ -n "$d_processes" ]; then
d_processes=$(echo "$d_processes" | tr '\n' ',' | sed 's/,$//')
fi
output_result "UNINTERRUPTIBLE_COUNT" "$d_count"
if [ -n "$d_processes" ]; then
output_result "UNINTERRUPTIBLE_PROCESSES" "$d_processes"
fi
if [ "$d_count" -gt 5 ]; then
output_result "UNINTERRUPTIBLE_STATUS" "严重"
elif [ "$d_count" -gt 0 ]; then
output_result "UNINTERRUPTIBLE_STATUS" "警告"
else
output_result "UNINTERRUPTIBLE_STATUS" "正常"
fi
}
# 按进程统计打开文件数TOP5
check_process_open_files_top5() {
if command -v lsof &> /dev/null; then
local top5
top5=$(lsof 2>/dev/null | awk '{print $2}' | sort | uniq -c | sort -rn | head -5)
if [ -n "$top5" ]; then
output_result "PROCESS_OPEN_FILES_TOP5" "$top5"
else
output_result "PROCESS_OPEN_FILES_TOP5" "无数据"
fi
else
output_result "PROCESS_OPEN_FILES_TOP5" "lsof不可用"
fi
}
# 按进程统计网络连接数TOP5
check_process_connections_top5() {
if command -v ss &> /dev/null; then
local top5
# 获取各进程的网络连接数
top5=$(ss -ntp 2>/dev/null | awk '{print $7}' | sort | uniq -c | sort -rn | head -5 | grep -v "PID")
if [ -n "$top5" ]; then
output_result "PROCESS_CONNECTIONS_TOP5" "$top5"
else
output_result "PROCESS_CONNECTIONS_TOP5" "无数据"
fi
else
output_result "PROCESS_CONNECTIONS_TOP5" "ss不可用"
fi
}
# 检测进程可执行文件路径
check_process_executable_paths() {
if command -v ps &> /dev/null; then
# 获取TOP10进程的可执行文件路径
local exe_paths=""
exe_paths=$(ps -eo pid,comm,exe --no-headers 2>/dev/null | sort -k3 -rn | head -10 | awk '{print $1":"$2":"$3}' | tr '\n' ',' | sed 's/,$//')
if [ -n "$exe_paths" ]; then
output_result "PROCESS_EXE_PATHS_TOP10" "$exe_paths"
else
output_result "PROCESS_EXE_PATHS_TOP10" "无数据"
fi
# 统计孤儿进程
local orphan_count=0
orphan_count=$(ps -eo pid,ppid,comm --no-headers 2>/dev/null | awk '$2==1 {print $1}' | wc -l)
output_result "PROCESS_ORPHAN_COUNT" "$orphan_count"
if [ "$orphan_count" -gt 10 ]; then
output_result "PROCESS_ORPHAN_STATUS" "严重"
elif [ "$orphan_count" -gt 0 ]; then
output_result "PROCESS_ORPHAN_STATUS" "警告"
else
output_result "PROCESS_ORPHAN_STATUS" "正常"
fi
else
output_result "PROCESS_EXE_PATHS_TOP10" "ps不可用"
fi
}
# ==================== 主检测流程 ====================
main() {
log_info "开始进程状态检测..."
# 执行各项检测
check_zombie_processes
check_thread_count
check_file_descriptors
check_system_load
check_process_count
check_process_top_cpu
check_process_top_memory
check_longest_running
check_uninterruptible_processes
check_process_open_files_top5
check_process_connections_top5
check_process_executable_paths
log_info "进程状态检测完成"
}
# 执行主函数
main
#!/bin/bash
################################################################################
# 定时任务检测模块
# 功能: 检测crontab任务、systemd定时器等定时任务配置
# 作者: Claude Code
# 日期: 2026-05-09
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# ==================== 检测函数 ====================
# 检测crontab任务
check_crontab() {
local crontab_count=0
local crontab_list=""
if command -v crontab &> /dev/null; then
# 获取当前用户的crontab
local crontab_output
crontab_output=$(crontab -l 2>/dev/null)
if [ -n "$crontab_output" ]; then
# 统计非注释行
crontab_count=$(echo "$crontab_output" | grep -v "^#" | grep -v "^$" | wc -l)
# 获取任务列表(前10个)
crontab_list=$(echo "$crontab_output" | grep -v "^#" | grep -v "^$" | head -10)
output_result "CRONTAB_COUNT" "$crontab_count"
if [ -n "$crontab_list" ]; then
output_result "CRONTAB_LIST" "已获取"
fi
else
output_result "CRONTAB_COUNT" "0"
output_result "CRONTAB_STATUS" "无任务"
fi
else
output_result "CRONTAB_STATUS" "未安装"
fi
output_result "CRONTAB_LEVEL" "正常"
}
# 检测systemd定时器
check_systemd_timers() {
local timer_count=0
local active_timers=0
if command -v systemctl &> /dev/null; then
# 获取定时器列表
local timer_list
timer_list=$(systemctl list-timers --no-pager 2>/dev/null | tail -n +2 | head -10)
if [ -n "$timer_list" ]; then
timer_count=$(echo "$timer_list" | wc -l)
active_timers=$(echo "$timer_list" | grep -c "ACTIVE" || echo "0")
output_result "SYSTEMD_TIMERS" "$timer_count"
output_result "SYSTEMD_TIMERS_ACTIVE" "$active_timers"
else
output_result "SYSTEMD_TIMERS" "0"
fi
else
output_result "SYSTEMD_TIMERS" "systemctl不可用"
fi
output_result "SYSTEMD_TIMERS_LEVEL" "正常"
}
# 检测anacron任务
check_anacron() {
local anacron_status="未安装"
if [ -f /etc/anacrontab ]; then
anacron_status="已配置"
# 统计任务数量
local anacron_count
anacron_count=$(grep -v "^#" /etc/anacrontab 2>/dev/null | grep -v "^$" | wc -l)
output_result "ANACRON_COUNT" "$anacron_count"
else
output_result "ANACRON_STATUS" "$anacron_status"
fi
}
# 检测at任务
check_at_jobs() {
local at_count=0
if command -v at &> /dev/null; then
# 获取at任务列表
at_count=$(at -l 2>/dev/null | wc -l)
output_result "AT_JOBS" "$at_count"
else
output_result "AT_JOBS" "未安装"
fi
output_result "AT_JOBS_LEVEL" "正常"
}
# 检测crond服务状态
check_crond_status() {
local crond_status="未知"
local crond_service=""
if command -v systemctl &> /dev/null; then
# 检查crond服务
if systemctl is-active cron &> /dev/null; then
crond_service="cron"
crond_status="运行中"
elif systemctl is-active crond &> /dev/null; then
crond_service="crond"
crond_status="运行中"
else
crond_status="未运行"
fi
fi
output_result "CROND_SERVICE" "$crond_service"
output_result "CROND_STATUS" "$crond_status"
if [ "$crond_status" = "未运行" ]; then
output_result "CROND_LEVEL" "警告"
else
output_result "CROND_LEVEL" "正常"
fi
}
# 检测系统级crontab
check_system_crontab() {
local system_cron_count=0
local cron_dirs=("/etc/cron.d" "/etc/cron.hourly" "/etc/cron.daily" "/etc/cron.weekly" "/etc/cron.monthly")
for dir in "${cron_dirs[@]}"; do
if [ -d "$dir" ]; then
local count
count=$(find "$dir" -type f 2>/dev/null | wc -l)
system_cron_count=$((system_cron_count + count))
fi
done
output_result "SYSTEM_CRON_COUNT" "$system_cron_count"
# 检查/etc/crontab
if [ -f /etc/crontab ]; then
local crontab_entries
crontab_entries=$(grep -v "^#" /etc/crontab 2>/dev/null | grep -v "^$" | wc -l)
output_result "ETC_CRONTAB_ENTRIES" "$crontab_entries"
fi
}
# 检测定时任务日志
check_cron_logs() {
local cron_errors=0
if command -v journalctl &> /dev/null; then
# 检查cron相关日志中的错误
cron_errors=$(journalctl --since '24 hours ago' -u cron -u crond 2>/dev/null | grep -ci "error" || echo "0")
fi
output_result "CRON_ERRORS_24H" "$cron_errors"
if [ "$cron_errors" -gt 10 ]; then
output_result "CRON_LOGS_LEVEL" "警告"
else
output_result "CRON_LOGS_LEVEL" "正常"
fi
}
# ==================== 主检测流程 ====================
main() {
log_info "开始定时任务检测..."
# 执行各项检测
check_crontab
check_systemd_timers
check_anacron
check_at_jobs
check_crond_status
check_system_crontab
check_cron_logs
log_info "定时任务检测完成"
}
# 执行主函数
main
#!/bin/bash
################################################################################
# 端口服务检测模块
# 功能: 检测关键服务端口的监听状态
# 作者: Claude Code
# 日期: 2026-05-09
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# ==================== 端口配置 ====================
# 端口格式: "名称:端口:关键标志"
declare -a PORT_CONFIG=(
"SSH:22:1"
"MySQL:8306:1"
"Redis:6379:1"
"EMQX_MQTT:1883:1"
"EMQX_SSL:8883:0"
"EMQX_WS:8083:0"
"Java_Web:8080:1"
"HTTPS:443:1"
"Java_Admin:8999:1"
"Python:8000:0"
"FastDFS_Tracker:22122:0"
"FastDFS_Storage:23000:0"
"HTTP:80:0"
"MySQL_Default:3306:0"
"Python_Web:8081:0"
)
# ==================== 检测函数 ====================
# 检测单个端口状态
check_single_port() {
local port_name=$1
local port_num=$2
local is_critical=$3
local is_listening=0
local listen_address=""
local process_name=""
# 使用 ss 命令检测
if command -v ss &> /dev/null; then
local port_info
port_info=$(ss -tlnp 2>/dev/null | grep ":$port_num " | grep LISTEN)
if [ -n "$port_info" ]; then
is_listening=1
listen_address=$(echo "$port_info" | awk '{print $4}' | head -1)
# 尝试获取进程名
process_name=$(echo "$port_info" | grep -oP 'pid=\K[0-9]+.*' | head -1)
fi
# 备用方案:使用 netstat
elif command -v netstat &> /dev/null; then
local port_info
port_info=$(netstat -tln 2>/dev/null | grep ":$port_num " | grep LISTEN)
if [ -n "$port_info" ]; then
is_listening=1
listen_address=$(echo "$port_info" | awk '{print $4}' | head -1)
fi
# 最后备用方案:直接检查 /proc/net/tcp
elif [ -f /proc/net/tcp ]; then
# 将端口号转换为16进制
local port_hex=$(printf "%04X" $port_num)
if grep -q ":$port_hex " /proc/net/tcp 2>/dev/null; then
is_listening=1
fi
fi
# 确定状态级别
local status_level
if [ $is_listening -eq 1 ]; then
status_level="正常"
else
if [ $is_critical -eq 1 ]; then
status_level="严重"
else
status_level="警告"
fi
fi
# 输出结果
local key_name="PORT_${port_name}"
output_result "${key_name}_NUMBER" "$port_num"
output_result "${key_name}_STATUS" "$status_level"
if [ $is_listening -eq 1 ]; then
output_result "${key_name}_LISTENING" "是"
if [ -n "$listen_address" ]; then
output_result "${key_name}_ADDRESS" "$listen_address"
fi
else
output_result "${key_name}_LISTENING" "否"
echo "ERROR:端口${port_name}(${port_num})未监听"
fi
}
# 检测所有配置的端口
check_all_ports() {
local total_ports=${#PORT_CONFIG[@]}
local listening_count=0
local critical_down=0
for port_info in "${PORT_CONFIG[@]}"; do
IFS=':' read -r name port critical <<< "$port_info"
check_single_port "$name" "$port" "$critical"
# 统计监听中的端口
local key_name="PORT_${name}_LISTENING"
# 重新检查端口状态用于统计(简化版)
if command -v ss &> /dev/null; then
if ss -tlnp 2>/dev/null | grep -q ":$port "; then
listening_count=$((listening_count + 1))
else
if [ "$critical" -eq 1 ]; then
critical_down=$((critical_down + 1))
fi
fi
fi
done
output_result "PORT_TOTAL" "$total_ports"
output_result "PORT_LISTENING" "$listening_count"
output_result "PORT_DOWN" "$((total_ports - listening_count))"
if [ $critical_down -gt 0 ]; then
output_result "PORT_CRITICAL_DOWN" "$critical_down"
output_result "PORT_OVERALL_STATUS" "严重"
elif [ $listening_count -lt $((total_ports / 2)) ]; then
output_result "PORT_OVERALL_STATUS" "警告"
else
output_result "PORT_OVERALL_STATUS" "正常"
fi
}
# 检测端口占用情况
check_port_usage() {
local total_listening=0
local total_ports=65535
if command -v ss &> /dev/null; then
total_listening=$(ss -tln 2>/dev/null | grep -c LISTEN || echo "0")
fi
output_result "PORT_LISTENING_COUNT" "$total_listening"
if [ "$total_listening" -gt 100 ]; then
output_result "PORT_USAGE_LEVEL" "警告"
else
output_result "PORT_USAGE_LEVEL" "正常"
fi
}
# 检测特权端口(<1024)
check_privileged_ports() {
local priv_count=0
if command -v ss &> /dev/null; then
priv_count=$(ss -tlnp 2>/dev/null | awk '{print $4}' | grep -oE ':[0-9]+' | sed 's/://' | awk '$1 < 1024' | wc -l)
fi
output_result "PRIVILEGED_PORTS" "$priv_count"
}
# 检测端口复用情况
check_port_reuse() {
local reuse_count=0
if command -v ss &> /dev/null; then
# 检查SO_REUSEADDR端口
reuse_count=$(ss -tlnp 2>/dev/null | grep -c "0.0.0.0:" || echo "0")
fi
output_result "PORT_REUSE_COUNT" "$reuse_count"
}
# 检测IPv6端口监听
check_ipv6_ports() {
local ipv6_count=0
if command -v ss &> /dev/null; then
ipv6_count=$(ss -tln6 2>/dev/null | grep -c LISTEN || echo "0")
fi
output_result "IPV6_PORTS" "$ipv6_count"
}
# ==================== 主检测流程 ====================
main() {
log_info "开始端口服务检测..."
# 执行各项检测
check_all_ports
check_port_usage
check_privileged_ports
check_port_reuse
check_ipv6_ports
log_info "端口服务检测完成"
}
# 执行主函数
main
...@@ -61,13 +61,33 @@ ALL_MODULES: List[CheckModule] = [ ...@@ -61,13 +61,33 @@ ALL_MODULES: List[CheckModule] = [
{SUITE_QUICK, SUITE_FULL}, "03_memory_check.sh"), {SUITE_QUICK, SUITE_FULL}, "03_memory_check.sh"),
CheckModule("04_disk_check", "磁盘检测", "system", CheckModule("04_disk_check", "磁盘检测", "system",
{SUITE_QUICK, SUITE_FULL}, "04_disk_check.sh"), {SUITE_QUICK, SUITE_FULL}, "04_disk_check.sh"),
CheckModule("05_oom_check", "OOM和内核异常检测", "system",
{SUITE_FULL}, "05_oom_check.sh"),
CheckModule("06_process_check", "进程检测", "system",
{SUITE_FULL}, "06_process_check.sh"),
CheckModule("07_network_check", "网络检测", "system",
{SUITE_FULL}, "07_network_check.sh"),
CheckModule("11_scheduled_tasks", "计划任务检测", "system",
{SUITE_FULL}, "11_scheduled_tasks.sh"),
CheckModule("12_port_check", "端口检测", "system",
{SUITE_FULL}, "12_port_check.sh"),
# ---- service 类 ---- # ---- service 类 ----
CheckModule("20_docker_basic", "Docker基础", "service", CheckModule("20_docker_basic", "Docker基础", "service",
{SUITE_QUICK, SUITE_FULL}, "20_docker_basic.sh"), {SUITE_QUICK, SUITE_FULL}, "20_docker_basic.sh"),
CheckModule("21_docker_deep", "Docker深度检测", "service",
{SUITE_FULL}, "21_docker_deep.sh"),
CheckModule("22_mysql_basic", "MySQL基础", "service", CheckModule("22_mysql_basic", "MySQL基础", "service",
{SUITE_FULL}, "22_mysql_basic.sh"), {SUITE_FULL}, "22_mysql_basic.sh"),
CheckModule("23_mysql_depth", "MySQL深度检测", "service",
{SUITE_FULL}, "23_mysql_depth.sh"),
CheckModule("24_redis_basic", "Redis基础", "service", CheckModule("24_redis_basic", "Redis基础", "service",
{SUITE_FULL}, "24_redis_basic.sh"), {SUITE_FULL}, "24_redis_basic.sh"),
CheckModule("25_redis_depth", "Redis深度检测", "service",
{SUITE_FULL}, "25_redis_depth.sh"),
CheckModule("37_ustorage_check", "UStorage容器监测", "service",
{SUITE_FULL}, "37_ustorage_check.sh"),
CheckModule("38_utracker_check", "UTracker容器监测", "service",
{SUITE_FULL}, "38_utracker_check.sh"),
] ]
_BY_ID: Dict[str, CheckModule] = {m.id: m for m in ALL_MODULES} _BY_ID: Dict[str, CheckModule] = {m.id: m for m in ALL_MODULES}
......
...@@ -159,4 +159,180 @@ DISPLAY_NAMES: Dict[str, str] = { ...@@ -159,4 +159,180 @@ DISPLAY_NAMES: Dict[str, str] = {
"REDIS_AOF": "Redis AOF状态", "REDIS_AOF": "Redis AOF状态",
"REDIS_TOTAL_CONNECTIONS": "Redis总连接数", "REDIS_TOTAL_CONNECTIONS": "Redis总连接数",
"REDIS_TOTAL_COMMANDS": "Redis总命令数", "REDIS_TOTAL_COMMANDS": "Redis总命令数",
# ---- 05 OOM和内核异常检测 ----
"OOM_COUNT": "OOM事件总数",
"OOM_RECENT_DAYS": "近7天OOM事件",
"OOM_STATUS": "OOM状态",
"CORE_DUMP_COUNT": "Core dump文件数",
"CORE_DUMP_STATUS": "Core dump状态",
"READONLY_FS_COUNT": "只读文件系统数",
"READONLY_FS_STATUS": "只读文件系统状态",
"KERNEL_ERRORS": "内核错误数",
"KERNEL_STATUS": "内核状态",
"SOFT_LOCKUP_COUNT": "软锁定事件数",
"SOFT_LOCKUP_STATUS": "软锁定状态",
"HARDWARE_ERRORS": "硬件错误数",
"HARDWARE_STATUS": "硬件状态",
"MCE_DEVICE": "MCE设备",
# ---- 06 进程检测 ----
"PROCESS_COUNT": "进程总数",
"THREAD_COUNT": "线程总数",
"THREAD_STATUS": "线程状态",
"FD_ALLOCATED": "已分配文件描述符",
"FD_MAXIMUM": "最大文件描述符",
"FD_STATUS": "文件描述符状态",
"FD_USAGE": "文件描述符使用率",
"ZOMBIE_COUNT": "僵尸进程数",
"ZOMBIE_STATUS": "僵尸进程状态",
"ORPHAN_COUNT": "孤儿进程数",
"PROCESS_ORPHAN_COUNT": "孤儿进程数",
"PROCESS_ORPHAN_STATUS": "孤儿进程状态",
"UNINTERRUPTIBLE_COUNT": "不可中断进程数",
"UNINTERRUPTIBLE_STATUS": "不可中断进程状态",
"UNINTERRUPTIBLE_PROCESSES": "不可中断进程列表",
"PROCESS_TOP10_CPU": "CPU占用TOP10进程",
"PROCESS_TOP10_MEMORY": "内存占用TOP10进程",
"PROCESS_CONNECTIONS_TOP5": "连接数TOP5进程",
"PROCESS_OPEN_FILES_TOP5": "打开文件数TOP5进程",
"PROCESS_EXE_PATHS_TOP10": "可执行路径TOP10",
"PROCESS_LONGEST_RUNNING": "最长运行进程",
# ---- 07 网络检测 ----
"NET_INTERFACE_TOTAL": "网卡总数",
"NET_INTERFACE_UP": "活动网卡数",
"NET_INTERFACE_STATUS": "网卡状态",
"NET_HOSTNAME": "网络主机名",
"NET_GATEWAY": "网关地址",
"NET_GATEWAY_STATUS": "网关状态",
"GATEWAY_PING_STATUS": "网关Ping状态",
"DNS_RESOLUTION": "DNS解析状态",
"NET_TRAFFIC": "网络流量",
"NET_BANDWIDTH_DETAIL": "带宽详情",
"NET_ERRORS": "网络错误数",
"NET_ERRORS_STATUS": "网络错误状态",
"ROUTES_COUNT": "路由条目数",
"ARP_COUNT": "ARP条目数",
"ARP_ENTRIES": "ARP表项",
"TCP_ESTABLISHED": "TCP已建立连接数",
"TCP_TIME_WAIT": "TCP TIME_WAIT数",
"TCP_TIME_WAIT_STATUS": "TCP TIME_WAIT状态",
"TCP_CLOSE_WAIT": "TCP CLOSE_WAIT数",
"TCP_CLOSE_WAIT_STATUS": "TCP CLOSE_WAIT状态",
"TCP_TW_RECYCLE": "TCP TW回收",
"TCP_TW_REUSE": "TCP TW复用",
"TCP_FIN_TIMEOUT_PARAM": "TCP FIN超时参数",
"TCP_EXT_STATS": "TCP扩展统计",
"LISTEN_QUEUE_BACKLOG": "监听队列积压",
"SOCKET_STATS": "Socket统计",
"IPV6_PORTS": "IPv6端口数",
"CONTAINER_NETWORK_TO_EMQX": "容器到EMQX网络",
"LOAD_RATIO": "负载比率",
"LOAD_CORES": "负载核心数",
"LOAD_STATUS": "负载状态",
# ---- 11 计划任务检测 ----
"CRONTAB_COUNT": "Crontab任务数",
"CRONTAB_LIST": "Crontab任务列表",
"CRONTAB_STATUS": "Crontab状态",
"CRONTAB_LEVEL": "Crontab等级",
"ETC_CRONTAB_ENTRIES": "/etc/crontab条目",
"SYSTEM_CRON_COUNT": "系统Cron任务数",
"CROND_SERVICE": "Crond服务状态",
"CROND_STATUS": "Crond状态",
"CROND_LEVEL": "Crond等级",
"CRON_ERRORS_24H": "24小时Cron错误",
"CRON_LOGS_LEVEL": "Cron日志等级",
"ANACRON_COUNT": "Anacron任务数",
"ANACRON_STATUS": "Anacron状态",
"SYSTEMD_TIMERS": "Systemd定时器数",
"SYSTEMD_TIMERS_ACTIVE": "活跃Systemd定时器数",
"SYSTEMD_TIMERS_LEVEL": "Systemd定时器等级",
"AT_JOBS": "At任务数",
"AT_JOBS_LEVEL": "At任务等级",
# ---- 12 端口检测 ----
"PORT_TOTAL": "端口总数",
"PORT_LISTENING": "监听端口数",
"PORT_LISTENING_COUNT": "监听端口数",
"PORT_DOWN": "未监听端口数",
"PORT_CRITICAL_DOWN": "关键未监听端口数",
"PORT_OVERALL_STATUS": "端口总体状态",
"PORT_USAGE_LEVEL": "端口使用等级",
"PORT_REUSE_COUNT": "端口复用数",
"PRIVILEGED_PORTS": "特权端口",
# ---- 21 Docker深度检测 ----
"DOCKER_VERSION": "Docker版本",
"DOCKER_API_VERSION": "Docker API版本",
"DOCKER_STORAGE_DRIVER": "Docker存储驱动",
"DOCKER_IMAGES_COUNT": "Docker镜像数",
"DOCKER_IMAGES_DANGLING": "悬空镜像数",
"DOCKER_IMAGES_TOP5": "Docker镜像TOP5",
"DOCKER_NETWORK_COUNT": "Docker网络数",
"DOCKER_NETWORK_BRIDGE": "Docker Bridge网络数",
"DOCKER_NETWORK_OVERLAY": "Docker Overlay网络数",
"DOCKER_NETWORK_LIST": "Docker网络列表",
"DOCKER_VOLUMES_COUNT": "Docker卷数",
"DOCKER_VOLUMES_LIST": "Docker卷列表",
"DOCKER_BUILD_CACHE": "Docker构建缓存",
"DOCKER_DAEMON_CPU": "Docker守护进程CPU",
"DOCKER_DAEMON_MEM": "Docker守护进程内存",
"DOCKER_EVENTS_ERROR": "Docker错误事件",
"DOCKER_EVENTS_WARN": "Docker警告事件",
"DOCKER_EVENTS_LEVEL": "Docker事件等级",
# ---- 37 UStorage容器监测 ----
"USTORAGE_CONTAINER_NAME": "UStorage容器名",
"USTORAGE_CONTAINER_STATUS": "UStorage容器状态",
"USTORAGE_CONTAINER_LEVEL": "UStorage容器等级",
"USTORAGE_RESTART_COUNT": "UStorage重启次数",
"USTORAGE_RESTART_LEVEL": "UStorage重启等级",
"USTORAGE_UPTIME_SECONDS": "UStorage运行时长(秒)",
"USTORAGE_CPU_USAGE": "UStorage CPU使用率",
"USTORAGE_MEMORY_USAGE": "UStorage内存使用",
"USTORAGE_MEMORY_PERCENT": "UStorage内存使用率",
"USTORAGE_NET_IO": "UStorage网络IO",
"USTORAGE_BLOCK_IO": "UStorage磁盘IO",
"USTORAGE_CONTAINER_IP": "UStorage容器IP",
"USTORAGE_SERVICE_PORT": "UStorage服务端口",
"USTORAGE_HEALTH_CHECK": "UStorage健康检查",
"USTORAGE_RESPONSE_TIME": "UStorage响应时间",
"USTORAGE_HEALTH_LEVEL": "UStorage健康等级",
"USTORAGE_DATA_SIZE": "UStorage数据大小",
"USTORAGE_DISK_USAGE": "UStorage磁盘使用率",
"USTORAGE_DISK_LEVEL": "UStorage磁盘等级",
"USTORAGE_INODE_USAGE": "UStorage Inode使用率",
"USTORAGE_LOG_SIZE": "UStorage日志大小",
"USTORAGE_LOG_LEVEL": "UStorage日志等级",
# ---- 38 UTracker容器监测 ----
"UTRACKER_CONTAINER_NAME": "UTracker容器名",
"UTRACKER_CONTAINER_STATUS": "UTracker容器状态",
"UTRACKER_CONTAINER_LEVEL": "UTracker容器等级",
"UTRACKER_RESTART_COUNT": "UTracker重启次数",
"UTRACKER_RESTART_LEVEL": "UTracker重启等级",
"UTRACKER_UPTIME_SECONDS": "UTracker运行时长(秒)",
"UTRACKER_CPU_USAGE": "UTracker CPU使用率",
"UTRACKER_MEMORY_USAGE": "UTracker内存使用",
"UTRACKER_MEMORY_PERCENT": "UTracker内存使用率",
"UTRACKER_NET_IO": "UTracker网络IO",
"UTRACKER_BLOCK_IO": "UTracker磁盘IO",
"UTRACKER_CONTAINER_IP": "UTracker容器IP",
"UTRACKER_SERVICE_PORT": "UTracker服务端口",
"UTRACKER_HEALTH_CHECK": "UTracker健康检查",
"UTRACKER_RESPONSE_TIME": "UTracker响应时间",
"UTRACKER_HEALTH_LEVEL": "UTracker健康等级",
"UTRACKER_PROCESS_COUNT": "UTracker进程数",
"UTRACKER_THREAD_COUNT": "UTracker线程数",
"UTRACKER_FD_COUNT": "UTracker文件描述符数",
"UTRACKER_TCP_ESTABLISHED": "UTracker TCP已建立连接",
"UTRACKER_TCP_TIME_WAIT": "UTracker TCP TIME_WAIT",
"UTRACKER_TCP_CLOSE_WAIT": "UTracker TCP CLOSE_WAIT",
"UTRACKER_TCP_LEVEL": "UTracker TCP连接等级",
"UTRACKER_DISK_USAGE": "UTracker磁盘使用率",
"UTRACKER_DISK_LEVEL": "UTracker磁盘等级",
"UTRACKER_LOG_SIZE": "UTracker日志大小",
"UTRACKER_LOG_LEVEL": "UTracker日志等级",
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论