Como limitar o tamanho do arquivo de log usando >>

24

Como posso limitar o tamanho de um arquivo de log gravado com >>200 MB?

$ run_program >> myprogram.log
david
fonte
11
Deseja que o programa seja morto após 200 MB? Ou você quer os últimos 200 MB com tudo mais antigo no bloco de bits?
Aaron D. Marasco
Não, o processo não pode parar até que matou manualmente
david
decidiu ir para logrotate, agradece a todos para as entradas valiosas
david

Respostas:

9

Se o seu aplicativo (ou seja, run_program) não suportar a limitação do tamanho do arquivo de log, você poderá verificar o tamanho do arquivo periodicamente em um loop com um aplicativo ou script externo.

Você também pode usar logrotate(8)para girar seus logs, ele possui um sizeparâmetro que você pode usar para sua finalidade:

Com isso, o arquivo de log é girado quando o tamanho especificado é atingido. O tamanho pode ser especificado em bytes (padrão), kilobytes (sizek) ou megabytes (tamanho).

Emre Yazici
fonte
11
Os arquivos de log +1 com informações repetidas geralmente podem ser compactados em ordens de magnitude.
usuário desconhecido
O logrotate trunca arquivos ou simplesmente os copia ou move? Porque isso funcionará apenas se o arquivo associado ao fd estiver truncado. Se for mv'd, o arquivo continuará a crescer, se for desvinculado, será mantido aberto e continuará a crescer até o processo terminar ... O IIRC registra cópias, desassocia e cria um novo arquivo, é por isso que geralmente é necessário enviar SIGHUP para daemons quando seus registros são girados.
Michael Trausch
Note-se que mesmo que seja truncado, não é um problema se o arquivo não foi aberto no modo append (arquivos de log deve sempre ser aberto no modo anexar, mas na minha experiência muitas vezes não são)
Random832
O logrotate pode girar uma vez que o arquivo atinge um determinado tamanho, diariamente, semanalmente etc. Ele também pode ser compactado e você pode usar a postscriptopção para fazer com que a configuração do logrotate seja enviada SIGHUPao programa.
Laebshade
12

Se o seu programa não precisar gravar OUTROS arquivos maiores que esse limite, você poderá informar o kernel desse limite usando ulimit. Antes de executar seu comando, execute isso para configurar um limite de tamanho de arquivo de 200 MB para todo o processo executado na sua sessão atual do shell:

ulimit -f $((200*1024))

Isso protegerá o seu sistema, mas pode estar causando problemas para o programa que está gravando o arquivo. Como eyazici sugere , considere configurar logrotatepara remover arquivos de log assim que atingirem um determinado tamanho ou idade. Você pode descartar dados antigos ou arquivá-los por um período de tempo em uma série de arquivos compactados.

Caleb
fonte
isso limita o tamanho de qualquer arquivo gravado pelo programa #
22711 Kim
Verdade. Se o programa tiver uma necessidade legítima de gravar outros arquivos grandes, você precisará de uma solução diferente.
Caleb
6

Você pode criar uma nova imagem do sistema de arquivos, montá-la usando o dispositivo de loop e colocar o arquivo de log nesse sistema de arquivos:

dd if=/dev/zero of=./200mb.img bs=1024 count=200000 # create new empty 200MB file
mkfs.ext2 200mb.img # or ext3, or whatever fits your needs
mkdir logs
sudo mount -t ext2 -o loop 200mb.img logs # only root can do '-o loop' by default
run_program >>logs/myprogram.log

Você também pode usar em tmpfsvez de um arquivo, se tiver memória suficiente.

alex
fonte
Idéia criativa ... que deixa para o programa o que fazer quando acabar.
Aaron D. Marasco
6

Você pode truncar a saída com head:

size=$((200*1024*1024-$(stat -c %s myprogram.log)))
run_program | head -c ${size} >> myprogram.log
smoking
fonte
Muito criativo. Apenas uma observação de que isso funcionaria apenas para limitar a gravação de NOVOS dados no arquivo, não levaria em consideração o tamanho grande ou pequeno do arquivo.
Caleb
2
Observe que é provável que isso acabe com o programa (com SIGPIPE) assim que atingir o limite de tamanho, em vez de descartar os dados.
Random832
11
Eu estava pensando semelhante com alguma ddmágica, mas sim, a Random832 está certa, você receberá um SIGPIPEas head/ dd/ whateverdrops.
Aaron D. Marasco 23/07
Que tal ignorá-lo com um trap '' SIGPIPE?
tuxce
Ou canalize para { head -c "$size" >> log; cat > /dev/null; }.
Stéphane Chazelas
5

No pacote apache2-utilsestá presente o utilitário chamado rotatelogs, pode ser útil para você.

Sinopse:

rotatelogs [-l] [-L linkname ] [-p program ] [-f] [-t] [-v] [-e] [-c] [-n número de arquivos ] tempo de rotação do arquivo de log | tamanho do arquivo (B | K | M | G) [ deslocamento ]

Exemplo:

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

Manual completo que você pode ler neste link .

PRIHLOP
fonte
O link é inexistente.
Alexander Gonchiy
1

Estou certo de que o pôster original encontrou uma solução. Aqui está outro para outros que podem ler este tópico ...

O corte reduz o tamanho da saída de um programa e preserva os últimos 200 MB de saída com o seguinte comando:

$ run_program | curtail -s 200M myprogram.log

Referências

NOTA: Sou o mantenedor do repositório acima. Apenas compartilhando a solução ...

Dave Wolaver
fonte
Eu amo a idéia de reduzir. Eu não estou tão familiarizado com C, então há uma chance de fornecer um binário para isso? ou pelo menos instruções detalhadas sobre como instalá-lo?
Felipe
0

Como é um texto, eu escreveria um script no seu idioma favorito e o direcionaria para isso. Faça com que ele lide com a E / S do arquivo (ou mantenha tudo na memória e depois despeje-o SIGHUPou similar). Por isso, em vez de 200 MB, eu pensaria em um número 'razoável' de linhas para acompanhar.

Aaron D. Marasco
fonte
Manter 200 MB de dados de log na memória por nenhum outro motivo além de poder truncá-lo não é um uso muito bom dos recursos do sistema. A contagem de linhas também não está em um grande arquivo de log. Eu recomendaria o uso de ferramentas criadas para isso como sysloge logrotate.
Caleb
0

O script a seguir deve fazer o trabalho.

LOG_SIZE=500000
NUM_SEGM=2
while getopts "s:n:" opt; do
  case "$opt" in
    s)
      LOG_SIZE=$OPTARG
      ;;
    n)
      NUM_SEGM=$OPTARG
      ;;
  esac
done
shift $((OPTIND-1))
if [ $# == 0 -o -z "$1" ]; then
    echo "missing output file argument"
    exit 1
fi
OUT_FILE=$1
shift
NUM=1
while :; do
    dd bs=10 count=$(($LOG_SIZE/10)) >> $OUT_FILE 2>/dev/null
    SZ=`stat -c%s $OUT_FILE`
    if [ $SZ -eq 0 ]; then
        rm $OUT_FILE
        break
    fi
    echo -e "\nLog portion finished" >> $OUT_FILE
    mv $OUT_FILE $OUT_FILE.n$NUM
    NUM=$(($NUM + 1))
    [ $NUM -gt $NUM_SEGM ] && NUM=1
done

Ele tem alguns atalhos óbvios, mas no geral ele faz o que você pediu. Ele dividirá o log em pedaços de tamanho limitado e a quantidade de pedaços também é limitada. Tudo pode ser especificado através dos argumentos da linha de comando. O arquivo de log também é especificado através da linha de comando.

Observe uma pequena pegadinha se você a usar com o daemon que se bifurca em segundo plano. O uso de um pipe impedirá que o daemon vá para o segundo plano. Nesse caso, há uma sintaxe (provavelmente específica do bash) para evitar o problema:

my_daemon | ( logger.sh /var/log/my_log.log <&0 & )

Observe que <&0, embora pareça redundante, não funcionará sem isso.

stsp
fonte