本文目录导读:

最简单的重定向方式
#!/bin/bash # 将标准输出和错误输出重定向到日志文件 exec > script.log 2>&1 echo "脚本开始执行" ls /nonexistent # 这条命令会报错 echo "脚本执行完毕"
使用函数封装日志
#!/bin/bash
LOG_FILE="app.log"
# 日志函数,包含时间戳和日志级别
log() {
local level="$1"
local message="$2"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
# 使用示例
log "INFO" "脚本开始运行"
log "WARN" "配置文件未找到,使用默认配置"
log "ERROR" "数据库连接失败"
# 执行一些操作
ls /etc/ 2>> "$LOG_FILE" # 将错误也追加到日志
完整的日志系统实现
#!/bin/bash
# 日志配置
LOG_DIR="/var/log/myapp"
LOG_FILE="${LOG_DIR}/$(date +%Y%m%d).log"
LOG_LEVEL="DEBUG" # DEBUG, INFO, WARN, ERROR
MAX_LOG_SIZE=10485760 # 10MB
LOG_RETENTION_DAYS=30
# 确保日志目录存在
mkdir -p "$LOG_DIR"
# 日志级别定义(数值越大越严重)
declare -A LOG_LEVELS=(
["DEBUG"]=0
["INFO"]=1
["WARN"]=2
["ERROR"]=3
)
# 日志函数
log() {
local level="$1"
local message="$2"
local script_name=$(basename "$0")
local function_name="${FUNCNAME[1]:-main}"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
local pid=$$
# 检查日志级别
if [[ ${LOG_LEVELS[$level]} -lt ${LOG_LEVELS[$LOG_LEVEL]} ]]; then
return
fi
# 生成日志行
local log_entry="[$timestamp] [$level] [PID:$pid] [$script_name:$function_name] $message"
# 写入日志文件
echo "$log_entry" >> "$LOG_FILE"
# 错误级别同时输出到标准错误
if [[ "$level" == "ERROR" ]]; then
echo "$log_entry" >&2
fi
# 检查日志文件大小
check_log_size
# 清理旧日志
clean_old_logs
}
# 检查日志文件大小,超过限制时轮转
check_log_size() {
if [[ -f "$LOG_FILE" ]] && [[ $(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null) -gt $MAX_LOG_SIZE ]]; then
rotate_log
fi
}
# 日志轮转
rotate_log() {
local backup_file="${LOG_FILE}.$(date +%H%M%S)"
mv "$LOG_FILE" "$backup_file"
touch "$LOG_FILE"
log "INFO" "日志文件已轮转: $backup_file"
# 压缩旧日志
gzip "$backup_file" 2>/dev/null
}
# 清理旧日志
clean_old_logs() {
find "$LOG_DIR" -name "*.log.*.gz" -mtime +$LOG_RETENTION_DAYS -delete 2>/dev/null
find "$LOG_DIR" -name "*.log.*" -mtime +$LOG_RETENTION_DAYS ! -name "*.gz" -delete 2>/dev/null
}
# 执行命令并记录输出
run_with_log() {
local command="$@"
local output_file="/tmp/command_output.$$"
log "DEBUG" "执行命令: $command"
# 执行命令并捕获输出
eval "$command" > "$output_file" 2>&1
local exit_code=$?
# 记录命令输出
if [[ -s "$output_file" ]]; then
log "DEBUG" "命令输出: $(tr '\n' ' ' < "$output_file")"
fi
# 根据退出码记录日志
if [[ $exit_code -eq 0 ]]; then
log "INFO" "命令执行成功: $command"
else
log "ERROR" "命令执行失败(退出码:$exit_code): $command"
log "ERROR" "错误输出: $(tr '\n' ' ' < "$output_file")"
fi
rm -f "$output_file"
return $exit_code
}
# 使用示例
main() {
log "INFO" "应用程序启动"
# 设置日志级别为INFO(不记录DEBUG级别的日志)
LOG_LEVEL="INFO"
# 记录不同级别的日志
log "DEBUG" "这是调试信息" # 不会记录
log "INFO" "配置加载完成"
log "WARN" "磁盘空间不足,剩余${disk_space}GB"
# 执行命令并记录
run_with_log "ls /tmp"
run_with_log "cat /nonexistent/file"
log "INFO" "应用程序结束"
}
main "$@"
使用 logger 命令(系统日志)
#!/bin/bash
# 使用系统日志
log_to_syslog() {
local message="$1"
local priority="${2:-user.info}"
logger -p "$priority" -t "$(basename $0)[$$]" "$message"
}
# 使用示例
log_to_syslog "用户登录成功"
log_to_syslog "磁盘空间不足" "user.warning"
log_to_syslog "内存溢出" "user.err"
彩色日志输出(同时记录文件和终端)
#!/bin/bash
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
LOG_FILE="app.log"
log() {
local level="$1"
local message="$2"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
# 选择颜色
local color="$NC"
case "$level" in
INFO) color="$GREEN" ;;
WARN) color="$YELLOW" ;;
ERROR) color="$RED" ;;
DEBUG) color="$BLUE" ;;
esac
# 终端输出(带颜色)
echo -e "${color}[$timestamp] [$level] $message${NC}"
# 文件输出(无颜色)
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
}
# 使用示例
log "INFO" "系统正常运行"
log "WARN" "配置未优化"
log "ERROR" "服务异常终止"
使用建议
-
选择日志方式:
- 简单脚本使用
exec > log.txt 2>&1 - 中等复杂度使用日志函数封装
- 生产环境使用完整日志系统
- 简单脚本使用
-
规范:
- 始终包含时间戳
- 记录日志级别和来源
- 包含足够的上下文信息
-
日志管理:
- 设置日志轮转机制
- 控制日志文件大小
- 定期清理旧日志
-
安全考虑:
- 避免记录敏感信息(密码、密钥等)
- 设置合适的文件权限
- 考虑日志存储位置的安全性
根据你的具体需求选择合适的日志实现方式即可。