Como continuar redirecionando o stdout para um arquivo depois que o logrotate o move?

22

Eu tenho um script simples que gera vários logs para a tela e canalizei o STDOUT para um arquivo para armazenar os logs. Como esse script é de longa duração, eu precisava rotacionar os arquivos de log para que eles sejam divididos em arquivos menores e mais gerenciáveis.

O problema que enfrentei foi que, uma vez que o logrotatearquivo de log atual é movido para um novo, o arquivo de log recém-criado não é mais preenchido com os logs. Parece que, assim que o arquivo de log original é removido, seu manipulador de arquivos é perdido e o redirecionamento não funciona mais.

Eu também encontrei este post que tinha o mesmo problema que eu e afirma que ele pode ser corrigido usando em >>vez de >redirecionar a saída. Testei sua solução, mas não funcionou para mim. Alguém tem alguma idéia de como manter o redirecionamento funcionando?

Mehran
fonte
4
Eu ainda recomendaria, no seu caso, usar ">>" em vez de ">" se você pretender gravar em um arquivo truncado: como ">>" aberto no modo de acréscimo, ele procurará até o final do arquivo cada vez que escreve. Dessa forma, quando você truncar o arquivo (fazendo com que ele vá de XXXX bytes para 0 bytes), ele "procurará até o fim", então saberá que agora precisa escrever após o byte 0. Caso contrário, ele poderá escrever após o byte XXXX e, portanto, criar um arquivo esparso com XXXX nulo bytes antes de ele (ou seja, quando ">", o fd pode apenas lembrar onde foi nesse arquivo, e escrever a partir daí, sem perceber a encolhido o tamanho do arquivo!)
Olivier Dulac

Respostas:

25

Você deve usar a diretiva copytruncate em sua configuração de logrotate para este arquivo de log.

copytruncate Trunca o arquivo de log original depois de criar uma cópia, em vez de mover o arquivo de log antigo e, opcionalmente, criar um novo. Ele pode ser usado quando algum programa não pode ser solicitado a fechar seu arquivo de log e, portanto, pode continuar gravando (anexando) no arquivo de log anterior para sempre. Observe que há um intervalo de tempo muito pequeno entre copiar o arquivo e truncá-lo, portanto, alguns dados de registro podem ser perdidos. Quando essa opção é usada, a opção de criação não terá efeito, pois o arquivo de log antigo permanece no local

user9517 suporta GoFundMonica
fonte
2
Vale ressaltar: Por um curto período de tempo, antes da compressoperação, os dados são duplicados. Isso nos causou um problema uma vez, mas esse foi nosso problema, já que não deveríamos estar tão perto do lvlimite de espaço. Além disso, conforme declarado no mantrecho, você pode perder alguns dados de log entre as operações de cópia e truncar.
Belmin Fernandez 03/07/2014
6

Como alternativa, você também pode:

  • use o utilitário logger em seu script em vez de canalizar, com um recurso dedicado (por exemplo, local5), por exemplo:

    logger -p local5.info -t myscriptname "this is some log data"

  • configure o syslog para gravar esse recurso no arquivo de log desejado, exemplo (rsyslog.conf):

    local5.* /var/log/mylogfile

  • configurar a regra de rotação de log para este log.

tonioc
fonte
Isso só funciona se você tiver comandos de saída explícitos como echo. A saída de ferramentas de terceiros que são chamados a partir do script e também de saída algo não pode ser redirecionado para o logger desta forma
Daniel Alder
4

Outra alternativa à solução Iain é usar um postrotatescript para reiniciar seu script depois que a rotação ocorrer. Isso é feito para muitos daemons (reinicie ou recarregue o daemon), mas sem conhecer seu script, não sei se essa solução será adequada ou não (seu script depende de algum estado gerado há algum tempo?).

Conteúdo de /etc/logrotate.d/your-script-name:

/var/log/your-script-name.log {
    # your current logrotate options
    ...
    postrotate
        # this supposing you have the current pid stored
        cat /run/your-script-name.pid | xargs -r kill
        #relaunch it again
        /usr/local/bin/your-script-name
    endscript
}
Carlos Campderrós
fonte
0

Você pode canalizar o stdout para "dividir" (parte dos coreutils no linux). Ele permite que você divida o arquivo / stdin em partes com base no tamanho, número de linhas, etc. Depois de obtê-las, você pode gerenciá-las com logrotate, se necessário.

Nazar
fonte