日志是脚本运行的重要记录,对于调试、审计、问题排查都非常有价值。良好的日志记录习惯能让脚本的维护和问题定位事半功倍。
最基本的日志就是 echo:
echo "开始执行任务"
echo "处理文件:$filename"
echo "任务完成"
echo "日志信息" >> app.log
echo "$(date) - 日志信息" >> app.log
封装日志函数,统一格式:
log() {
local level=$1
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message"
}
log "INFO" "开始执行"
log "ERROR" "文件不存在:$file"
log "DEBUG" "变量值:$var"
#!/bin/bash
LOG_LEVEL=${LOG_LEVEL:-INFO}
LEVEL_DEBUG=0
LEVEL_INFO=1
LEVEL_WARN=2
LEVEL_ERROR=3
log() {
local level=$1
shift
local message="$*"
local current_level
case $level in
DEBUG) current_level=$LEVEL_DEBUG ;;
INFO) current_level=$LEVEL_INFO ;;
WARN) current_level=$LEVEL_WARN ;;
ERROR) current_level=$LEVEL_ERROR ;;
esac
local threshold_level
case $LOG_LEVEL in
DEBUG) threshold_level=$LEVEL_DEBUG ;;
INFO) threshold_level=$LEVEL_INFO ;;
WARN) threshold_level=$LEVEL_WARN ;;
ERROR) threshold_level=$LEVEL_ERROR ;;
esac
if [ $current_level -ge $threshold_level ]; then
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message"
fi
}
log "DEBUG" "调试信息"
log "INFO" "普通信息"
log "WARN" "警告信息"
log "ERROR" "错误信息"
设置日志级别:
LOG_LEVEL=DEBUG ./script.sh
log() {
local message="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
echo "$message" | tee -a app.log
}
log_error() {
echo "[ERROR] $*" >&2
}
#!/bin/bash
LOG_FILE="app.log"
exec 1> >(tee -a "$LOG_FILE")
exec 2>&1
echo "这行会同时输出到屏幕和文件"
echo "错误信息也会被记录"
logger 命令可以把日志写入系统日志:
logger "脚本执行完成"
logger -t myscript "自定义标签"
logger -p local0.info "指定 facility 和级别"
查看日志:
tail -f /var/log/syslog
journalctl -t myscript
长时间运行的脚本需要考虑日志轮转:
rotate_log() {
local log_file=$1
local max_size=${2:-10485760} # 默认 10MB
local max_files=${3:-5}
if [ -f "$log_file" ]; then
local size=$(stat -c%s "$log_file")
if [ $size -gt $max_size ]; then
for i in $(seq $((max_files - 1)) -1 1); do
[ -f "${log_file}.${i}" ] && mv "${log_file}.${i}" "${log_file}.$((i + 1))"
done
mv "$log_file" "${log_file}.1"
fi
fi
}
log() {
local log_file="app_$(date '+%Y%m%d').log"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] $*" >> "$log_file"
}
创建配置文件 /etc/logrotate.d/myapp:
/var/log/myapp/*.log {
daily
rotate 7
compress
missingok
notifempty
create 0644 user group
}
输出 JSON 格式的日志:
log_json() {
local level=$1
shift
local message="$*"
cat << EOF
{"timestamp":"$(date -Iseconds)","level":"$level","message":"$message","script":"$(basename $0)"}
EOF
}
log_json "INFO" "开始执行"
输出:
{"timestamp":"2024-03-15T10:00:00+08:00","level":"INFO","message":"开始执行","script":"script.sh"}
#!/bin/bash
LOG_FILE=${LOG_FILE:-"/var/log/myapp/app.log"}
LOG_LEVEL=${LOG_LEVEL:-INFO}
LOG_MAX_SIZE=${LOG_MAX_SIZE:-10485760}
LOG_MAX_FILES=${LOG_MAX_FILES:-5}
init_log() {
local log_dir=$(dirname "$LOG_FILE")
mkdir -p "$log_dir"
rotate_log
}
rotate_log() {
if [ -f "$LOG_FILE" ]; then
local size=$(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)
if [ $size -gt $LOG_MAX_SIZE ]; then
for i in $(seq $((LOG_MAX_FILES - 1)) -1 1); do
[ -f "${LOG_FILE}.${i}" ] && mv "${LOG_FILE}.${i}" "${LOG_FILE}.$((i + 1))"
done
mv "$LOG_FILE" "${LOG_FILE}.1"
fi
fi
}
log() {
local level=$1
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local log_line="[$timestamp] [$level] $$ $message"
case $level in
ERROR|WARN)
echo "$log_line" >&2
;;
*)
echo "$log_line"
;;
esac
echo "$log_line" >> "$LOG_FILE"
}
log_info() { log "INFO" "$@"; }
log_warn() { log "WARN" "$@"; }
log_error() { log "ERROR" "$@"; }
log_debug() { log "DEBUG" "$@"; }
# 使用
init_log
log_info "脚本开始执行"
log_error "发生错误"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $*"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
}