2011-07-15 5 views
12

Bir UNIX işleminden çıktı almak istiyorum ancak maksimum dosya boyutunu sınırlamak ve/veya yeni bir dosyaya döndürmek istiyorum.Tişört (veya eşdeğer) kullanın, ancak maksimum dosya boyutunu sınırlandırın veya yeni dosyaya dönün

Logrotate'ı gördüm, ancak gerçek zamanlı çalışmıyor. Anladığım kadarıyla paralel çalışan bir "temizlik" işi.

Doğru çözüm nedir? Sanırım bunu yapmak için küçük bir senaryo yazacağım, ancak mevcut metin araçlarıyla basit bir yol olduğunu umuyorum.

Düşünün: o doldurur gibi ... log/my_program_log000001 ve yeni bir günlüğünü başlatmak için yeniden adlandırılmış Sonra log/my_program_log

:

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

Daima gibi en son günlük dosyasını yazma ... verir misiniz/my_program_log.

cevap

14

kullanım bölünmüş:

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

Yoksa çıktıyı görmek istemiyorsanız, doğrudan boru bölmek olabilir: Günlük rotasyon gelince

my_program | split -d -b 100000 - 

, hiçbir var otomatik olarak yapan coreutils aracı. Bir sembolik oluşturmak ve periyodik olarak bir bash komutunu kullanarak güncelleme olabilir: max kesin değildir, bu yüzden bir araya hatları tutar

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

Bah ... Bash'deki (ve diğer bazı kabuklarda)>() operatörünü unuttum. Çok seyrek kullanırım. Seninki en özlü cevaptır. – kevinarpe

1

Bunu çözmenin en kolay yolu, muhtemelen bu amaçla tasarlanmış olan python ve logging module'u kullanmaktır. stdin'dan okuyarak bir kod oluşturun ve stdout'a yazın ve aşağıda açıklanan log-rotasyonunu uygulayın.

"günlük" modülü provides Sorduğunuz tam olarak ne yapar

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

.

Dosyanın önceden belirlenen bir boyutta yuvarlanmasını sağlamak için maxBytes ve backupCount değerlerini kullanabilirsiniz. docs.python.org

itibaren

Bazen bir günlük dosyası daha sonra yeni bir dosya açın ve buna oturum belli bir boyuta büyümesine izin istiyorum. Bu dosyaların belirli bir sayısını saklamak isteyebilirsiniz ve bu çok sayıda dosya oluşturulduğunda, dosya sayısını ve dosyaların boyutlarının sınırlı kalmasını sağlayacak şekilde dosyaları döndürün.

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 
:

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) 

sonuç uygulaması için günlük geçmişinde bir parçası olan 6 ayrı dosyalar, her şekilde olmalıdır: Bu kullanım modeli için, günlüğü paketi RotatingFileHandler sağlar

En güncel dosya her zaman logging_rotatingfile_example.out olur ve her defasında boyut sınırına ulaştığında, sonek .1 ile yeniden adlandırılır. Varolan yedekleme dosyalarının her biri son eki artırmak için yeniden adlandırılır (.1 olur .2, vb.) Ve .6 dosyası silinir.

Açıkçası bu örnek, log uzunluğunu aşırı bir örnek olarak çok küçük değil. MaxBytes değerini uygun bir değere ayarlamak istersiniz.

+0

Kafam karıştı. Programım Python değil. Bu bana nasıl yardımcı oluyor? Standart GNU coreutils kullanmak istiyorum: awk/tee/split/etc. – kevinarpe

5

veya kullanan awk

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

, ancak bu özellikle güzel olabilir günlüğe kaydetme amaçları. Dosya adını formatlamak için awk'in sprintfini kullanabilirsiniz.

İşte çalıştırın 'arı' adlı bir dosyaya bu kaydetmek awk 'chmod +x bee'

#!/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)}' 

kullanarak, pipable senaryo ve

program | bee 

olarak kullanabilirsiniz veya mevcut bölmek

bee -b1000 -o proglog -w8 file 
+0

Yorumunuza katılıyorum: "Çizgileri bir arada tutar, bu yüzden max kesin değildir, ancak bu özellikle günlüğe kaydetme amaçları için güzel olabilir." – kevinarpe

2

100 bayt boyutunu sınırlamak için olduğu gibi dosya, sadece dd kullanabilirsiniz:

my_program | dd bs=1 count=100 > log 

100 bayt yazıldığında dd, boruyu kapatır ve my_program EPIPE'yi alır.

0

Başka bir çözüm, Apache rotatelogs yardımcı programını kullanmak olacaktır. komut aşağıdaki

Veya: paketinde apache2-utils yılında

#!/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 '%s\n' "$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 '%s\n' "$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 "%s\n" "$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 "%s\n" "$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 "%s\n" "$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 
1

, rotatelogs denilen mevcut aracıdır tamamen sizin ihtiyaçlarına cevap.

Özet:

rotatelogs [-l] [-L linkname] [-p programı] [f] [t] [-v] [e] [-c] [ -n dosya-dosyalarının sayısı] logfile rotationtime | Eğer this link okumak olabilir

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

Tam kılavuzu: dosya boyutu (B | K | | MG)

Örnek [ ofset].

İlgili konular