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

feat(health-check): 新增服务日志导出功能并优化报告生成

- 新增 export_logs 函数,支持新旧平台的日志文件导出
- 实现容器内 nginx error.log 的导出功能
- 对齐 ps1 脚本的日志导出清单和路径配置
- 添加 Docker 容器文件拷贝支持
- 更新报告生成版本为 v5,增加 PS1 风格总览统计
- 新增备份和日志导出摘要显示
- 添加日志导出文件列表表格展示
- 优化服务检测结果显示和统计信息
上级 da5fc0e1
...@@ -1445,7 +1445,124 @@ data_backup() { ...@@ -1445,7 +1445,124 @@ data_backup() {
} }
# ------------------------------ # ------------------------------
# 18) 报告生成(Markdown)—增强:把 KV 也写入 # 18) 日志导出(对齐 ps1:补齐新平台导出清单 + 容器内 nginx error.log)
# ------------------------------
export_logs() {
local platform="$1"
local has_ujava="$2"
local has_upython="$3"
local ujava_container="$4"
local upython_container="$5"
log INFO "========== 服务日志导出 =========="
local export_dir="$SCRIPT_DIR/logs_$(get_primary_ip)_${TS}"
mkdir -p "$export_dir"
# 收集导出结果(写入报告KV)
local exported_files=()
copy_if_exists() {
local src="$1"
local dst="$2"
if [[ -f "$src" ]]; then
mkdir -p "$(dirname "$dst")" 2>/dev/null || true
cp -f "$src" "$dst" 2>/dev/null || true
exported_files+=("$(basename "$dst")|$src")
return 0
fi
return 1
}
# 从容器中拷贝文件(docker cp 更稳,不依赖容器内命令)
copy_from_container_if_exists() {
local container="$1"
local inside="$2"
local dst="$3"
[[ -z "$container" ]] && return 1
command_exists docker || return 1
# 先 test -f
if docker exec "$container" sh -c "test -f '$inside'" >/dev/null 2>&1; then
mkdir -p "$(dirname "$dst")" 2>/dev/null || true
docker cp "${container}:${inside}" "$dst" >>"$LOG_FILE" 2>&1 || return 1
exported_files+=("$(basename "$dst")|${container}:${inside}")
return 0
fi
return 1
}
# --------------------------
# New 平台:对齐 ps1 的 NewPlatformLogs(主日志 + 各模块 ubains-INFO-AND-ERROR.log)
# 说明:路径按 ps1 注释约定;如果现场路径不一致,copy_if_exists 会自动跳过并不报错。
# --------------------------
if [[ "$platform" == "new" ]]; then
# 1) ujava 主日志(ps1:/data/services/api/java-meeting/java-meeting2.0/log.out 等)
copy_if_exists "/data/services/api/java-meeting/java-meeting2.0/log.out" "$export_dir/java-meeting2.0_log.out" || true
copy_if_exists "/data/services/api/java-meeting/java-meeting3.0/log.out" "$export_dir/java-meeting3.0_log.out" || true
copy_if_exists "/data/services/api/java-meeting/java-meeting-extapi/log.out" "$export_dir/java-meeting-extapi_log.out" || true
copy_if_exists "/data/services/api/java-meeting/java-message-scheduling/log.out" "$export_dir/java-message-scheduling_log.out" || true
copy_if_exists "/data/services/api/java-meeting/java-mqtt/log.out" "$export_dir/java-mqtt_log.out" || true
copy_if_exists "/data/services/api/java-meeting/java-quartz/log.out" "$export_dir/java-quartz_log.out" || true
copy_if_exists "/data/services/api/auth/auth-sso-auth/log.out" "$export_dir/auth-sso-auth_log.out" || true
copy_if_exists "/data/services/api/auth/auth-sso-gatway/log.out" "$export_dir/auth-sso-gatway_log.out" || true
copy_if_exists "/data/services/api/auth/auth-sso-system/log.out" "$export_dir/auth-sso-system_log.out" || true
# 2) 各模块统一日志(ps1:/data/services/logs/.../ubains-INFO-AND-ERROR.log)
copy_if_exists "/data/services/logs/auth-sso-auth/ubains-INFO-AND-ERROR.log" "$export_dir/auth-sso-auth_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/auth-sso-gatway/ubains-INFO-AND-ERROR.log" "$export_dir/auth-sso-gatway_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/auth-sso-system/ubains-INFO-AND-ERROR.log" "$export_dir/auth-sso-system_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/java-meeting2.0/ubains-INFO-AND-ERROR.log" "$export_dir/java-meeting2.0_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/java-meeting3.0/ubains-INFO-AND-ERROR.log" "$export_dir/java-meeting3.0_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/java-meeting-extapi/ubains-INFO-AND-ERROR.log" "$export_dir/java-meeting-extapi_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/java-message-scheduling/ubains-INFO-AND-ERROR.log" "$export_dir/java-message-scheduling_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/java-mqtt/ubains-INFO-AND-ERROR.log" "$export_dir/java-mqtt_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/data/services/logs/java-quartz/ubains-INFO-AND-ERROR.log" "$export_dir/java-quartz_ubains-INFO-AND-ERROR.log" || true
fi
# --------------------------
# Old 平台:补齐 ps1 的容器内 nginx error.log 导出(ujava/upython)
# 注:ps1 通过 docker cp 容器内 /var/log/nginx/error.log
# --------------------------
if [[ "$platform" == "old" ]]; then
if [[ "$has_ujava" -eq 1 ]]; then
copy_if_exists "/var/www/java/api-java-meeting2.0/logs/ubains-INFO-AND-ERROR.log" "$export_dir/对内后端_ubains-INFO-AND-ERROR.log" || true
copy_if_exists "/var/www/java/external-meeting-api/logs/ubains-INFO-AND-ERROR.log" "$export_dir/对外后端_ubains-INFO-AND-ERROR.log" || true
# 容器内 nginx error.log(ujava 容器)
copy_from_container_if_exists "$ujava_container" "/var/log/nginx/error.log" "$export_dir/ujava容器_nginx_error.log" || true
fi
if [[ "$has_upython" -eq 1 ]]; then
copy_if_exists "/var/www/html/log/error.log" "$export_dir/运维集控_error.log" || true
copy_if_exists "/var/www/html/log/uinfo.log" "$export_dir/运维集控_uinfo.log" || true
copy_if_exists "/var/www/html/log/uwsgi.log" "$export_dir/运维集控_uwsgi.log" || true
# 容器内 nginx error.log(upython 容器)
copy_from_container_if_exists "$upython_container" "/var/log/nginx/error.log" "$export_dir/upython容器_nginx_error.log" || true
fi
fi
if [[ "${#exported_files[@]}" -gt 0 ]]; then
report_kv_set "log_export.dir" "$export_dir"
report_kv_set "log_export.files" "$(printf "%s\n" "${exported_files[@]}")"
report_kv_set "log_export.count" "${#exported_files[@]}"
report_kv_set "log_export.status" "OK"
else
report_kv_set "log_export.dir" "$export_dir"
report_kv_set "log_export.files" ""
report_kv_set "log_export.count" "0"
report_kv_set "log_export.status" "WARN"
fi
log SUCCESS "日志导出目录: $export_dir"
echo "$export_dir"
}
# ------------------------------
# 19) 报告生成(Markdown)—增强:把 KV 也写入
# ------------------------------ # ------------------------------
write_report() { write_report() {
local server_ip="$1" local server_ip="$1"
...@@ -1461,7 +1578,7 @@ write_report() { ...@@ -1461,7 +1578,7 @@ write_report() {
done done
} }
w "<!-- REPORT_GENERATOR: sh-write_report-v4(unified) $(date '+%F %T') -->" w "<!-- REPORT_GENERATOR: sh-write_report-v5(align-ps1-summary) $(date '+%F %T') -->"
w "" w ""
w "# 服务自检报告" w "# 服务自检报告"
w "" w ""
...@@ -1470,8 +1587,47 @@ write_report() { ...@@ -1470,8 +1587,47 @@ write_report() {
w "- 检测时间: $(date '+%Y-%m-%d %H:%M:%S')" w "- 检测时间: $(date '+%Y-%m-%d %H:%M:%S')"
w "- 脚本版本: $SCRIPT_VERSION" w "- 脚本版本: $SCRIPT_VERSION"
w "" w ""
# ✅ 新增:将旧的 REPORT_LINES(摘要/过程性输出)写入报告,避免丢失 # ✅ 新增:PS1 风格总览统计(服务检测结果)
w "## 总览统计"
w ""
local svc_total=0 svc_ok=0 svc_fail=0
# 这里必须对 set -euo pipefail 友好:
# - grep 在无匹配时返回 1,会让 pipefail 下的命令替换失败
# - 用 grep -c 并加 || true,保证得到数字
local all_lines
all_lines="$(printf "%s\n" "${REPORT_LINES[@]}")"
svc_ok="$(grep -cE '\|running\b' <<<"$all_lines" 2>/dev/null || true)"
svc_fail="$(grep -cE '\|stopped\b' <<<"$all_lines" 2>/dev/null || true)"
# 强制数字兜底(避免空/多行)
[[ "$svc_ok" =~ ^[0-9]+$ ]] || svc_ok=0
[[ "$svc_fail" =~ ^[0-9]+$ ]] || svc_fail=0
svc_total=$((svc_ok + svc_fail))
w "- 服务条目总数: \`$svc_total\`"
w "- 运行中: \`$svc_ok\`"
w "- 异常/未运行: \`$svc_fail\`"
if [[ "$svc_total" -eq 0 ]]; then
w "- 结论: \`未检测到服务条目(可能未安装/未找到容器)\`"
elif [[ "$svc_fail" -eq 0 ]]; then
w "- 结论: \`所有检测到的服务均正常\`"
else
w "- 结论: \`存在异常服务,请查看“服务检测”详情\`"
fi
w ""
# ✅ 新增:备份结果摘要(点4)
w "## 备份/日志导出摘要"
w ""
w "- DataBackup: \`$(report_kv_get "bak.status")\` dir=\`$(report_kv_get "bak.dir")\` archive=\`$(report_kv_get "bak.archive")\`"
w "- LogExport: \`$(report_kv_get "log_export.status")\` count=\`$(report_kv_get "log_export.count")\` dir=\`$(report_kv_get "log_export.dir")\`"
w ""
# ✅ 原有:REPORT_LINES 写入(过程摘要)
if [[ "${#REPORT_LINES[@]}" -gt 0 ]]; then if [[ "${#REPORT_LINES[@]}" -gt 0 ]]; then
w "## 过程摘要(REPORT_LINES)" w "## 过程摘要(REPORT_LINES)"
w "" w ""
...@@ -1491,6 +1647,26 @@ write_report() { ...@@ -1491,6 +1647,26 @@ write_report() {
w '```' w '```'
w "" w ""
# ✅ 新增:日志导出文件清单(点4)
w "## 日志导出文件列表"
w ""
w "- export_dir: \`$(report_kv_get "log_export.dir")\`"
w "- count: \`$(report_kv_get "log_export.count")\`"
local le
le="$(report_kv_get "log_export.files")"
if [[ -n "$le" ]]; then
w ""
w "| 文件名 | 源路径 |"
w "|---|---|"
while IFS="|" read -r name src; do
[[ -z "$name" ]] && continue
w "| $name | $src |"
done <<<"$le"
else
w "- (未导出或无可用日志)"
fi
w ""
# ✅ 摘要:只放结论,不放长明细(避免重复、不易读) # ✅ 摘要:只放结论,不放长明细(避免重复、不易读)
w "## 检测结果摘要" w "## 检测结果摘要"
w "" w ""
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论