在现代系统管理中,日志文件的处理与管理是确保系统稳定性和高效运维的重要任务之一。尤其是在多容器环境下,由于日志文件结构的不统一和数量庞大,如何有效进行日志的老化处理、备份和清理成为了一个亟待解决的问题。本文介绍了一个名为 clearlogs.sh
的脚本,旨在自动化处理和清理指定目录下的日志文件。脚本通过定期备份超过七天未修改的日志文件,打包存档并管理其生命周期,同时确保备份文件不超过一个月,避免日志文件占用过多存储空间。此外,脚本还提供了针对日志清理的详细操作,帮助运维人员有效控制系统存储,确保日志管理的高效性与安全性。
一、功能介绍
将某一目录下的所有日志进行老化处理,这些日志是来自于其他容器的外挂日志,由于各个容器内的日志安排不同,所以结构不统一.
(一)具体案例背景
- 所有容器下的日志会外挂到/home/log下,我们处理这个目录下的日志就可以;
- /home/log下的结构按外挂容器名和具体日志有如下结构,只是举例,列举部分容器的外挂
(二)具体要求说明
现在要求日志老化,具体要求如下:
- 将以上具体某个日志下的日志已保留了七天的统一打包到一个目录下,该目录的名称和原来的目录名称基本对应,以保证在看其备份日志时,可以方便查找;
- 上面打包以后采用直接move操作来转移到新目录下;
- 在新的统一目录下,要求所有的tar包都只保留一个月,一个月后自动清除。
二、部分注意指令
(一)find 目录 -maxdepth 1 -ctime +7 -type f
功能:查找指定目录下超过7天未修改的文件。
详解:find
命令用于搜索文件系统中符合特定条件的文件和目录。这条命令通过 -maxdepth 1
限制查找深度为当前目录,-ctime +7
指定文件的修改时间超过7天,-type f
表示查找的是普通文件而非目录或其他类型的文件。
(二)复杂判断思考
if [[ " "x != ${NOT_INCLUDE}x ]] && [[ -n "find ${targetdir} -maxdepth 1 -type f | grep -v 'gz$'
" ]]:
功能:在复杂判断条件中使用改进的条件语句以避免兼容性问题。
详解:[[ ... ]]
是 Bash shell 中的条件判断语句," "x != ${NOT_INCLUDE}x
判断变量 ${NOT_INCLUDE}
是否为空,避免了字符串比较时可能出现的问题。第二个条件是判断目标目录 ${targetdir}
中是否存在非以 .gz
结尾的普通文件,通过 find
结合 grep -v 'gz$'
实现。
(三)tar --warning=no-file-changed
功能:在使用 tar
命令打包时,禁止出现常见的文件未改变的警告。
详解:--warning=no-file-changed
参数告诉 tar
命令在打包时忽略任何文件未改变的警告信息,这通常用于在自动化备份和脚本执行中避免不必要的干扰和输出。
(四)tar --exclude=文件
功能:使用 tar
命令排除指定文件或目录,避免备份中包含不需要的内容。
详解:正确使用 --exclude=文件
参数可以确保 tar
命令在打包时排除指定的文件或目录,而不会因为语法问题造成兼容性错误。
(五)tar --zpcP
功能:
-p
:保留备份数据的原本权限和属性,适用于需要完整保留文件权限的场景,如重要的配置文件备份。-P
:保留绝对路径,允许备份数据中含有根目录存在之意,适用于需要保持文件层次结构完整性的情况。
详解:这些选项在 tar
命令中控制备份文件时的权限和路径行为,确保备份和恢复的准确性和完整性。合理选择 -p
或 -P
可根据具体需求保证备份数据的恢复效果符合预期。
通过了解和正确使用这些指令和参数,可以有效提高系统管理和数据备份的效率和安全性,避免常见的兼容性问题和错误用法带来的风险。
三、具体代码和说明
(一)代码展示
#!/bin/bash
#Program:
#History: 2018.11.20 zyf
#Common constant
NOWTIME=`date +"%Y%m%d%H%M%S"`
LOG_PATH=/home/log
LOG_BACKUP_PATH=/home/backuplog
LOG_TEMPFILE_PATH=/home/logtemp
LOG_TEMPFILE1=${LOG_TEMPFILE_PATH}/temp.dat
LOG_TEMPFILE2=${LOG_TEMPFILE_PATH}/clearlog-${NOWTIME}.dat
LOG_TEMPFILE3=${LOG_TEMPFILE_PATH}/firsttarfiles.dat
#print timestamp
getTimeStamp()
{
echo `date +"%Y-%m-%d %H:%M:%S"`
}
mkdir_clearlog()
{
if [ ! -f "${LOG_TEMPFILE2}" ]; then
log "mkdir_clearlog touch ${LOG_TEMPFILE2}..."
touch ${LOG_TEMPFILE2}
fi
}
#print log for analyzing
log()
{
echo " $1"
echo "`getTimeStamp` : $1" >> ${LOG_TEMPFILE2}
}
errlog()
{
echo "[ERROR:] $1"
echo "`getTimeStamp` : [ERROR:] $1" >> ${LOG_TEMPFILE2}
}
abnormalexit()
{
errlog "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
errlog "@@@@@@@@ !!! FAILED !!! @@@@@@@"
errlog "@@@@@ CLEARLOGS OPERATE FAILED!! @@@@@@"
errlog "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
exit 1
}
function cmdlog()
{
cmd=$1
log "$cmd"
`$cmd`
if [ $? -ne 0 ]
then
errlog "$cmd"
abnormalexit
fi
}
#scan all subdirectories of the current directory
#and make the corresponding directories in the specified directory,
#then mv required files in sourcedir to targetdir and make new tar
mkdir_and_deallog()
{
if [ ! -d ${LOG_TEMPFILE_PATH} ]; then
mkdir -p ${LOG_TEMPFILE_PATH}
elif [ ! -f "${LOG_TEMPFILE1}" ]; then
log "mkdir_and_deallog() touch LOG_TEMPFILE1..."
touch ${LOG_TEMPFILE1}
else
cat /dev/null > ${LOG_TEMPFILE1}
fi
find ${LOG_PATH} -maxdepth 15 -type d >> ${LOG_TEMPFILE1}
for line in `cat ${LOG_TEMPFILE1}`
do
CURRENT_DIR=`echo ${line} | cut -d '/' -f 4-`
if [ -n "${CURRENT_DIR}" ]; then
CORRESPOND_DIR=${LOG_BACKUP_PATH}/${CURRENT_DIR}
if [ ! -d ${CORRESPOND_DIR} ]; then
log "mkdir_and_deallog mkdir -p ${CORRESPOND_DIR}"
mkdir -p ${CORRESPOND_DIR}
fi
deal_required_logs "${CORRESPOND_DIR}" "${LOG_PATH}/${CURRENT_DIR}"
fi
done
}
#mv required files in sourcedir to targetdir and make new tar
deal_required_logs()
{
targetdir=$1
sourcedir=$2
#view sourcedir log files and mv
log "=========================================================="
log "deal_required_logs start, and now executing in ${sourcedir}..."
log "=========================================================="
for file in `find ${sourcedir} -maxdepth 1 -ctime +7 -type f`
do
log "deal_required_logs ${file} in ${sourcedir} created over 7 days"
if [ -n "${file}" ] && [ ! -n "`lsof ${file}`" ]; then
cmdlog "cp ${file} ${targetdir}"
fi
done
#tar targetdir
log "=========================================================="
log "cp-execute end, and now executing in ${targetdir}..."
log "=========================================================="
NOT_INCLUDE=" "
for file in `find ${targetdir} -maxdepth 1 -type f | grep 'gz$'`
do
if [ -n "${file}" ]; then
NOT_INCLUDE=${NOT_INCLUDE}" --exclude="${file}" "
fi
done
log "deal_required_logs() set files that not-including, NOT_INCLUDE=${NOT_INCLUDE}......"
if [[ " "x == ${NOT_INCLUDE}x ]]; then
log "start firsttarfile_targetdir : firsttarfile_targetdir ${targetdir}"
firsttarfile_targetdir ${targetdir}
elif [[ " "x != ${NOT_INCLUDE}x ]] && [[ -n "`find ${targetdir} -maxdepth 1 -type f | grep -v 'gz$'`" ]]; then
log "tar --zpcP -f ${targetdir}/${NOWTIME}.tar.gz ${NOT_INCLUDE} ${targetdir}"
tar --warning=no-file-changed -zpcP -f ${targetdir}/${NOWTIME}.tar.gz ${NOT_INCLUDE} ${targetdir}
fi
}
firsttarfile_targetdir()
{
targetdir=$1
if [ ! -f "${LOG_TEMPFILE3}" ]; then
log "firsttarfile_targetdir() touch LOG_TEMPFILE3..."
touch ${LOG_TEMPFILE3}
fi
find ${targetdir} -maxdepth 1 -type f >> ${LOG_TEMPFILE3}
FIRST_TAR_FILES=" "
for line in `cat ${LOG_TEMPFILE3}`
do
if [[ " "x != ${line}x ]]; then
FIRST_TAR_FILES=${FIRST_TAR_FILES}" "${line}
fi
done
log "firsttarfile_targetdir : FIRST_TAR_FILES=${FIRST_TAR_FILES}"
if [[ " "x != ${FIRST_TAR_FILES}x ]]; then
log "tar --warning=no-file-changed -zpcP -f ${targetdir}/${NOWTIME}0.tar.gz ${FIRST_TAR_FILES}"
tar --warning=no-file-changed -zpcP -f ${targetdir}/${NOWTIME}0.tar.gz ${FIRST_TAR_FILES}
fi
rm ${LOG_TEMPFILE3}
}
clear_overtime_files()
{
log "clear_overtime_files rm tar.gz that save more than 30 days......"
find ${LOG_BACKUP_PATH} -mtime +30 -name "*.tar.gz" -exec rm -rf {} \;
log "clear_overtime_files rm temp files that save more than 2 days......"
find ${LOG_TEMPFILE_PATH} -mtime +2 -name "*.log" -exec rm -rf {} \;
log "clear_overtime_files rm extra files in /home/backuplog......"
find /home/backuplog -type f -not -name '*gz' -print0 | xargs -0 -I {} rm -v {}
}
###############main##############
cd ${LOG_PATH}
mkdir_clearlog
log "clearlogs.sh start..."
mkdir_and_deallog
clear_overtime_files
log "clearlogs.sh end..."
log "[~CLEARLOGS OPERATE SUCCESS~]"
(二)具体功能说明
脚本 clearlogs.sh
主要用于日志文件的管理和清理:
- getTimeStamp():获取当前时间戳的函数,用于日志记录。
- mkdir_clearlog():创建临时文件和目录,确保后续操作正常进行。
- log() 和 errlog():记录普通日志和错误日志,并将其输出到指定的日志文件
${LOG_TEMPFILE2}
。 - abnormalexit():异常退出函数,用于在操作失败时记录错误信息并终止脚本执行。
- cmdlog():执行命令并记录执行日志,如果命令执行失败则调用
errlog()
记录错误并异常退出。 - mkdir_and_deallog():扫描指定目录下的子目录,创建对应的备份目录并处理需要备份的日志文件。
- deal_required_logs():移动超过7天未修改的日志文件到指定目录,并将其打包成
tar.gz
文件。 - firsttarfile_targetdir():对目标目录下的文件进行首次打包处理,以保证备份的完整性和准确性。
- clear_overtime_files():清理超过一定时间的备份文件和临时文件,确保系统空间的有效管理。
整个脚本通过多个函数实现了日志文件的备份和清理,保证了系统资源的有效利用和日志数据的安全性。
四、总结
通过本文的介绍,我们了解了如何使用 clearlogs.sh
脚本来高效管理和清理日志文件。脚本通过多种功能实现了对日志文件的老化处理、打包存档和清理,确保了系统存储的有效利用。具体来说,脚本能够:
- 自动扫描指定目录下的日志文件,并对超过七天未修改的文件进行备份处理。
- 对备份的日志文件进行打包存档,且每月自动清理过期的备份文件,避免磁盘空间被长期占用。
- 在处理日志文件时,脚本能够记录详细的操作日志,确保操作的透明性和可追溯性。
- 采用条件判断和错误处理机制,确保在遇到问题时能够及时发现并中止操作,避免系统出现不可预期的错误。
这个脚本在多容器环境下尤其有用,它能够统一处理各个容器的日志文件,并通过自动化的方式减轻运维人员的工作负担。通过合理配置和使用该脚本,能够大大提高日志文件管理的效率,降低系统资源浪费,为企业或开发团队的系统运维提供了坚实的保障。