使用tee(或同等功能),但限制最大文件大小或旋转到新文件



我想捕获UNIX进程的输出,但限制最大文件大小和/或旋转到一个新文件。

我见过logrotate,但它不能实时工作。根据我的理解,这是一个并行运行的"清理"工作。

正确的解决方案是什么?我想我会写一个小脚本来做这件事,但我希望有一个简单的方法与现有的文本工具。

想象:

my_program | tee——max-bytes 100000 log/my_program_log

会给…总是将最新的日志文件写为:日志/my_program_log

然后,当它填充…

重命名为log/my_program_log000001,并开始一个新的日志/my_program_log。

use split:

my_program | tee >(split -d -b 100000 -)

或者,如果你不想看到输出,你可以直接管道分割:

my_program | split -d -b 100000 -

至于日志旋转,coretils中没有自动完成它的工具。您可以创建一个符号链接,并使用bash命令定期更新它:

while ((1)); do ln -fns target_log_name $(ls -t | head -1); sleep 1; done

apache2-utils包中有一个名为rotatelogs的实用程序,它完全满足您的要求。

剧情简介:

rotatelogs [- l] [- l 链接名] [p 程序][f] [t] [v] [e] [c] [n 文件数量)日志文件 rotationtime | 文件大小 (B K | | | G) (抵消)

的例子:

your_program | rotatelogs -n 5 /var/log/logfile 1M

您可以在这个链接上阅读完整的手册

或者使用awk

program | awk 'BEGIN{max=100} {n+=length($0); print $0 > "log."int(n/max)}'

它将行放在一起,所以最大值不是精确的,但这对于日志目的来说可能很好。您可以使用awk的sprintf来格式化文件名。

下面是一个可执行的脚本,使用awk
#!/bin/bash
maxb=$((1024*1024))    # default 1MiB
out="log"              # output file name
width=3                # width: log.001, log.002
while getopts "b:o:w:" opt; do
  case $opt in
    b ) maxb=$OPTARG;;
    o ) out="$OPTARG";;
    w ) width=$OPTARG;;
    * ) echo "Unimplented option."; exit 1
  esac
done
shift $(($OPTIND-1))
IFS='n'              # keep leading whitespaces
if [ $# -ge 1 ]; then # read from file
  cat $1
else                  # read from pipe
  while read arg; do
    echo $arg
  done
fi | awk -v b=$maxb -v o="$out" -v w=$width '{
    n+=length($0); print $0 > sprintf("%s.%0.*d",o,w,n/b)}'

保存到一个名为'bee'的文件中,运行' chmod +x bee ',你可以使用它作为

program | bee

或将现有文件分割为

bee -b1000 -o proglog -w8 file

要将大小限制为100字节,只需使用dd:

my_program | dd bs=1 count=100 > log

当写入100字节时,dd将关闭管道,my_program接收EPIPE。

解决这个问题最直接的方法可能是使用python和专门为此目的设计的日志模块。创建一个从stdin读取并写入stdout的脚本,并实现下面描述的日志轮换。

"logging"模块提供了

class logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0,
              backupCount=0, encoding=None, delay=0)

做的正是你想要的。

您可以使用maxBytes和backupCount值来允许文件以预定的大小滚动。

从docs.python.org

有时您想让日志文件增长到一定大小,然后打开一个新文件并记录该文件。您可能希望保留一定数量的这些文件,并且当创建了那么多文件时,请旋转这些文件,以便文件的数量和文件的大小都保持有限。对于这种使用模式,日志包提供了一个RotatingFileHandler:

import glob
import logging
import logging.handlers
LOG_FILENAME = 'logging_rotatingfile_example.out'
# Set up a specific logger with our desired output level
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)
# Add the log message handler to the logger
handler = logging.handlers.RotatingFileHandler(
              LOG_FILENAME, maxBytes=20, backupCount=5)
my_logger.addHandler(handler)
# Log some messages
for i in range(20):
    my_logger.debug('i = %d' % i)
# See what files are created
logfiles = glob.glob('%s*' % LOG_FILENAME)
for filename in logfiles:
    print(filename)

结果应该是6个单独的文件,每个文件都包含应用程序的部分日志历史记录:

logging_rotatingfile_example.out
logging_rotatingfile_example.out.1
logging_rotatingfile_example.out.2
logging_rotatingfile_example.out.3
logging_rotatingfile_example.out.4
logging_rotatingfile_example.out.5

最新的文件总是logging_rotatingfile_example。输出,并且每次它达到大小限制时,它都用后缀.1重命名。对每个现有备份文件进行重命名,以增加后缀(。1变成。2,等等),.6文件被擦除。

作为一个极端的例子,显然这个例子设置的日志长度太小了。您需要将maxBytes设置为合适的值。

另一个解决方案是使用Apache的rotatelogs实用程序。

或以下脚本:

#!/bin/ksh
#rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]
numberOfFiles=10
while getopts "n:fltvecp:L:" opt; do
    case $opt in
  n) numberOfFiles="$OPTARG"
    if ! printf '%sn' "$numberOfFiles" | grep '^[0-9][0-9]*$' >/dev/null;     then
      printf 'Numeric numberOfFiles required %s. rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]n' "$numberOfFiles" 1>&2
      exit 1
    elif [ $numberOfFiles -lt 3 ]; then
      printf 'numberOfFiles < 3 %s. rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]n' "$numberOfFiles" 1>&2
    fi
  ;;
  *) printf '-%s ignored. rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]n' "$opt" 1>&2
  ;;
  esac
done
shift $(( $OPTIND - 1 ))
pathToLog="$1"
fileSize="$2"
if ! printf '%sn' "$fileSize" | grep '^[0-9][0-9]*[BKMG]$' >/dev/null; then
  printf 'Numeric fileSize followed by B|K|M|G required %s. rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]n' "$fileSize" 1>&2
  exit 1
fi
sizeQualifier=`printf "%sn" "$fileSize" | sed "s%^[0-9][0-9]*([BKMG])$%1%"`
multip=1
case $sizeQualifier in
B) multip=1 ;;
K) multip=1024 ;;
M) multip=1048576 ;;
G) multip=1073741824 ;;
esac
fileSize=`printf "%sn" "$fileSize" | sed "s%^([0-9][0-9]*)[BKMG]$%1%"`
fileSize=$(( $fileSize * $multip ))
fileSize=$(( $fileSize / 1024 ))
if [ $fileSize -le 10 ]; then
  printf 'fileSize %sKB < 10KB. rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]n' "$fileSize" 1>&2
  exit 1
fi
if ! touch "$pathToLog"; then
  printf 'Could not write to log file %s. rotatelogs.sh -n numberOfFiles pathToLog fileSize[B|K|M|G]n' "$pathToLog" 1>&2
  exit 1
fi
lineCnt=0
while read line
do
  printf "%sn" "$line" >>"$pathToLog"
  lineCnt=$(( $lineCnt + 1 ))
  if [ $lineCnt -gt 200 ]; then
    lineCnt=0
    curFileSize=`du -k "$pathToLog" | sed -e 's/^[  ][  ]*//' -e 's%[   ][  ]*$%%' -e 's/[  ][  ]*/[    ]/g' | cut -f1 -d" "`
    if [ $curFileSize -gt $fileSize ]; then
      DATE=`date +%Y%m%d_%H%M%S`
      cat "$pathToLog" | gzip -c >"${pathToLog}.${DATE}".gz && cat /dev/null >"$pathToLog"
      curNumberOfFiles=`ls "$pathToLog".[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9].gz | wc -l | sed -e 's/^[   ][  ]*//' -e 's%[   ][  ]*$%%' -e 's/[  ][  ]*/[    ]/g'`
      while [ $curNumberOfFiles -ge $numberOfFiles ]; do
        fileToRemove=`ls "$pathToLog".[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9].gz | head -1`
        if [ -f "$fileToRemove" ]; then
          rm -f "$fileToRemove"
          curNumberOfFiles=`ls "$pathToLog".[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9].gz | wc -l | sed -e 's/^[   ][  ]*//' -e 's%[   ][  ]*$%%' -e 's/[  ][  ]*/[    ]/g'`
        else
          break
        fi
      done
    fi
  fi
done

限制最大尺寸也可以通过head:

my_program | head -c 100  # Limit to 100 first bytes

查看dd: https://unix.stackexchange.com/a/121888/

的优点

最新更新