5.5.1 日志设计与分级规范
日志设计与分级规范#
日志是脚本可观测性的基础,应围绕“可读、可搜、可关联、可追溯”设计。本节从规范、落地实现、排错与练习四个角度给出可执行方案。
1. 原理草图:日志从脚本到平台#
2. 日志设计原则(带示例)#
- 结构化:字段固定、顺序统一
示例(键值对):
ts=2024-06-10 10:20:33 level=INFO host=node01 script=backup.sh func=main trace=job-20240610 msg="backup start" - 上下文完整:包含时间、主机、脚本名、函数名、任务标识、耗时
- 可关联:引入
TRACE_ID/JOB_ID贯穿多步骤 - 可过滤:按级别筛选
示例:只看错误
bash grep 'level=ERROR' /var/log/app/task.log - 可持久:关键操作和错误必须落盘,调试日志可开关
3. 日志分级规范(五级)#
- DEBUG:调试信息,如变量值、外部命令输出
- INFO:正常流程信息
- WARN:可恢复问题(重试/降级)
- ERROR:失败但可继续
- FATAL:致命错误并退出
4. 标准日志格式#
推荐统一格式(可读 & 可解析):
ts=<time> level=<LEVEL> host=<host> script=<script> func=<func> trace=<id> msg="<text>"
示例:
ts=2024-06-10 10:20:33 level=INFO host=node01 script=backup.sh func=dump_db trace=job-20240610 msg="backup start"
5. Shell 实现(可执行完整示例)#
文件:/opt/scripts/backup.sh
#!/usr/bin/env bash
set -o pipefail
LOG_FILE="/var/log/app/task.log"
DEBUG="${DEBUG:-0}"
TRACE_ID="${TRACE_ID:-job-$(date +%Y%m%d%H%M%S)}"
log() {
local level="$1"; shift
local msg="$*"
local ts
ts=$(date "+%Y-%m-%d %H:%M:%S")
local line="ts=${ts} level=${level} host=${HOSTNAME} script=${0##*/} func=${FUNCNAME[1]:-main} trace=${TRACE_ID} msg=\"${msg}\""
# 同时输出到控制台与文件;ERROR/FATAL走stderr
if [[ "$level" == "ERROR" || "$level" == "FATAL" ]]; then
echo "$line" | tee -a "$LOG_FILE" >&2
else
echo "$line" | tee -a "$LOG_FILE"
fi
}
debug() { [[ "$DEBUG" == "1" ]] && log DEBUG "$*"; }
info() { log INFO "$*"; }
warn() { log WARN "$*"; }
error() { log ERROR "$*"; }
fatal() { log FATAL "$*"; exit 1; }
dump_db() {
local start end cost
start=$(date +%s)
info "start dump"
mysqldump -uroot -p'pass' testdb >/tmp/testdb.sql 2>/tmp/mysqldump.err
if [[ $? -ne 0 ]]; then
error "mysqldump failed, err=$(tail -n1 /tmp/mysqldump.err)"
return 1
fi
end=$(date +%s); cost=$((end - start))
info "dump success cost=${cost}s"
}
main() {
info "backup job start"
dump_db || warn "dump_db failed but continue"
info "backup job end"
}
main "$@"
运行示例:
mkdir -p /var/log/app
chmod +x /opt/scripts/backup.sh
DEBUG=1 TRACE_ID=job-20240610 /opt/scripts/backup.sh
预期日志(节选):
ts=2024-06-10 10:20:33 level=INFO host=node01 script=backup.sh func=main trace=job-20240610 msg="backup job start"
ts=2024-06-10 10:20:33 level=INFO host=node01 script=backup.sh func=dump_db trace=job-20240610 msg="start dump"
ts=2024-06-10 10:20:34 level=ERROR host=node01 script=backup.sh func=dump_db trace=job-20240610 msg="mysqldump failed, err=Access denied"
6. 与系统日志联动(logger 示例)#
将日志同时写入 syslog:
logger -t backup.sh "level=INFO trace=${TRACE_ID} msg=backup start"
查看:
journalctl -t backup.sh -n 20
7. 常见排错#
- 日志文件为空
检查权限与路径:
bash ls -l /var/log/app/task.log id - 只在屏幕不落盘
确认tee -a和LOG_FILE变量是否正确 - TRACE_ID 未生效
检查脚本开头是否设置:
bash echo "$TRACE_ID"
8. 练习#
- 增加
elapsed_ms字段,记录外部命令耗时(毫秒)。 - 增加
LOG_LEVEL参数,支持只输出INFO及以上。 - 将
ERROR/FATAL日志单独写入/var/log/app/task.err。