1. Shell脚本日志记录的核心价值
在生产环境中,Shell脚本的日志记录质量直接决定了运维效率。我曾经历过一次惨痛的教训:某凌晨3点自动化备份脚本失败,由于缺乏有效日志,团队花了6小时才定位到是一个权限配置问题。自此我系统性地重构了所有脚本的日志模块,总结出一套可复用的最佳实践。
良好的日志系统需要实现三个核心目标:
- 问题可追溯:能清晰还原脚本执行路径和关键变量状态
- 错误可诊断:包含足够的上下文信息帮助快速定位根因
- 行为可审计:满足合规要求,记录关键操作的执行者和时间戳
2. 基础日志框架设计
2.1 日志分级策略
采用Syslog标准的8级日志分类(从0-7),但实践中可简化为4个实用级别:
bash复制LOG_LEVEL_DEBUG=3
LOG_LEVEL_INFO=2
LOG_LEVEL_WARNING=1
LOG_LEVEL_ERROR=0
在脚本开头通过全局变量控制输出级别:
bash复制CURRENT_LOG_LEVEL=$LOG_LEVEL_INFO # 生产环境通常设为INFO
2.2 日志函数封装
基础日志函数应包含以下要素:
bash复制log() {
local level=$1
local message=$2
local timestamp=$(date "+%Y-%m-%d %H:%M:%S.%3N")
[ $level -ge $CURRENT_LOG_LEVEL ] && \
echo "[${timestamp}] [${HOSTNAME}] [$$] [$(whoami)] [${level}] ${message}" >> ${LOG_FILE}
}
关键字段说明:
- %3N:精确到毫秒的时间戳,对于并发脚本排查至关重要
- $$:当前进程ID,区分并行执行的脚本实例
- whoami:执行用户,满足审计要求
3. 高级日志技巧
3.1 动态日志路径管理
为避免日志文件膨胀,建议采用按天滚动策略:
bash复制LOG_DIR="/var/log/$(basename $0 .sh)"
mkdir -p ${LOG_DIR}
LOG_FILE="${LOG_DIR}/$(date +%Y%m%d).log"
3.2 关键操作审计日志
对于敏感操作(如文件删除、权限变更),应记录操作前后的完整状态:
bash复制audit_delete() {
local file=$1
local checksum=$(sha256sum "$file")
log $LOG_LEVEL_INFO "DELETE AUDIT START: ${file} (${checksum})"
# 实际删除操作
rm -f "$file"
local status=$?
[ $status -eq 0 ] && \
log $LOG_LEVEL_INFO "DELETE AUDIT SUCCESS: ${file}" || \
log $LOG_LEVEL_ERROR "DELETE AUDIT FAILED: ${file} (code:${status})"
return $status
}
3.3 彩色终端输出
当脚本在终端运行时,可通过ANSI颜色码增强可读性:
bash复制[ -t 1 ] && {
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
error() { echo -e "${RED}[ERROR]${NC} $*"; }
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
}
4. 日志分析工具链
4.1 实时监控方案
使用tail结合grep实现关键错误监控:
bash复制tail -F ${LOG_FILE} | grep --line-buffered '\[ERROR\]' | \
while read line; do
send_alert "[URGENT] Script Error: $line"
done
4.2 日志分析脚本
生成每日执行报告示例:
bash复制analyze_log() {
local log_file=$1
echo "==== Execution Report $(date -d @$(stat -c %Y "$log_file") +%F) ===="
grep -c '\[INFO\]' "$log_file" | awk '{print "Success operations:", $1}'
grep -c '\[ERROR\]' "$log_file" | awk '{print "Failed operations:", $1}'
grep 'CPU' "$log_file" | tail -1 | awk '{print "Last CPU load:", $NF}'
}
5. 性能优化技巧
5.1 缓冲写入优化
高频日志写入时,使用缓冲提升性能:
bash复制exec 3>>${LOG_FILE}
log() {
# ...原有逻辑...
echo "[${timestamp}] ..." >&3
}
# 脚本结束时关闭
exec 3>&-
5.2 异步日志处理
对于性能敏感场景,可采用后台进程处理日志:
bash复制mkfifo /tmp/logpipe
cat /tmp/logpipe >> ${LOG_FILE} &
exec 3>/tmp/logpipe
log() {
echo "[$(date)] $*" >&3
}
6. 典型问题排查指南
6.1 日志不落盘问题
现象:日志内容未及时写入文件
排查步骤:
- 检查文件描述符状态:
ls -l /proc/$$/fd/ - 确认磁盘空间:
df -h ${LOG_DIR%/*} - 测试直接写入:
echo "test" >> ${LOG_FILE}
6.2 日志权限问题
推荐的安全权限配置:
bash复制chmod 640 ${LOG_FILE}
chown root:adm ${LOG_FILE}
7. 企业级实践建议
-
日志规范:
- 所有超过100行的脚本必须包含日志模块
- 关键函数入口/出口必须打日志
- 错误处理必须记录错误码和上下文
-
日志保留策略:
bash复制# 保留最近30天日志 find ${LOG_DIR} -name "*.log" -mtime +30 -exec rm {} \; -
集中式日志管理:
- 使用rsyslog转发关键日志到中央服务器
- 重要操作日志写入系统日志:
logger -t "script_audit" "$message"