Shell脚本如何实现日志记录

wen 实用脚本 1

本文目录导读:

Shell脚本如何实现日志记录

  1. 最简单的重定向方式
  2. 使用函数封装日志
  3. 完整的日志系统实现
  4. 使用 logger 命令(系统日志)
  5. 彩色日志输出(同时记录文件和终端)
  6. 使用建议

最简单的重定向方式

#!/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" "服务异常终止"

使用建议

  1. 选择日志方式

    • 简单脚本使用 exec > log.txt 2>&1
    • 中等复杂度使用日志函数封装
    • 生产环境使用完整日志系统
  2. 规范

    • 始终包含时间戳
    • 记录日志级别和来源
    • 包含足够的上下文信息
  3. 日志管理

    • 设置日志轮转机制
    • 控制日志文件大小
    • 定期清理旧日志
  4. 安全考虑

    • 避免记录敏感信息(密码、密钥等)
    • 设置合适的文件权限
    • 考虑日志存储位置的安全性

根据你的具体需求选择合适的日志实现方式即可。

抱歉,评论功能暂时关闭!