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

feat(scripts): 优化服务器监控脚本的容器检测功能

- 实现MySQL、Redis、EMQX、Java、Python、Nginx、Nacos容器的模糊匹配检测
- 添加EMQX Dashboard状态检测功能
- 增加Spring Boot Actuator端点检测
- 添加Java应用配置文件检测
- 实现Nginx访问日志状态码统计
- 添加Nginx慢请求检测
- 增加应用日志错误频率和类型检测
- 创建新的服务器空间检查脚本
- 优化容器状态检测逻辑和错误处理机制
上级 e38a4884
...@@ -263,10 +263,13 @@ function Parse-ModuleResult { ...@@ -263,10 +263,13 @@ function Parse-ModuleResult {
$lines = $RawOutput -split "`n" $lines = $RawOutput -split "`n"
$category = Get-ModuleCategory -ModuleName $ModuleName $category = Get-ModuleCategory -ModuleName $ModuleName
# Write-Log "=== $ModuleName 解析结果 ===" "DEBUG" # 调试输出(针对Java模块)
# Write-Log "原始输出长度: $($RawOutput.Length)" "DEBUG" if ($ModuleName -eq "28_java_check.sh") {
# Write-Log "原始输出内容: [$RawOutput]" "DEBUG" Write-Log "=== $ModuleName 解析结果 ===" "DEBUG"
# Write-Log "接收到的行数: $($lines.Count)" "DEBUG" Write-Log "原始输出长度: $($RawOutput.Length)" "DEBUG"
Write-Log "原始输出内容: [$RawOutput]" "DEBUG"
Write-Log "接收到的行数: $($lines.Count)" "DEBUG"
}
foreach ($line in $lines) { foreach ($line in $lines) {
$line = $line.Trim() $line = $line.Trim()
...@@ -569,19 +572,55 @@ function Get-DisplayName { ...@@ -569,19 +572,55 @@ function Get-DisplayName {
"EMQX_CONN_LEVEL" = "EMQX连接状态等级" "EMQX_CONN_LEVEL" = "EMQX连接状态等级"
"EMQX_MEMORY_USAGE" = "EMQX内存使用率" "EMQX_MEMORY_USAGE" = "EMQX内存使用率"
"EMQX_PLUGINS_COUNT" = "EMQX插件数量" "EMQX_PLUGINS_COUNT" = "EMQX插件数量"
"EMQX_CONTAINER" = "EMQX容器名称"
"EMQX_CONTAINER_STATUS" = "EMQX容器状态"
"EMQX_CONTAINER_LEVEL" = "EMQX容器状态等级"
"EMQX_RULES_COUNT" = "EMQX规则数量" "EMQX_RULES_COUNT" = "EMQX规则数量"
"EMQX_ALARMS_COUNT" = "EMQX告警数量" "EMQX_ALARMS_COUNT" = "EMQX告警数量"
"EMQX_ALARMS_LEVEL" = "EMQX告警等级" "EMQX_ALARMS_LEVEL" = "EMQX告警等级"
"EMQX_MESSAGES_SENT" = "EMQX发送消息数" "EMQX_MESSAGES_SENT" = "EMQX发送消息数"
"EMQX_MESSAGES_RECEIVED" = "EMQX接收消息数" "EMQX_MESSAGES_RECEIVED" = "EMQX接收消息数"
"EMQX_VERSION" = "EMQX版本" "EMQX_VERSION" = "EMQX版本"
"EMQX_DASHBOARD_STATUS" = "EMQX数据板状态"
"EMQX_DASHBOARD_LEVEL" = "EMQX数据板状态等级"
"EMQX_DASHBOARD_URL" = "EMQX数据板访问地址"
"EMQX_DASHBOARD_VERSION" = "EMQX数据板版本"
# 通用状态 # 通用状态
"DOCKER_STATUS" = "Docker状态" "DOCKER_STATUS" = "Docker状态"
"MYSQL_STATUS" = "MySQL状态" "MYSQL_STATUS" = "MySQL状态"
"REDIS_STATUS" = "Redis状态" "REDIS_STATUS" = "Redis状态"
"EMQX_STATUS" = "EMQX状态" "EMQX_STATUS" = "EMQX状态"
"JAVA_CONTAINER" = "Java容器名称"
"JAVA_CONTAINER_STATUS" = "Java容器状态"
"JAVA_CONTAINER_LEVEL" = "Java容器状态等级"
"JAVA_TEST_OUTPUT" = "Java测试输出"
"JAVA_MODULE_STARTED" = "Java模块启动"
"JAVA_MODULE_STATUS" = "Java模块状态"
"JAVA_MODULE_COMPLETED" = "Java模块完成"
"JAVA_VERSION" = "Java版本" "JAVA_VERSION" = "Java版本"
"JAVA_PID" = "Java进程PID"
"JAVA_VM_SIZE" = "Java虚拟内存大小"
"JAVA_VM_RSS" = "Java物理内存大小"
"JAVA_THREADS" = "Java线程数"
"JAVA_HEAP_CAPACITY" = "Java堆内存容量"
"JAVA_HEAP_USED" = "Java堆内存已用"
"JAVA_HEAP_PERCENT" = "Java堆内存使用率"
"JAVA_HEAP_LEVEL" = "Java堆内存状态等级"
"JAVA_FULL_GC" = "Java Full GC次数"
"JAVA_YOUNG_GC" = "Java Young GC次数"
"JAVA_GC_LEVEL" = "Java GC状态等级"
"JAVA_THREAD_COUNT" = "Java应用线程数"
"JAVA_THREAD_LEVEL" = "Java线程状态等级"
"JAVA_LOG_ERRORS" = "Java日志错误数"
"JAVA_LOG_LEVEL" = "Java日志状态等级"
"SPRINGBOOT_ACTUATOR" = "Spring Boot Actuator状态"
"SPRINGBOOT_HEALTH_STATUS" = "Spring Boot健康状态"
"SPRINGBOOT_HEALTH_LEVEL" = "Spring Boot健康等级"
"JAVA_CONFIG_FILE" = "Java配置文件路径"
"JAVA_SERVER_PORT" = "Java服务端口"
"JAVA_DATABASE_URL" = "Java数据库连接URL"
"JAVA_CONFIG_COUNT" = "Java配置项数量"
"PYTHON_VERSION" = "Python版本" "PYTHON_VERSION" = "Python版本"
"NGINX_VERSION" = "Nginx版本" "NGINX_VERSION" = "Nginx版本"
"NACOS_VERSION" = "Nacos版本" "NACOS_VERSION" = "Nacos版本"
...@@ -600,6 +639,14 @@ function Get-DisplayName { ...@@ -600,6 +639,14 @@ function Get-DisplayName {
"NGINX_ACCESS_LOG_SIZE" = "Nginx访问日志大小" "NGINX_ACCESS_LOG_SIZE" = "Nginx访问日志大小"
"NGINX_ERROR_LOG_SIZE" = "Nginx错误日志大小" "NGINX_ERROR_LOG_SIZE" = "Nginx错误日志大小"
"NGINX_RECENT_ERRORS" = "Nginx最近错误数" "NGINX_RECENT_ERRORS" = "Nginx最近错误数"
"NGINX_ACCESS_LOG_STATS" = "Nginx访问日志状态码分布"
"NGINX_STATUS_2XX" = "Nginx状态码2xx数量"
"NGINX_STATUS_3XX" = "Nginx状态码3xx数量"
"NGINX_STATUS_4XX" = "Nginx状态码4xx数量"
"NGINX_STATUS_5XX" = "Nginx状态码5xx数量"
"NGINX_ERROR_RATE" = "Nginx请求错误率"
"NGINX_SLOWEST_REQUESTS" = "Nginx最慢请求TOP10"
"NGINX_SLOW_REQUESTS_COUNT" = "Nginx慢请求数量"
"NGINX_SSL_ENABLED" = "Nginx SSL启用" "NGINX_SSL_ENABLED" = "Nginx SSL启用"
"NGINX_CACHE_ENABLED" = "Nginx缓存启用" "NGINX_CACHE_ENABLED" = "Nginx缓存启用"
"NGINX_UPSTREAM_COUNT" = "Nginx上游数量" "NGINX_UPSTREAM_COUNT" = "Nginx上游数量"
...@@ -722,6 +769,20 @@ function Get-DisplayName { ...@@ -722,6 +769,20 @@ function Get-DisplayName {
"NETWORK_ERRORS" = "网络错误" "NETWORK_ERRORS" = "网络错误"
"NETWORK_ERRORS_LEVEL" = "网络错误等级" "NETWORK_ERRORS_LEVEL" = "网络错误等级"
# 应用日志检测
"APP_LOG_ERRORS_LAST_HOUR" = "应用日志最近1小时错误数"
"APP_LOG_HOURLY_STATS" = "应用日志每小时错误统计"
"APP_LOG_ERROR_LEVEL" = "应用日志错误等级"
"APP_LOG_ERROR_TYPES" = "应用日志错误类型分类"
"DOCKER_LOG_ERRORS_JAVA" = "Java容器最近1小时错误数"
"DOCKER_LOG_CONTAINER_JAVA" = "Java容器实际名称"
"DOCKER_LOG_ERRORS_NGINX" = "Nginx容器最近1小时错误数"
"DOCKER_LOG_CONTAINER_NGINX" = "Nginx容器实际名称"
"DOCKER_LOG_ERRORS_NACOS" = "Nacos容器最近1小时错误数"
"DOCKER_LOG_CONTAINER_NACOS" = "Nacos容器实际名称"
"DOCKER_LOG_ERRORS_EMQX" = "EMQX容器最近1小时错误数"
"DOCKER_LOG_CONTAINER_EMQX" = "EMQX容器实际名称"
# 时间同步检测 # 时间同步检测
"NTP_SERVICE_STATUS" = "NTP服务状态" "NTP_SERVICE_STATUS" = "NTP服务状态"
"SYSTEM_CLOCK_SYNC" = "系统时钟同步" "SYSTEM_CLOCK_SYNC" = "系统时钟同步"
...@@ -866,12 +927,21 @@ function Get-Threshold { ...@@ -866,12 +927,21 @@ function Get-Threshold {
"EMQX_ROUTES_TOTAL" = ">1000" "EMQX_ROUTES_TOTAL" = ">1000"
"EMQX_LISTENERS_COUNT" = "<1" "EMQX_LISTENERS_COUNT" = "<1"
"EMQX_SESSIONS_TOTAL" = ">1000" "EMQX_SESSIONS_TOTAL" = ">1000"
"EMQX_DASHBOARD_LEVEL" = "严重"
"EMQX_ALARMS_LEVEL" = "警告"
# ==================== Java应用阈值 ==================== # ==================== Java应用阈值 ====================
"JAVA_THREADS" = ">500" "JAVA_THREADS" = ">500"
"JAVA_THREAD_COUNT" = ">500" "JAVA_THREAD_COUNT" = ">500"
"Java线程数" = ">500" "Java线程数" = ">500"
"JAVA_LOG_ERRORS" = ">10" "JAVA_LOG_ERRORS" = ">10"
"JAVA_HEAP_PERCENT" = ">80%"
"JAVA_HEAP_LEVEL" = "警告"
"JAVA_FULL_GC" = ">2"
"JAVA_GC_LEVEL" = "警告"
"JAVA_THREAD_LEVEL" = "警告"
"JAVA_LOG_LEVEL" = "警告"
"SPRINGBOOT_HEALTH_LEVEL" = "严重"
# ==================== 综合诊断阈值 ==================== # ==================== 综合诊断阈值 ====================
"DIAG_SWAP_LEVEL" = ">20%" "DIAG_SWAP_LEVEL" = ">20%"
...@@ -947,7 +1017,6 @@ function Get-Threshold { ...@@ -947,7 +1017,6 @@ function Get-Threshold {
"EMQX_PLUGINS_COUNT" = "<1" "EMQX_PLUGINS_COUNT" = "<1"
"EMQX_RULES_COUNT" = "未启用" "EMQX_RULES_COUNT" = "未启用"
"EMQX_ALARMS_COUNT" = ">0" "EMQX_ALARMS_COUNT" = ">0"
"EMQX_ALARMS_LEVEL" = ">0"
"EMQX_MESSAGES_SENT" = ">1000000" "EMQX_MESSAGES_SENT" = ">1000000"
"EMQX_MESSAGES_RECEIVED" = ">1000000" "EMQX_MESSAGES_RECEIVED" = ">1000000"
"EMQX_CLUSTER_MODE" = "否" "EMQX_CLUSTER_MODE" = "否"
...@@ -1000,6 +1069,10 @@ function Get-Threshold { ...@@ -1000,6 +1069,10 @@ function Get-Threshold {
"NGINX_ACTIVE_CONNECTIONS" = ">1000" "NGINX_ACTIVE_CONNECTIONS" = ">1000"
"NGINX_CONFIG_LEVEL" = "严重" "NGINX_CONFIG_LEVEL" = "严重"
"NGINX_RECENT_ERRORS" = ">10" "NGINX_RECENT_ERRORS" = ">10"
"NGINX_STATUS_5XX" = ">50"
"NGINX_STATUS_4XX" = ">100"
"NGINX_ERROR_RATE" = ">5%"
"NGINX_SLOW_REQUESTS_COUNT" = ">100"
"NGINX_HEAP_USAGE" = ">80%" "NGINX_HEAP_USAGE" = ">80%"
# ==================== Nacos应用阈值 ==================== # ==================== Nacos应用阈值 ====================
...@@ -1054,6 +1127,12 @@ function Get-Threshold { ...@@ -1054,6 +1127,12 @@ function Get-Threshold {
"LARGE_LOG_FILES_LEVEL" = ">0" "LARGE_LOG_FILES_LEVEL" = ">0"
"NETWORK_ERRORS" = ">0" "NETWORK_ERRORS" = ">0"
"NETWORK_ERRORS_LEVEL" = ">0" "NETWORK_ERRORS_LEVEL" = ">0"
"APP_LOG_ERRORS_LAST_HOUR" = ">20"
"APP_LOG_ERROR_LEVEL" = "警告"
"DOCKER_LOG_ERRORS_JAVA" = ">50"
"DOCKER_LOG_ERRORS_NGINX" = ">50"
"DOCKER_LOG_ERRORS_NACOS" = ">20"
"DOCKER_LOG_ERRORS_EMQX" = ">20"
# ==================== 时间同步检测阈值 ==================== # ==================== 时间同步检测阈值 ====================
"SYSTEM_CLOCK_SYNC" = "未同步" "SYSTEM_CLOCK_SYNC" = "未同步"
...@@ -1439,7 +1518,8 @@ function New-MarkdownReport { ...@@ -1439,7 +1518,8 @@ function New-MarkdownReport {
# 跳过容器详细信息和内部变量 # 跳过容器详细信息和内部变量
if ($item.Name -match "^(CONTAINER_|LIMIT_|PROCESSES_)" -and if ($item.Name -match "^(CONTAINER_|LIMIT_|PROCESSES_)" -and
$item.Name -notmatch "_(STATUS|LEVEL)$") { $item.Name -notmatch "_(STATUS|LEVEL)$" -and
$item.Name -notmatch "^(JAVA_CONTAINER|EMQX_CONTAINER|MYSQL_CONTAINER|REDIS_CONTAINER|NGINX_CONTAINER|NACOS_CONTAINER|PYTHON_CONTAINER)$") {
continue continue
} }
...@@ -1461,8 +1541,8 @@ function New-MarkdownReport { ...@@ -1461,8 +1541,8 @@ function New-MarkdownReport {
# 跳过长列表内容项(但保留重要的进程检测项) # 跳过长列表内容项(但保留重要的进程检测项)
if ($item.Name -match "(TOP5|TOP10|TOP20|_LIST|_DETAIL|_DISTRIBUTION|_STATS|_CONFIG|_INFO|TOPICS|TOP1)$") { if ($item.Name -match "(TOP5|TOP10|TOP20|_LIST|_DETAIL|_DISTRIBUTION|_STATS|_CONFIG|_INFO|TOPICS|TOP1)$") {
# 排除例外项:进程可执行路径、孤儿进程、最近系统错误 # 排除例外项:进程检测项、系统错误项、应用日志项、服务统计项
if ($item.Name -notmatch "^(PROCESS_EXE_PATHS|RECENT_SYSTEM_ERRORS|PROCESS_ORPHAN)") { if ($item.Name -notmatch "^(PROCESS_EXE_PATHS|RECENT_SYSTEM_ERRORS|PROCESS_ORPHAN|APP_LOG_ERRORS_LAST_HOUR|APP_LOG_HOURLY_STATS|APP_LOG_ERROR_LEVEL|APP_LOG_ERROR_TYPES|DOCKER_LOG_ERRORS|DOCKER_LOG_CONTAINER|NGINX_ACCESS_LOG_STATS|NGINX_STATUS_2XX|NGINX_STATUS_3XX|NGINX_STATUS_4XX|NGINX_STATUS_5XX|NGINX_ERROR_RATE|NGINX_SLOWEST_REQUESTS|NGINX_SLOW_REQUESTS_COUNT|SPRINGBOOT_ACTUATOR|SPRINGBOOT_HEALTH_STATUS|SPRINGBOOT_HEALTH_LEVEL|JAVA_CONFIG_FILE|JAVA_SERVER_PORT|JAVA_DATABASE_URL|JAVA_CONFIG_COUNT|EMQX_DASHBOARD_STATUS|EMQX_DASHBOARD_LEVEL|EMQX_DASHBOARD_URL|EMQX_DASHBOARD_VERSION)") {
continue continue
} }
} }
......
...@@ -37,18 +37,33 @@ mysql_exec() { ...@@ -37,18 +37,33 @@ mysql_exec() {
# ==================== 检测函数 ==================== # ==================== 检测函数 ====================
# 检测MySQL容器状态 # 检测MySQL容器状态(使用模糊匹配)
check_mysql_container() { check_mysql_container() {
local container_status="未运行" local container_status="未运行"
local level="严重" local level="严重"
local matched_container=""
if command -v docker &> /dev/null; then if command -v docker &> /dev/null; then
if docker ps --format "{{.Names}}" | grep -q "^${MYSQL_CONTAINER}$"; then # 尝试精确匹配
container_status="运行中" matched_container=$(docker ps --format "{{.Names}}" | grep -x "${MYSQL_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$matched_container" ] && [ -n "$MYSQL_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${MYSQL_CONTAINER}" | head -1)
fi
if [ -n "$matched_container" ]; then
container_status="运行中 (${matched_container})"
level="正常" level="正常"
elif docker ps -a --format "{{.Names}}" | grep -q "^${MYSQL_CONTAINER}$"; then # 更新全局变量
container_status="已停止" eval "MYSQL_CONTAINER='${matched_container}'"
level="警告" else
# 检查容器是否存在但未运行
matched_container=$(docker ps -a --format "{{.Names}}" | grep -i "${MYSQL_CONTAINER}" | head -1)
if [ -n "$matched_container" ]; then
container_status="已停止 (${matched_container})"
level="警告"
fi
fi fi
fi fi
......
...@@ -37,18 +37,33 @@ redis_exec() { ...@@ -37,18 +37,33 @@ redis_exec() {
# ==================== 检测函数 ==================== # ==================== 检测函数 ====================
# 检测Redis容器状态 # 检测Redis容器状态(使用模糊匹配)
check_redis_container() { check_redis_container() {
local container_status="未运行" local container_status="未运行"
local level="严重" local level="严重"
local matched_container=""
if command -v docker &> /dev/null; then if command -v docker &> /dev/null; then
if docker ps --format "{{.Names}}" | grep -q "^${REDIS_CONTAINER}$"; then # 尝试精确匹配
container_status="运行中" matched_container=$(docker ps --format "{{.Names}}" | grep -x "${REDIS_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$matched_container" ] && [ -n "$REDIS_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${REDIS_CONTAINER}" | head -1)
fi
if [ -n "$matched_container" ]; then
container_status="运行中 (${matched_container})"
level="正常" level="正常"
elif docker ps -a --format "{{.Names}}" | grep -q "^${REDIS_CONTAINER}$"; then # 更新全局变量
container_status="已停止" eval "REDIS_CONTAINER='${matched_container}'"
level="警告" else
# 检查容器是否存在但未运行
matched_container=$(docker ps -a --format "{{.Names}}" | grep -i "${REDIS_CONTAINER}" | head -1)
if [ -n "$matched_container" ]; then
container_status="已停止 (${matched_container})"
level="警告"
fi
fi fi
fi fi
......
...@@ -37,18 +37,33 @@ emqx_exec() { ...@@ -37,18 +37,33 @@ emqx_exec() {
# ==================== 检测函数 ==================== # ==================== 检测函数 ====================
# 检测EMQX容器状态 # 检测EMQX容器状态(使用模糊匹配)
check_emqx_container() { check_emqx_container() {
local container_status="未运行" local container_status="未运行"
local level="严重" local level="严重"
local matched_container=""
if command -v docker &> /dev/null; then if command -v docker &> /dev/null; then
if docker ps --format "{{.Names}}" | grep -q "^${EMQX_CONTAINER}$"; then # 尝试精确匹配
container_status="运行中" matched_container=$(docker ps --format "{{.Names}}" | grep -x "${EMQX_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$matched_container" ] && [ -n "$EMQX_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${EMQX_CONTAINER}" | head -1)
fi
if [ -n "$matched_container" ]; then
container_status="运行中 (${matched_container})"
level="正常" level="正常"
elif docker ps -a --format "{{.Names}}" | grep -q "^${EMQX_CONTAINER}$"; then # 更新全局变量
container_status="已停止" eval "EMQX_CONTAINER='${matched_container}'"
level="警告" else
# 检查容器是否存在但未运行
matched_container=$(docker ps -a --format "{{.Names}}" | grep -i "${EMQX_CONTAINER}" | head -1)
if [ -n "$matched_container" ]; then
container_status="已停止 (${matched_container})"
level="警告"
fi
fi fi
fi fi
......
...@@ -385,17 +385,89 @@ check_emqx_performance() { ...@@ -385,17 +385,89 @@ check_emqx_performance() {
fi fi
} }
# 检测EMQX Dashboard(数据板)状态
check_emqx_dashboard() {
local dashboard_status="未启用"
local dashboard_level="正常"
local dashboard_url=""
local dashboard_port="18083"
# 直接尝试访问Dashboard(不依赖netstat)
local http_response
http_response=$(emqx_exec curl -s -m 3 --max-time 3 "http://localhost:$dashboard_port" 2>/dev/null | head -c 1000)
if [ -n "$http_response" ]; then
# 检查响应内容
if echo "$http_response" | grep -qiE "emqx|dashboard|login|mqtt"; then
dashboard_status="可访问"
dashboard_level="正常"
dashboard_url="http://localhost:$dashboard_port"
# 尝试检测Dashboard版本(如果有版本信息)
local dashboard_version
dashboard_version=$(echo "$http_response" | grep -oE "v[0-9.]+" | head -1)
if [ -n "$dashboard_version" ]; then
output_result "EMQX_DASHBOARD_VERSION" "$dashboard_version"
fi
else
dashboard_status="响应异常"
dashboard_level="警告"
fi
fi
# 检查其他可能的Dashboard端口
if [ "$dashboard_status" = "未启用" ]; then
local alt_ports=("8081" "8083" "8883")
for alt_port in "${alt_ports[@]}"; do
local alt_response
alt_response=$(emqx_exec curl -s -m 2 --max-time 2 "http://localhost:$alt_port" 2>/dev/null | head -c 500)
if [ -n "$alt_response" ]; then
if echo "$alt_response" | grep -qiE "emqx|dashboard|login|mqtt"; then
dashboard_status="可访问(端口$alt_port)"
dashboard_level="正常"
dashboard_url="http://localhost:$alt_port"
break
fi
fi
done
fi
output_result "EMQX_DASHBOARD_STATUS" "$dashboard_status"
output_result "EMQX_DASHBOARD_LEVEL" "$dashboard_level"
if [ -n "$dashboard_url" ]; then
output_result "EMQX_DASHBOARD_URL" "$dashboard_url"
fi
}
# ==================== 主检测流程 ==================== # ==================== 主检测流程 ====================
main() { main() {
log_info "开始EMQX深度检测..." log_info "开始EMQX深度检测..."
# 检查容器状态 # 在检测前先找到实际的容器名
if ! docker ps --format "{{.Names}}" | grep -q "^${EMQX_CONTAINER}$"; then if command -v docker &> /dev/null; then
# 尝试精确匹配
local actual_container=$(docker ps --format "{{.Names}}" | grep -x "${EMQX_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$actual_container" ]; then
actual_container=$(docker ps --format "{{.Names}}" | grep -i "emqx" | head -1)
fi
# 更新EMQX_CONTAINER为实际找到的容器名
if [ -n "$actual_container" ]; then
EMQX_CONTAINER="$actual_container"
fi
fi
if [ -z "$EMQX_CONTAINER" ]; then
log_warn "EMQX容器未运行" log_warn "EMQX容器未运行"
output_result "EMQX_CONTAINER_STATUS" "未运行" output_result "EMQX_CONTAINER_STATUS" "未运行"
return 1 return 1
fi fi
output_result "EMQX_CONTAINER" "$EMQX_CONTAINER"
output_result "EMQX_CONTAINER_STATUS" "运行中" output_result "EMQX_CONTAINER_STATUS" "运行中"
# 执行各项深度检测(添加错误处理,确保部分失败不影响其他检测) # 执行各项深度检测(添加错误处理,确保部分失败不影响其他检测)
...@@ -414,6 +486,7 @@ main() { ...@@ -414,6 +486,7 @@ main() {
check_emqx_rules 2>/dev/null || true check_emqx_rules 2>/dev/null || true
check_emqx_alarms 2>/dev/null || true check_emqx_alarms 2>/dev/null || true
check_emqx_performance 2>/dev/null || true check_emqx_performance 2>/dev/null || true
check_emqx_dashboard 2>/dev/null || true
log_info "EMQX深度检测完成" log_info "EMQX深度检测完成"
} }
......
...@@ -37,18 +37,26 @@ java_exec() { ...@@ -37,18 +37,26 @@ java_exec() {
# ==================== 检测函数 ==================== # ==================== 检测函数 ====================
# 检测Java容器状态 # 检测Java容器状态(使用模糊匹配)
check_java_container() { check_java_container() {
local container_status="未运行" local container_status="未运行"
local level="严重" local level="严重"
if command -v docker &> /dev/null; then if command -v docker &> /dev/null; then
# 使用当前JAVA_CONTAINER变量值进行检测
if docker ps --format "{{.Names}}" | grep -q "^${JAVA_CONTAINER}$"; then if docker ps --format "{{.Names}}" | grep -q "^${JAVA_CONTAINER}$"; then
container_status="运行中" container_status="运行中"
level="正常" level="正常"
elif docker ps -a --format "{{.Names}}" | grep -q "^${JAVA_CONTAINER}$"; then elif docker ps --format "{{.Names}}" | grep -qi "${JAVA_CONTAINER}"; then
container_status="已停止" # 找到匹配的容器,但不更新变量(由调用者处理)
level="警告" container_status="运行中"
level="正常"
else
# 检查容器是否存在但未运行
if docker ps -a --format "{{.Names}}" | grep -qi "${JAVA_CONTAINER}"; then
container_status="已停止"
level="警告"
fi
fi fi
fi fi
...@@ -191,7 +199,8 @@ check_gc_status() { ...@@ -191,7 +199,8 @@ check_gc_status() {
check_java_threads() { check_java_threads() {
local thread_count=0 local thread_count=0
thread_count=$(java_exec jps 2>/dev/null | grep -v "Jps" | awk '{print $1}' | xargs -I {} docker exec "$JAVA_CONTAINER" cat /proc/{}/status 2>/dev/null | grep "^Threads:" | awk '{print $2}') # 获取第一个Java进程的线程数
thread_count=$(java_exec jps 2>/dev/null | grep -v "Jps" | awk '{print $1}' | head -1 | xargs -I {} docker exec "$JAVA_CONTAINER" cat /proc/{}/status 2>/dev/null | grep "^Threads:" | awk '{print $2}')
if [ -n "$thread_count" ]; then if [ -n "$thread_count" ]; then
output_result "JAVA_THREAD_COUNT" "$thread_count" output_result "JAVA_THREAD_COUNT" "$thread_count"
...@@ -213,6 +222,8 @@ check_java_logs() { ...@@ -213,6 +222,8 @@ check_java_logs() {
local log_errors=0 local log_errors=0
log_errors=$(docker logs --tail 1000 "$JAVA_CONTAINER" 2>&1 | grep -ciE "ERROR|Exception" || echo "0") log_errors=$(docker logs --tail 1000 "$JAVA_CONTAINER" 2>&1 | grep -ciE "ERROR|Exception" || echo "0")
# 确保只获取数字(取最后一行)
log_errors=$(echo "$log_errors" | tail -1)
output_result "JAVA_LOG_ERRORS" "$log_errors" output_result "JAVA_LOG_ERRORS" "$log_errors"
...@@ -223,10 +234,154 @@ check_java_logs() { ...@@ -223,10 +234,154 @@ check_java_logs() {
fi fi
} }
# 检测Spring Boot Actuator端点
check_springboot_actuator() {
# 检测可用命令(curl或wget)
local http_cmd=""
if docker exec "$JAVA_CONTAINER" which curl >/dev/null 2>&1; then
http_cmd="curl -s -m 2 --max-time 2"
elif docker exec "$JAVA_CONTAINER" which wget >/dev/null 2>&1; then
http_cmd="wget -q -O - -T 2 --timeout=2"
else
output_result "SPRINGBOOT_ACTUATOR" "检测工具不可用"
output_result "SPRINGBOOT_HEALTH_STATUS" "未知"
output_result "SPRINGBOOT_HEALTH_LEVEL" "未知"
return
fi
# 常见的Actuator端点路径和端口
local actuator_ports=("8080" "8999")
local actuator_paths=("/actuator/health" "/health" "/actuator" "/")
local actuator_found="false"
local health_status="未检测"
for port in "${actuator_ports[@]}"; do
for path in "${actuator_paths[@]}"; do
# 尝试访问端点(超时2秒)
local response
response=$(docker exec "$JAVA_CONTAINER" $http_cmd "http://localhost:${port}${path}" 2>/dev/null | head -c 500)
if [ -n "$response" ]; then
# 检查是否是健康检查响应或认证错误
if echo "$response" | grep -qiE '"status"|"UP"|"DOWN"|"HEALTH"'; then
actuator_found="true"
# 解析健康状态
if echo "$response" | grep -qi '"status"[[:space:]]*:[[:space:]]*"UP"'; then
health_status="UP"
elif echo "$response" | grep -qi '"status"[[:space:]]*:[[:space:]]*"DOWN"'; then
health_status="DOWN"
elif echo "$response" | grep -qi '"status"[[:space:]]*:[[:space:]]*"{.*}"'; then
health_status="UNKNOWN"
else
health_status="解析失败"
fi
break 2
elif echo "$response" | grep -qiE "403|401|禁止|拒绝|unauthorized"; then
# 端点存在但需要认证
actuator_found="true"
health_status="需要认证"
break 2
fi
fi
done
if [ "$actuator_found" = "true" ]; then
break
fi
done
if [ "$actuator_found" = "true" ]; then
output_result "SPRINGBOOT_ACTUATOR" "已启用"
output_result "SPRINGBOOT_HEALTH_STATUS" "$health_status"
# 判断健康状态等级
local level="正常"
if [ "$health_status" = "DOWN" ]; then
level="严重"
elif [ "$health_status" = "UNKNOWN" ]; then
level="警告"
fi
output_result "SPRINGBOOT_HEALTH_LEVEL" "$level"
else
output_result "SPRINGBOOT_ACTUATOR" "未启用或不可访问"
output_result "SPRINGBOOT_HEALTH_STATUS" "未知"
output_result "SPRINGBOOT_HEALTH_LEVEL" "未知"
fi
}
# 检测Java应用配置文件
check_java_application_config() {
# 常见的配置文件路径(根据实际路径更新)
local config_paths=(
"/var/www/java/api/java-meeting/java-meeting3.0/config/application.properties"
"/var/www/java/api/java-meeting/config/application.properties"
"/var/www/java/api/config/application.properties"
"/data/services/api/java-meeting/application-prod.properties"
"/app/application.properties"
)
local config_found="false"
local config_file=""
for path in "${config_paths[@]}"; do
if docker exec "$JAVA_CONTAINER" test -f "$path" 2>/dev/null; then
config_found="true"
config_file="$path"
break
fi
done
if [ "$config_found" = "true" ]; then
output_result "JAVA_CONFIG_FILE" "$config_file"
# 检查关键配置项
local server_port db_url
server_port=$(docker exec "$JAVA_CONTAINER" grep -E "^server.port" "$config_file" 2>/dev/null | cut -d'=' -f2 | tr -d ' ' | head -1)
db_url=$(docker exec "$JAVA_CONTAINER" grep -E "^spring.datasource.url" "$config_file" 2>/dev/null | cut -d'=' -f2 | tr -d ' ' | head -1)
[ -n "$server_port" ] && output_result "JAVA_SERVER_PORT" "$server_port"
[ -n "$db_url" ] && output_result "JAVA_DATABASE_URL" "$db_url"
# 统计配置项数量
local config_count
config_count=$(docker exec "$JAVA_CONTAINER" grep -c "=" "$config_file" 2>/dev/null || echo "0")
output_result "JAVA_CONFIG_COUNT" "$config_count"
else
output_result "JAVA_CONFIG_FILE" "未找到配置文件"
output_result "JAVA_CONFIG_COUNT" "0"
fi
}
# ==================== 主检测流程 ==================== # ==================== 主检测流程 ====================
main() { main() {
log_info "开始Java应用检测..." log_info "开始Java应用检测..."
# 立即输出一个测试项
output_result "JAVA_TEST_OUTPUT" "MODULE_RUNNING"
# 在检测前先找到实际的容器名
if command -v docker &> /dev/null; then
# 尝试精确匹配
local actual_container=$(docker ps --format "{{.Names}}" | grep -x "${JAVA_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$actual_container" ]; then
actual_container=$(docker ps --format "{{.Names}}" | grep -i "java" | head -1)
fi
# 更新JAVA_CONTAINER为实际找到的容器名
if [ -n "$actual_container" ]; then
JAVA_CONTAINER="$actual_container"
fi
fi
# 输出实际使用的容器名
output_result "JAVA_CONTAINER" "$JAVA_CONTAINER"
# 检查容器状态 # 检查容器状态
if ! check_java_container; then if ! check_java_container; then
log_warn "Java容器未运行,跳过其他检测" log_warn "Java容器未运行,跳过其他检测"
...@@ -240,6 +395,8 @@ main() { ...@@ -240,6 +395,8 @@ main() {
check_gc_status check_gc_status
check_java_threads check_java_threads
check_java_logs check_java_logs
check_springboot_actuator
check_java_application_config
log_info "Java应用检测完成" log_info "Java应用检测完成"
} }
......
...@@ -26,8 +26,21 @@ python_exec() { ...@@ -26,8 +26,21 @@ python_exec() {
main() { main() {
log_info "开始Python应用检测..." log_info "开始Python应用检测..."
if command -v docker &> /dev/null && docker ps --format "{{.Names}}" | grep -q "^${PYTHON_CONTAINER}$"; then local matched_container=""
output_result "PYTHON_CONTAINER" "运行中" if command -v docker &> /dev/null; then
# 尝试精确匹配
matched_container=$(docker ps --format "{{.Names}}" | grep -x "${PYTHON_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$matched_container" ] && [ -n "$PYTHON_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${PYTHON_CONTAINER}" | head -1)
fi
fi
if [ -n "$matched_container" ]; then
# 更新全局变量(使用eval确保全局变量更新)
eval "PYTHON_CONTAINER='${matched_container}'"
output_result "PYTHON_CONTAINER" "运行中 (${PYTHON_CONTAINER})"
local py_version local py_version
py_version=$(python_exec python --version 2>&1 | awk '{print $2}') py_version=$(python_exec python --version 2>&1 | awk '{print $2}')
......
...@@ -26,8 +26,21 @@ nginx_exec() { ...@@ -26,8 +26,21 @@ nginx_exec() {
main() { main() {
log_info "开始Nginx应用检测..." log_info "开始Nginx应用检测..."
if command -v docker &> /dev/null && docker ps --format "{{.Names}}" | grep -q "^${NGINX_CONTAINER}$"; then local matched_container=""
output_result "NGINX_CONTAINER" "运行中" if command -v docker &> /dev/null; then
# 尝试精确匹配
matched_container=$(docker ps --format "{{.Names}}" | grep -x "${NGINX_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$matched_container" ] && [ -n "$NGINX_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${NGINX_CONTAINER}" | head -1)
fi
fi
if [ -n "$matched_container" ]; then
# 更新全局变量(使用eval确保全局变量更新)
eval "NGINX_CONTAINER='${matched_container}'"
output_result "NGINX_CONTAINER" "运行中 (${NGINX_CONTAINER})"
local nginx_version local nginx_version
nginx_version=$(nginx_exec nginx -v 2>&1 | grep "nginx version" | sed 's/.*nginx\///') nginx_version=$(nginx_exec nginx -v 2>&1 | grep "nginx version" | sed 's/.*nginx\///')
......
...@@ -26,8 +26,21 @@ nacos_exec() { ...@@ -26,8 +26,21 @@ nacos_exec() {
main() { main() {
log_info "开始Nacos应用检测..." log_info "开始Nacos应用检测..."
if command -v docker &> /dev/null && docker ps --format "{{.Names}}" | grep -q "^${NACOS_CONTAINER}$"; then local matched_container=""
output_result "NACOS_CONTAINER" "运行中" if command -v docker &> /dev/null; then
# 尝试精确匹配
matched_container=$(docker ps --format "{{.Names}}" | grep -x "${NACOS_CONTAINER}" | head -1)
# 如果精确匹配失败,尝试模糊匹配
if [ -z "$matched_container" ] && [ -n "$NACOS_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${NACOS_CONTAINER}" | head -1)
fi
fi
if [ -n "$matched_container" ]; then
# 更新全局变量(使用eval确保全局变量更新)
eval "NACOS_CONTAINER='${matched_container}'"
output_result "NACOS_CONTAINER" "运行中 (${NACOS_CONTAINER})"
local nacos_health local nacos_health
nacos_health=$(nacos_exec curl -s "http://localhost:8848/nacos/v1/console/health/readiness" 2>/dev/null) nacos_health=$(nacos_exec curl -s "http://localhost:8848/nacos/v1/console/health/readiness" 2>/dev/null)
......
...@@ -277,6 +277,107 @@ check_nginx_server_blocks() { ...@@ -277,6 +277,107 @@ check_nginx_server_blocks() {
fi fi
} }
# 检测Nginx访问日志状态码分布
check_nginx_access_log_stats() {
local access_log="/var/log/nginx/access.log"
# 检查日志文件是否存在
if ! nginx_exec test -f "$access_log" 2>/dev/null; then
output_result "NGINX_ACCESS_LOG_STATS" "日志文件不存在"
return
fi
# 统计最近1000行日志的状态码分布
local status_summary
status_summary=$(nginx_exec tail -1000 "$access_log" 2>/dev/null | awk '{print $9}' | sort | uniq -c | sort -rn | head -20)
if [ -n "$status_summary" ]; 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 <<< "$status_summary"
output_result "NGINX_ACCESS_LOG_STATS" "$formatted"
# 统计各状态码数量
local status_2xx status_3xx status_4xx status_5xx
status_2xx=$(nginx_exec tail -1000 "$access_log" 2>/dev/null | awk '$9 ~ /^2/ {count++} END {print count+0}')
status_3xx=$(nginx_exec tail -1000 "$access_log" 2>/dev/null | awk '$9 ~ /^3/ {count++} END {print count+0}')
status_4xx=$(nginx_exec tail -1000 "$access_log" 2>/dev/null | awk '$9 ~ /^4/ {count++} END {print count+0}')
status_5xx=$(nginx_exec tail -1000 "$access_log" 2>/dev/null | awk '$9 ~ /^5/ {count++} END {print count+0}')
output_result "NGINX_STATUS_2XX" "${status_2xx:-0}"
output_result "NGINX_STATUS_3XX" "${status_3xx:-0}"
output_result "NGINX_STATUS_4XX" "${status_4xx:-0}"
output_result "NGINX_STATUS_5XX" "${status_5xx:-0}"
# 计算错误率
local total_requests status_4xx_value status_5xx_value
total_requests=$(nginx_exec tail -1000 "$access_log" 2>/dev/null | wc -l)
status_4xx_value=${status_4xx:-0}
status_5xx_value=${status_5xx:-0}
if [ "$total_requests" -gt 0 ]; then
local error_rate=$(( (status_4xx_value + status_5xx_value) * 100 / total_requests ))
output_result "NGINX_ERROR_RATE" "${error_rate}%"
fi
else
output_result "NGINX_ACCESS_LOG_STATS" "无数据"
output_result "NGINX_STATUS_2XX" "0"
output_result "NGINX_STATUS_3XX" "0"
output_result "NGINX_STATUS_4XX" "0"
output_result "NGINX_STATUS_5XX" "0"
fi
}
# 检测Nginx最慢请求
check_nginx_slowest_requests() {
local access_log="/var/log/nginx/access.log"
# 检查日志文件是否存在
if ! nginx_exec test -f "$access_log" 2>/dev/null; then
output_result "NGINX_SLOWEST_REQUESTS" "日志文件不存在"
return
fi
# 查找响应时间最长的TOP10请求
# 日志格式: $request_time 是请求处理时间(秒)
local slowest_requests
slowest_requests=$(nginx_exec tail -5000 "$access_log" 2>/dev/null | awk '{print $NF, $0}' | sort -rn | head -10 | awk -F' ' '{print substr($0, index($0, " ") + 2)}')
if [ -n "$slowest_requests" ]; then
# 格式化输出,只显示URL、方法、状态码、响应时间
local formatted=""
while IFS= read -r line; do
if [ -n "$line" ]; then
# 提取关键信息: 方法 URL 状态码 响应时间
local summary=$(echo "$line" | awk '{print $1, $7, $9, $NF}' | tr ' ' ' ')
if [ -n "$formatted" ]; then
formatted="${formatted}; ${summary}"
else
formatted="${summary}"
fi
fi
done <<< "$slowest_requests"
output_result "NGINX_SLOWEST_REQUESTS" "$formatted"
else
output_result "NGINX_SLOWEST_REQUESTS" "无数据"
fi
# 统计慢请求数量(响应时间>1秒)
local slow_count
slow_count=$(nginx_exec tail -5000 "$access_log" 2>/dev/null | awk '{if ($NF > 1.0) print}' | wc -l)
output_result "NGINX_SLOW_REQUESTS_COUNT" "$slow_count"
}
# 检测Nginx运行时间 # 检测Nginx运行时间
check_nginx_uptime() { check_nginx_uptime() {
local nginx_pid local nginx_pid
...@@ -298,14 +399,23 @@ check_nginx_uptime() { ...@@ -298,14 +399,23 @@ check_nginx_uptime() {
main() { main() {
log_info "开始Nginx深度检测..." log_info "开始Nginx深度检测..."
# 检查容器状态 # 检查容器状态(使用模糊匹配)
if ! docker ps --format "{{.Names}}" | grep -q "^${NGINX_CONTAINER}$"; then local matched_container=""
matched_container=$(docker ps --format "{{.Names}}" | grep -x "${NGINX_CONTAINER}" | head -1)
if [ -z "$matched_container" ] && [ -n "$NGINX_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${NGINX_CONTAINER}" | head -1)
fi
if [ -z "$matched_container" ]; then
log_warn "Nginx容器未运行" log_warn "Nginx容器未运行"
output_result "NGINX_CONTAINER_STATUS" "未运行" output_result "NGINX_CONTAINER_STATUS" "未运行"
return 1 return 1
fi fi
output_result "NGINX_CONTAINER_STATUS" "运行中" # 更新为实际容器名(使用eval确保全局变量更新)
eval "NGINX_CONTAINER='${matched_container}'"
output_result "NGINX_CONTAINER_STATUS" "运行中 (${NGINX_CONTAINER})"
# 执行各项深度检测 # 执行各项深度检测
check_nginx_version_detail 2>/dev/null || true check_nginx_version_detail 2>/dev/null || true
...@@ -319,6 +429,8 @@ main() { ...@@ -319,6 +429,8 @@ main() {
check_nginx_cache 2>/dev/null || true check_nginx_cache 2>/dev/null || true
check_nginx_upstream 2>/dev/null || true check_nginx_upstream 2>/dev/null || true
check_nginx_server_blocks 2>/dev/null || true check_nginx_server_blocks 2>/dev/null || true
check_nginx_access_log_stats 2>/dev/null || true
check_nginx_slowest_requests 2>/dev/null || true
check_nginx_uptime 2>/dev/null || true check_nginx_uptime 2>/dev/null || true
log_info "Nginx深度检测完成" log_info "Nginx深度检测完成"
......
...@@ -288,14 +288,23 @@ check_nacos_uptime() { ...@@ -288,14 +288,23 @@ check_nacos_uptime() {
main() { main() {
log_info "开始Nacos深度检测..." log_info "开始Nacos深度检测..."
# 检查容器状态 # 检查容器状态(使用模糊匹配)
if ! docker ps --format "{{.Names}}" | grep -q "^${NACOS_CONTAINER}$"; then local matched_container=""
matched_container=$(docker ps --format "{{.Names}}" | grep -x "${NACOS_CONTAINER}" | head -1)
if [ -z "$matched_container" ] && [ -n "$NACOS_CONTAINER" ]; then
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${NACOS_CONTAINER}" | head -1)
fi
if [ -z "$matched_container" ]; then
log_warn "Nacos容器未运行" log_warn "Nacos容器未运行"
output_result "NACOS_CONTAINER_STATUS" "未运行" output_result "NACOS_CONTAINER_STATUS" "未运行"
return 1 return 1
fi fi
output_result "NACOS_CONTAINER_STATUS" "运行中" # 更新为实际容器名(使用eval确保全局变量更新)
eval "NACOS_CONTAINER='${matched_container}'"
output_result "NACOS_CONTAINER_STATUS" "运行中 (${NACOS_CONTAINER})"
# 执行各项深度检测 # 执行各项深度检测
check_nacos_version 2>/dev/null || true check_nacos_version 2>/dev/null || true
......
...@@ -451,6 +451,140 @@ check_oom_logs_detail() { ...@@ -451,6 +451,140 @@ check_oom_logs_detail() {
fi fi
} }
# 检测应用日志错误频率(按小时统计)
check_app_log_errors_hourly() {
local app_log_dirs=(
"/data/services/api/meeting/logs"
"/data/services/api/java-meeting/logs"
"/data/logs"
"/var/log/app"
"/app/logs"
)
local total_errors=0
local hourly_error_stats=""
# 检查每个应用日志目录
for log_dir in "${app_log_dirs[@]}"; do
if [ -d "$log_dir" ]; then
# 查找最近1小时的错误日志(使用find的-mmin -60参数)
local recent_errors
recent_errors=$(find "$log_dir" -type f -mmin -60 -name "*.log" 2>/dev/null | xargs grep -lE "ERROR|Exception|WARN" 2>/dev/null | wc -l)
if [ "$recent_errors" -gt 0 ]; then
# 统计错误数量
local error_count
error_count=$(find "$log_dir" -type f -mmin -60 -name "*.log" 2>/dev/null | xargs grep -cE "ERROR|Exception" 2>/dev/null | awk '{s+=$1} END {print s}')
[ -z "$error_count" ] && error_count=0
total_errors=$((total_errors + error_count))
# 记录该目录的统计信息
hourly_error_stats="${hourly_error_stats}${log_dir}:${error_count}个错误,"
fi
fi
done
output_result "APP_LOG_ERRORS_LAST_HOUR" "$total_errors"
if [ -n "$hourly_error_stats" ]; then
# 去掉末尾逗号
hourly_error_stats=$(echo "$hourly_error_stats" | sed 's/,$//')
output_result "APP_LOG_HOURLY_STATS" "$hourly_error_stats"
else
output_result "APP_LOG_HOURLY_STATS" "无数据"
fi
# 判断错误频率等级
local level="正常"
if [ "$total_errors" -gt 100 ]; then
level="严重"
elif [ "$total_errors" -gt 20 ]; then
level="警告"
fi
output_result "APP_LOG_ERROR_LEVEL" "$level"
}
# 检测应用日志错误类型详细分类
check_app_log_error_types() {
local app_log_dirs=(
"/data/services/api/meeting/logs"
"/data/services/api/java-meeting/logs"
"/data/logs"
"/var/log/app"
"/app/logs"
)
local error_types_summary=""
# 检查每个应用日志目录
for log_dir in "${app_log_dirs[@]}"; do
if [ -d "$log_dir" ]; then
# 查找最近1小时的日志文件
local log_files
log_files=$(find "$log_dir" -type f -mmin -60 -name "*.log" 2>/dev/null | head -5)
if [ -n "$log_files" ]; then
# 统计各类错误类型
local null_pointer
null_pointer=$(echo "$log_files" | xargs grep -c "NullPointerException" 2>/dev/null | awk '{s+=$1} END {print s}')
[ -z "$null_pointer" ] && null_pointer=0
local timeout
timeout=$(echo "$log_files" | xargs grep -cE "Timeout|timeout" 2>/dev/null | awk '{s+=$1} END {print s}')
[ -z "$timeout" ] && timeout=0
local connection
connection=$(echo "$log_files" | xargs grep -cE "Connection|connection" 2>/dev/null | awk '{s+=$1} END {print s}')
[ -z "$connection" ] && connection=0
local database
database=$(echo "$log_files" | xargs grep -cE "Database|database|SQL|sql" 2>/dev/null | awk '{s+=$1} END {print s}')
[ -z "$database" ] && database=0
# 如果有错误,记录统计
if [ "$null_pointer" -gt 0 ] || [ "$timeout" -gt 0 ] || [ "$connection" -gt 0 ] || [ "$database" -gt 0 ]; then
error_types_summary="${error_types_summary}${log_dir}[空指针:${null_pointer},超时:${timeout},连接:${connection},数据库:${database}],"
fi
fi
fi
done
if [ -n "$error_types_summary" ]; then
# 去掉末尾逗号
error_types_summary=$(echo "$error_types_summary" | sed 's/,$//')
output_result "APP_LOG_ERROR_TYPES" "$error_types_summary"
else
output_result "APP_LOG_ERROR_TYPES" "无数据"
fi
}
# 检测Docker容器应用日志错误
check_docker_app_logs() {
# 检查关键应用容器的日志错误(使用模糊匹配)
# 容器名称格式:ujava2、uemqx、unacos、unginx 等
local app_patterns=("java" "nginx" "nacos" "emqx")
for pattern in "${app_patterns[@]}"; do
# 使用模糊匹配查找容器(匹配包含pattern的容器名)
local matched_container
matched_container=$(docker ps --format "{{.Names}}" | grep -i "${pattern}" | head -1)
if [ -n "$matched_container" ]; then
# 统计最近1小时的错误
local error_count
error_count=$(docker logs --since 1h "$matched_container" 2>&1 | grep -cE "ERROR|Exception|WARN" || echo "0")
# 将pattern转换为大写作为键名
local pattern_upper=$(echo "$pattern" | tr '[:lower:]' '[:upper:]')
output_result "DOCKER_LOG_ERRORS_${pattern_upper}" "$error_count"
output_result "DOCKER_LOG_CONTAINER_${pattern_upper}" "$matched_container"
fi
done
}
# ==================== 主检测流程 ==================== # ==================== 主检测流程 ====================
main() { main() {
# 输出一个测试项确保模块被识别 # 输出一个测试项确保模块被识别
...@@ -476,6 +610,9 @@ main() { ...@@ -476,6 +610,9 @@ main() {
check_hardware_errors 2>/dev/null || true check_hardware_errors 2>/dev/null || true
check_log_file_sizes 2>/dev/null || true check_log_file_sizes 2>/dev/null || true
check_network_errors 2>/dev/null || true check_network_errors 2>/dev/null || true
check_app_log_errors_hourly 2>/dev/null || true
check_app_log_error_types 2>/dev/null || true
check_docker_app_logs 2>/dev/null || true
log_info "系统日志检测完成" log_info "系统日志检测完成"
} }
......
# 定时任务配置脚本使用说明
## 概述
`auto_crontab_settings.sh` 是一个支持多任务配置、参数化控制和自动清理的定时任务配置脚本。
## 调用方式
### 方式一:直接调用脚本
```bash
./auto_crontab_settings.sh [参数]
```
### 方式二:在主脚本中调用函数
```bash
source "$SCRIPT_DIR/auto_crontab_settings.sh"
add_crontab_job [参数]
```
## 支持的参数
| 参数 | 说明 |
|------|------|
| `--enable-ujava2` | 启用 ujava2-startup 定时任务 |
| `--disable-ujava2` | 禁用 ujava2-startup 定时任务 |
| `--enable-check-health` | 启用 check_server_health 定时任务 |
| `--disable-check-health` | 禁用 check_server_health 定时任务 |
| `--enable-mysql-backup` / `--enable-mysql` | 启用 mysql_backup 定时任务 |
| `--disable-mysql-backup` / `--disable-mysql` | 禁用 mysql_backup 定时任务 |
| `--enable-monitor-redis` | 启用 monitor_redis 定时任务 |
| `--disable-monitor-redis` | 禁用 monitor_redis 定时任务 |
| `--enable-monitor-emqx` | 启用 monitor_emqx 定时任务 |
| `--disable-monitor-emqx` | 禁用 monitor_emqx 定时任务 |
| `--enable-nginx-backup` | 启用 nginx_backup 定时任务 |
| `--disable-nginx-backup` | 禁用 nginx_backup 定时任务 |
| `--enable-mysql-logs-backup` | 启用 mysql_logs_backup 定时任务 |
| `--disable-mysql-logs-backup` | 禁用 mysql_logs_backup 定时任务 |
| `--enable-auto-clean` | 启用 auto_clean 定时任务 |
| `--disable-auto-clean` | 禁用 auto_clean 定时任务 |
| `-h, --help` | 显示帮助信息 |
## 定时任务列表
| 任务名称 | Cron 表达式 | 脚本路径 | 说明 |
|----------|-------------|----------|------|
| ujava2 | `*/3 * * * *` | `/data/services/scripts/ujava2-startup.sh` | 每3分钟执行,ujava2服务启动检查 |
| check_health | `0 1 * * *` | `/data/services/scripts/check_server_health.sh` | 每天凌晨01:00执行,服务健康检查 |
| mysql_backup | `0 0 * * 5` | `/data/services/scripts/UbainsmysqlBakUp.sh` | 每周五凌晨00:00执行,MySQL数据库备份 |
| monitor_redis | `*/5 * * * *` | `/data/services/scripts/monitor_redis_service.sh` | 每5分钟执行,Redis服务监控 |
| monitor_emqx | `*/5 * * * *` | `/data/services/scripts/monitor_emqx_service.sh` | 每5分钟执行,EMQX服务监控 |
| nginx_backup | `0 3 * * *` | `/data/services/scripts/backup_nginx_logs.sh` | 每天凌晨03:00执行,Nginx日志备份 |
| mysql_logs_backup | `0 2 * * *` | `/data/services/scripts/backup_mysql_logs.sh` | 每天凌晨02:00执行,MySQL日志备份 |
| auto_clean | `0 4 * * *` | `/data/services/scripts/auto_clean_deleted_ubains_v3.sh` | 每天凌晨04:00执行,自动清理已删除ubains |
| health_check | `0 0 * * *` | `/data/services/scripts/check_health_shell/check_server_health.sh` | 每天凌晨00:00执行,服务自检(强制启用) |
## 使用示例
### 默认全部启用
```bash
# 脚本方式
./auto_crontab_settings.sh
# 函数方式
source auto_crontab_settings.sh
add_crontab_job
```
### 禁用特定任务
```bash
# 禁用 ujava2-startup
./auto_crontab_settings.sh --disable-ujava2
# 禁用监控任务
./auto_crontab_settings.sh --disable-monitor-redis --disable-monitor-emqx
```
### 只启用特定任务
```bash
# 只启用数据库备份任务
./auto_crontab_settings.sh --enable-mysql-backup --enable-nginx-backup --enable-mysql-logs-backup
```
## 注意事项
1. **默认行为**:不传参数时,所有定时任务默认启用(向后兼容)
2. **参数冲突**:如果同时传入 `--enable-xxx``--disable-xxx`,脚本会跳过该任务并打印警告
3. **health_check 任务**:该任务默认强制启用,不支持禁用
4. **脚本存在性检查**:如果定时任务脚本不存在,会自动跳过配置并记录日志
5. **执行权限自动修复**:脚本会自动为无执行权限的脚本添加 `chmod +x`
6. **自动清理机制**:脚本不存在时,会自动移除对应的 crontab 条目
7. **Cron 服务自动启动**:如果 cron/crond 服务未运行,脚本会自动启动并设置开机自启
## 相关文档
- 需求文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_定时任务脚本优化_需求文档.md`
- 计划执行文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_定时任务脚本优化_需求文档_计划执行.md`
# 服务部署脚本使用说明
## 概述
`auto_deploy_services.sh` 是一个支持交互式选择和参数化过滤的服务部署脚本,支持预定系统、运维集控系统、语音转录系统、无纸化信令服务和电子桌牌服务的部署。
## 调用方式
### 方式一:在主脚本中调用函数
```bash
source "$SCRIPT_DIR/auto_deploy_services.sh"
# 默认显示全部服务选项
deploy_services ""
# 指定显示的服务(逗号分隔)
deploy_services "meeting,monitor,voice"
deploy_services "$deploy_services_type"
```
## 传参说明
### 参数格式
```
deploy_services "service1,service2,service3"
```
- 参数为空字符串 `""` 或不传参:显示全部服务选项
- 参数为服务名称列表(逗号分隔):只显示指定的服务选项
### 服务名称映射
| 服务名称 | 对应函数 | 菜单编号 | 说明 |
|---------|---------|---------|------|
| meeting | java_x86 | 1 | 预定系统(Java 后端服务) |
| monitor | python_x86 | 2 | 运维集控系统(Python 运维控制平台) |
| voice | python_voice_x86, iListen_x86 | 3 | 语音转录系统(语音识别引擎 + 转录后端) |
| paperless | paperless_x86 | 4 | 无纸化信令服务(Paperless 信令转发) |
| cardtable | cardtable_x86 | 5 | 电子桌牌服务(电子桌牌通信服务) |
## 使用示例
### 场景1:显示全部服务
```bash
deploy_services ""
# 或不传参(需脚本支持默认空参数)
```
### 场景2:只部署预定系统
```bash
deploy_services "meeting"
```
### 场景3:只部署预定系统和运维系统
```bash
deploy_services "meeting,monitor"
```
### 场景4:部署语音系统(包含两个服务)
```bash
deploy_services "voice"
# 会同时部署 python_voice_x86 和 iListen_x86
```
### 场景5:部署多个服务
```bash
deploy_services "meeting,monitor,voice"
```
### 场景6:只部署备份相关服务
```bash
deploy_services "paperless,cardtable"
```
## 部署流程
1. **服务过滤**:根据传入的参数过滤显示的服务选项
2. **交互选择**:用户在弹窗中勾选需要部署的服务
3. **确认部署**:显示选择的服务列表,用户确认后开始部署
4. **自动部署**:依次调用对应的服务部署函数
5. **结果统计**:显示部署成功和失败的服务数量
## 支持的服务部署函数
| 函数名 | 容器名 | 镜像 | 端口 | 说明 |
|--------|--------|------|------|------|
| java_x86 | ujava2 | 139.9.60.86:5000/ujava:v6 | 8085, 8993-8995, 9903-9920, 30880-30884 | 预定系统 Java 后端 |
| python_x86 | upython | 139.9.60.86:5000/upython:v16 | 8000, 8002 | 运维集控系统 |
| python_voice_x86 | upython_voice | 139.9.60.86:5000/upython:v13 | 8003-8004, 8080 | 语音转录后端 |
| iListen_x86 | (非容器) | - | - | 科大讯飞语音识别引擎 |
| paperless_x86 | paperless | paperless:v1 | 62121-62122 | 无纸化信令服务 |
| cardtable_x86 | cardtable | uos-cardtable:v1 | host 网络 | 电子桌牌服务 |
## 注意事项
1. **参数分隔符**:服务名称之间使用英文逗号 `,` 分隔
2. **未知服务名称**:传入无效服务名称时会输出警告并忽略,不影响其他有效服务
3. **全部无效服务名**:如果所有服务名都无效,将显示全部服务选项
4. **容器存在检查**:脚本会检查容器是否已存在,存在则跳过部署并退出
5. **镜像加载**:镜像不存在时会自动从 `/data/offline_auto_unifiedPlatform/data/temp/` 加载
6. **目录挂载**:部署前会检查目标目录是否存在,不存在则报错
## 常见问题
### Q: 如何只部署语音系统?
A: `voice` 服务会同时部署 `python_voice_x86``iListen_x86` 两个组件
### Q: 容器已存在怎么办?
A: 脚本会自动检测并跳过部署,需要先手动删除容器:`docker rm -f <容器名>`
### Q: 如何查看部署日志?
A: 部署过程会在终端输出详细日志,失败时提示执行 `docker logs <容器名>` 查看容器日志
## 相关文档
- 需求文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_deploy服务部署脚本优化_需求文档.md`
- 计划执行文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_deploy服务部署脚本优化_需求文档_计划执行.md`
# 中间件部署脚本使用说明
## 概述
`auto_middleware_install.sh` 是中间件服务部署脚本,支持 Docker、Redis、MySQL、EMQX、FastDFS、ngrok、Nacos、Nginx 等中间件的自动化部署。
## 调用方式
### 方式一:在主脚本中调用函数
```bash
# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 导入脚本
source "$SCRIPT_DIR/auto_middleware_install.sh"
# 设置服务器IP(可选)
server_ip="192.168.1.100"
# 单个中间件部署
middleware_type=redis install_middleware
# 多个中间件部署(空格分隔)
middleware_type="redis mysql emqx" install_middleware
# 所有中间件部署
middleware_type="mysql redis emqx fdfs ngrok nacos nginx" install_middleware
```
### 方式二:直接调用脚本
```bash
# 设置环境变量后调用
middleware_type="redis mysql" bash auto_middleware_install.sh
```
## 传参说明
### 参数格式
通过环境变量 `middleware_type` 传递中间件类型,多个中间件用空格分隔:
```bash
middleware_type="middleware1 middleware2 middleware3"
```
### 支持的中间件
| 中间件 | 参数值 | 部署函数 | 说明 |
|--------|--------|----------|------|
| **Docker** | 优先部署(无条件) | docker_x86 | 容器运行环境,必须优先部署 |
| Redis | redis | redis_x86 | 缓存数据库 |
| MySQL | mysql | mysql_x86 | 关系型数据库 |
| EMQX | emqx | emqx_x86 | MQTT 消息队列 |
| FastDFS | fdfs | fastfds_x86 | 分布式文件存储 |
| ngrok | ngrok | ngrok_x86 | 内网穿透服务 |
| Nacos | nacos | nacos_x86 | 配置中心和服务发现 |
| Nginx | nginx | nginx_x86 | 反向代理和负载均衡 |
## 部署顺序
脚本会按照以下优先级顺序部署中间件(建议顺序):
1. **Docker** (无条件优先部署)
2. **MySQL** (数据库优先)
3. **Redis** (缓存)
4. **EMQX** (消息队列)
5. **Nacos** (配置中心)
6. **FastDFS** (文件存储)
7. **ngrok** (内网穿透)
8. **Nginx** (反向代理)
**注意**:Docker 部署失败会导致整个部署流程停止。
## 使用示例
### 场景1:只部署 Redis
```bash
middleware_type=redis install_middleware
```
### 场景2:部署基础中间件(MySQL + Redis)
```bash
middleware_type="mysql redis" install_middleware
```
### 场景3:部署消息队列相关(Redis + EMQX)
```bash
middleware_type="redis emqx" install_middleware
```
### 场景4:部署所有中间件
```bash
middleware_type="mysql redis emqx fdfs ngrok nacos nginx" install_middleware
```
### 场景5:部署无纸化会议所需中间件
```bash
middleware_type="mysql redis emqx nginx" install_middleware
```
## 返回值说明
| 返回值 | 含义 | 处理方式 |
|--------|------|----------|
| 0 | 部署成功 | 继续后续流程 |
| 1 | 部署失败 | 使用 `log "ERROR"` 打印错误日志,主脚本应停止执行 |
## Docker 版本要求
| 配置项 | 值 |
|--------|-----|
| 离线包路径 | `/data/temp/docker-29.1.3.tgz` |
| 版本号 | `29.1.3` |
| 服务配置文件 | `/data/temp/docker.service` |
## 部署函数说明
### docker_x86()
- 检查 Docker 是否已安装
- 从离线包安装 Docker 29.1.3
- 配置 systemd 服务并启动
- 设置开机自启
### mysql_x86()
- 容器名:umysql
- 镜像:139.9.60.86:5000/umysql:v5.2
- 端口:8306
- 数据目录:/data/middleware/mysql
- 支持定时备份(每天 13:00)
### redis_x86()
- 容器名:uredis
- 镜像:139.9.60.86:5000/uredis:v1
- 端口:6379
- 数据目录:/data/middleware/redis
### emqx_x86()
- 容器名:uemqx
- 镜像:139.9.60.86:5000/uemqx:v1
- 端口:18083, 1883, 8883, 8083, 8084
- 数据目录:/data/middleware/emqx
### fastfds_x86()
- 容器名:ufastdfs
- 镜像:139.9.60.86:5000/ufastdfs:v1
- 端口:8888, 22122
- 数据目录:/data/middleware/fastdfs
### ngrok_x86()
- 容器名:ungrok
- 镜像:139.9.60.86:5000/ungrok:v1
- 端口:8081
### nacos_x86()
- 容器名:unacos
- 镜像:139.9.60.86:5000/unacos:v2
- 端口:8848, 9848, 9849
- 数据目录:/data/middleware/nacos
### nginx_x86()
- 容器名:unginx
- 镜像:139.9.60.86:5000/unified_nginx:v1
- 端口:80, 443
- 配置目录:/data/middleware/nginx
## 注意事项
1. **Docker 优先部署**:Docker 是所有中间件的基础,必须首先部署成功
2. **Docker 部署失败停止流程**:如果 Docker 部署失败,整个中间件部署流程会立即停止
3. **容器存在检查**:每个中间件部署前会检查容器是否已存在,存在则跳过部署
4. **离线包要求**:确保所有离线镜像包已上传到 `/data/temp/` 目录
5. **数据目录**:部署前确保宿主机数据目录存在(如 `/data/middleware/mysql/`
6. **参数分隔符**:多个中间件之间使用空格分隔,不是逗号
## 常见问题
### Q: Docker 部署失败怎么办?
A: 检查 `/data/temp/docker-29.1.3.tgz``/data/temp/docker.service` 文件是否存在
### Q: 如何跳过 Docker 部署?
A: 无法跳过,Docker 是所有中间件的基础,必须优先部署
### Q: 中间件部署顺序可以调整吗?
A: 脚本会按照建议顺序(MySQL → Redis → EMQX → Nacos → FastDFS → ngrok → Nginx)自动排序部署
### Q: 容器已存在会怎么处理?
A: 脚本会检测到容器已存在,跳过部署并继续下一个中间件
## 相关文档
- 需求文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_主脚本模块化拆分中间件_需求文档.md`
- 计划执行文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_主脚本模块化拆分中间件_需求文档_计划执行.md`
#!/bin/bash
#===================================================================================
# 功能说明:自动检查服务器空间分配
# 文件路径:自动化部署脚本/x86架构/新统一平台/auto_check_space.sh
# 调用方式:system_type=new_type_mount ./auto_check_space.sh
# system_type=new_type_root ./auto_check_space.sh
# system_type=old_type ./auto_check_space.sh
# 返回值:0-空间正常, 1-空间不足, 2-未正确分区
# 创建日期:2026-03-30
#===================================================================================
#===================================================================================
# 函数名称:auto_check_space
# 功能说明:检查服务器空间分配是否满足要求
# 参数说明:通过环境变量 $system_type 传入系统类型
# new_type_mount: 新统一平台,/data是独立挂载点,检查/data目录,要求≥100GB
# new_type_root: 新统一平台,/data是根下普通目录,检查/目录,要求≥100GB
# old_type: 传统平台,检查/目录,要求≥80GB
# 返回值:0-空间正常, 1-空间不足, 2-未正确分区
#===================================================================================
auto_check_space() {
# 定义内部变量
local exceted_space="" # 空间预期容量(GB)
local actual_space="" # 实际空间容量(GB)
local check_path="" # 检查路径
local result=0 # 返回结果
# 获取系统类型参数
local system_type="${system_type:-""}"
# 根据系统类型设置检查路径和预期容量
case "$system_type" in
new_type_mount)
# 新统一平台:/data是独立挂载点,检查/data目录,要求≥100GB
check_path="/data"
exceted_space=100
;;
new_type_root)
# 新统一平台:/data是根下普通目录,检查/目录,要求≥100GB
check_path="/"
exceted_space=100
;;
old_type)
# 传统平台:检查/目录,要求≥80GB
check_path="/"
exceted_space=80
;;
*)
# 未知系统类型
echo "[错误] 未知的系统类型: $system_type,请使用 new_type_mount、new_type_root 或 old_type"
return 2
;;
esac
# 检查目录是否存在
if [ ! -d "$check_path" ]; then
echo "[检查] 目录 $check_path 不存在,未正确分区"
return 2
fi
# 通过df命令获取空间信息,提取总空间大小
local space_info=$(df -h "$check_path" | tail -1 | awk '{print $2}')
# 提取数值和单位
local unit=$(echo "$space_info" | sed 's/[0-9.]//g') # 单位:T/G/M
local value=$(echo "$space_info" | sed 's/[^0-9.]//g') # 数值
# 单位转换:统一转换为GB
case "$unit" in
T|t)
# 1TB = 1024GB
actual_space=$(echo "$value * 1024" | bc)
actual_space=${actual_space%.*} # 取整
;;
G|g)
# 1GB = 1GB
actual_space=${value%.*} # 取整
;;
M|m)
# 1MB = 1/1024 GB
actual_space=$(echo "$value / 1024" | bc)
actual_space=${actual_space%.*} # 取整
;;
*)
echo "[错误] 未知的存储单位: $unit"
return 2
;;
esac
# 空间比较判断
if [ "$actual_space" -ge "$exceted_space" ]; then
echo "[检查] $check_path 总空间: ${actual_space}GB,预期: ≥${exceted_space}GB,结果: 空间正常"
result=0
else
echo "[检查] $check_path 总空间: ${actual_space}GB,预期: ≥${exceted_space}GB,结果: 空间不足"
result=1
fi
return $result
}
#===================================================================================
# 主程序入口
#===================================================================================
# 判断是否被直接调用(source方式调用时不执行主程序)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
# 执行空间检查函数
auto_check_space
# 输出返回值
exit $?
fi
#------------------------------开放防火墙端口-start------------------------------------------------------------------------------------------------------------------------
#--------开放服务端口---------------------
#==============================================================#
# 函数名: firewalldjava
# 功能: 开放 Java 服务所需防火墙端口(TCP/UDP)
# 说明: 自动检测 firewalld 状态,若开启则检查并开放以下端口:
# - TCP: 22(SSH), 443(HTTPS), 8848/9848(Nacos), 1883(MQTT), 8999(应用)
# - UDP: 123(NTP), 323(Telegraf/监控) —— 用于门口屏等设备
# 使用 --permanent 持久化规则,并在最后重新加载防火墙。
# 作者: [ubains]
# 日期: $(date +%Y-%m-%d)
#--------------------------------------------------------------#
# 参数: 无
# 返回: 0: 成功(或 firewalld 未运行)
# 1: firewalld 运行但操作失败
#--------------------------------------------------------------#
# 依赖: firewall-cmd, sudo(若使用 sudoset)
# 注意: 确保 $sudoset 已定义(如: sudoset="sudo")
#==============================================================#
function firewalldjava() {
log "INFO" "=================================================================="
log "INFO" "开始配置防火墙:开放服务所需端口"
log "INFO" "=================================================================="
# ------------------- 初始化变量 -------------------
# 初始化sudo相关变量
if [[ $(id -u) -ne 0 ]]; then
sudoset="sudo"
SUDO="sudo"
else
sudoset=""
SUDO=""
fi
# 定义 TCP 和 UDP 需要开放的端口
local tcp_ports=(22 443 1883 8883)
local udp_ports=(123 323)
# 检查 firewalld 是否正在运行
log "INFO" "正在检查 firewalld 服务状态..."
if ! $sudoset firewall-cmd --state >/dev/null 2>&1; then
log "WARN" "firewalld 未运行或未安装,跳过端口配置。"
log "INFO" "如需启用,请运行: sudo systemctl start firewalld && sudo systemctl enable firewalld"
return 0
fi
log "INFO" "✅ firewalld 已启用,开始配置端口..."
local failed=0
local changes_made=0
# ------------------- 开放 TCP 端口 -------------------
log "INFO" "🔍 检查并配置 TCP 端口: ${tcp_ports[*]}"
for port in "${tcp_ports[@]}"; do
if $sudoset firewall-cmd --zone=public --query-port="$port"/tcp >/dev/null 2>&1; then
log "INFO" "✅ TCP/$port 已开放,跳过"
else
log "INFO" "🔧 正在开放 TCP/$port ..."
if $sudoset firewall-cmd --zone=public --add-port="$port"/tcp --permanent >/dev/null 2>&1; then
log "INFO" "🎉 TCP/$port 开放成功(持久化)"
((changes_made++))
else
log "ERROR" "⛔ TCP/$port 开放失败,请手动检查"
((failed++))
fi
fi
done
# ------------------- 开放 UDP 端口 -------------------
log "INFO" "🔍 检查并配置 UDP 端口: ${udp_ports[*]}"
for port in "${udp_ports[@]}"; do
if $sudoset firewall-cmd --zone=public --query-port="$port"/udp >/dev/null 2>&1; then
log "INFO" "✅ UDP/$port 已开放,跳过"
else
log "INFO" "🔧 正在开放 UDP/$port ..."
if $sudoset firewall-cmd --zone=public --add-port="$port"/udp --permanent >/dev/null 2>&1; then
log "INFO" "🎉 UDP/$port 开放成功(持久化)"
((changes_made++))
else
log "ERROR" "⛔ UDP/$port 开放失败,请手动检查"
((failed++))
fi
fi
done
# ------------------- 重新加载防火墙 -------------------
if [[ $changes_made -gt 0 ]]; then
log "INFO" "🔄 检测到配置变更,正在重新加载 firewalld ..."
if $sudoset firewall-cmd --reload >/dev/null 2>&1; then
log "INFO" "✅ 防火墙重载成功!所有端口已生效。"
else
log "ERROR" "⛔ 防火墙重载失败,请手动执行: firewall-cmd --reload"
return 1
fi
else
log "INFO" "🟢 所有端口均已开放,无需重新加载。"
fi
# ------------------- 输出当前开放端口 -------------------
log "INFO" "📋 当前已开放的端口列表:"
$sudoset firewall-cmd --list-port 2>/dev/null || log "WARN" "无法获取端口列表"
# ------------------- 最终状态 -------------------
if [[ $failed -eq 0 ]]; then
log "INFO" "✅ 防火墙配置完成:所有端口检查通过。"
return 0
else
log "ERROR" "❌ 防火墙配置失败:共 $failed 个端口未能开放。"
return 1
fi
}
#------------------------------开放防火墙端口-end------------------------------------------------------------------------------------------------------------------------
#!/bin/bash
#------------------------------工具类模块---------------------------------------------------
LOG_FILE="/var/log/new_auto_script.log"
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
function log() {
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
local INFO_COLOR="\033[32m"
local WARN_COLOR="\033[33m"
local ERROR_COLOR="\033[31m"
local DEBUG_COLOR="\033[36m"
local RESET_COLOR="\033[0m"
if [ $# -lt 2 ]; then
echo "Usage: log <level> <message>"
return 1
fi
local level=$1
local message=$2
case $level in
"INFO") color=$INFO_COLOR ;;
"WARN") color=$WARN_COLOR ;;
"ERROR") color=$ERROR_COLOR ;;
"DEBUG") color=$DEBUG_COLOR ;;
*) echo "Invalid log level: $level"; return 1 ;;
esac
echo -e "${color}[$timestamp] [$level] $message${RESET_COLOR}"
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
}
# ===========================================
# 脚本: replace_ip_interactive.sh
# 功能: 扫描配置文件,查找并替换IP(完全自动化版本)
# ===========================================
# --- 配置区域 ---
TARGET_DIR="/data"
BACKUP_DIR="/data/temp"
OLD_IP_INPUT="192.168.5.45"
# 检查命令行参数
if [ $# -ge 1 ]; then
NEW_IP_INPUT="$1"
log "INFO" "使用传入的IP地址: $NEW_IP_INPUT"
else
# 自动获取本机IP
NEW_IP_INPUT=$(hostname -I | awk '{print $1}' | cut -d' ' -f1)
if [[ -z "$NEW_IP_INPUT" ]]; then
NEW_IP_INPUT=$(ip addr show | grep -E 'inet\s+(192\.168|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|10\.)' | awk '{print $2}' | cut -d/ -f1 | head -n1)
if [[ -z "$NEW_IP_INPUT" ]]; then
log "ERROR" "无法自动获取IP地址,请手动指定"
exit 1
fi
fi
log "INFO" "自动获取IP地址: $NEW_IP_INPUT"
fi
# 验证IP地址格式
if ! [[ $NEW_IP_INPUT =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
log "ERROR" "无效的IP地址格式: $NEW_IP_INPUT"
exit 1
fi
# 支持的配置文件扩展名
ALLOWED_EXTENSIONS=(
"\.js$"
"\.yml$"
"\.yaml$"
"\.json$"
"\.properties$"
"\.conf$"
"\.config$"
"\.ini$"
"\.env$"
"\.py$"
"\.xml$"
"\.txt$"
"\.sh$"
"\.cnf$"
)
EXT_REGEX=$(IFS='|'; echo "${ALLOWED_EXTENSIONS[*]}")
# 检查目标目录
if [[ ! -d "$TARGET_DIR" ]]; then
log "ERROR" "目录 '$TARGET_DIR' 不存在!"
exit 1
fi
# 确保备份目录存在
if [[ ! -d "$BACKUP_DIR" ]]; then
log "INFO" "备份目录 $BACKUP_DIR 不存在,正在创建..."
mkdir -p "$BACKUP_DIR" || {
log "ERROR" "无法创建备份目录 $BACKUP_DIR,请检查权限"
exit 1
}
log "INFO" "已创建 $BACKUP_DIR"
fi
# 转义旧IP用于sed
OLD_IP_ESCAPED=$(echo "$OLD_IP_INPUT" | sed 's/\./\\./g')
log "INFO" "开始自动化IP替换流程"
log "INFO" "扫描目录: $TARGET_DIR"
log "INFO" "查找旧IP: $OLD_IP_INPUT"
log "INFO" "替换为新IP: $NEW_IP_INPUT"
# 临时文件记录匹配的文件路径
MATCHED_FILES="/tmp/matched_files.$$"
> "$MATCHED_FILES"
# 使用 find 查找文件并处理
log "INFO" "正在扫描配置文件..."
find "$TARGET_DIR" -type f -regextype posix-extended -regex ".*($EXT_REGEX)" -print0 2>/dev/null | \
while IFS= read -r -d '' file; do
[[ -L "$file" ]] && continue
if ! file -b "$file" 2>/dev/null | grep -qi "text"; then
continue
fi
if grep -Fq "$OLD_IP_INPUT" "$file" 2>/dev/null; then
log "INFO" "发现匹配文件: $file"
echo "$file" >> "$MATCHED_FILES"
fi
done
# 检查是否有匹配的文件
if [[ ! -s "$MATCHED_FILES" ]]; then
log "INFO" "在指定类型的配置文件中未找到 '$OLD_IP_INPUT'。"
rm -f "$MATCHED_FILES"
exit 0
fi
MATCH_COUNT=$(wc -l < "$MATCHED_FILES")
log "INFO" "扫描完成,共找到 $MATCH_COUNT 个配置文件包含 '$OLD_IP_INPUT'。"
# 执行替换操作
log "INFO" "开始执行替换操作..."
SUCCESS_COUNT=0
FAIL_COUNT=0
while IFS= read -r file; do
if [[ -f "$file" ]]; then
# 创建备份文件名(替换斜杠为下划线)
BACKUP_NAME=$(echo "$file" | sed 's|^/||; s|/|_|g')".bak"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
# 创建备份
if cp "$file" "$BACKUP_PATH" 2>/dev/null; then
# 执行替换
if sed -i "s/$OLD_IP_ESCAPED/$NEW_IP_INPUT/g" "$file" 2>/dev/null; then
log "INFO" "✅ 已替换: $file"
((SUCCESS_COUNT++))
else
log "ERROR" "❌ 替换失败: $file"
((FAIL_COUNT++))
fi
else
log "ERROR" "❌ 备份失败: $file$BACKUP_PATH"
((FAIL_COUNT++))
fi
fi
done < "$MATCHED_FILES"
# 清理临时文件
rm -f "$MATCHED_FILES"
# 输出结果统计
log "INFO" "=================================================="
log "INFO" "IP替换完成: 成功 $SUCCESS_COUNT 个文件,失败 $FAIL_COUNT 个文件"
log "INFO" "备份文件保存在: $BACKUP_DIR"
log "INFO" "=================================================="
if [ $FAIL_COUNT -eq 0 ]; then
exit 0
else
exit 1
fi
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论