Anexando carimbo de data e hora junto com as linhas do arquivo de log

11

Eu tenho um arquivo de log e preciso acrescentar carimbos de data e hora a cada linha à medida que são adicionados. Então, eu estou procurando um script que acrescente timestamps a cada entrada nas linhas de log e que possa ser executado como um trabalho cron.

Kratos
fonte

Respostas:

18

O Caminho Geral

$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log

Como funciona:

  1. catlê o arquivo chamado input.loge apenas o imprime no fluxo de saída padrão.

    Normalmente, a saída padrão está conectada a um terminal, mas este pequeno script contém, |portanto, o shell redireciona a saída catpadrão para a entrada padrão de sed.

  2. sedlê dados (como os catproduz), processa-os (de acordo com o script fornecido com a -eopção) e depois os imprime em sua saída padrão. O script "s/^/$(date -R) /"significa substituir todo início de linha por um texto gerado por date -Rcomando (a construção geral do comando replace é:) s/pattern/replace/.

  3. Então, de acordo com >> bashredireciona a saída de sedpara um arquivo chamado output.log( >significa substituir o conteúdo do arquivo e >>significa anexar ao final).

O problema é $(date -R)avaliado uma vez quando você executa o script para inserir o registro de data e hora atual no início de cada linha. O registro de data e hora atual pode estar longe de um momento em que uma mensagem foi gerada. Para evitá-lo, é necessário processar as mensagens conforme elas são gravadas no arquivo, não com uma tarefa cron.

FIFO

O redirecionamento de fluxo padrão descrito acima chamado pipe . Você pode redirecioná-lo não apenas com |comandos no script, mas também através de um arquivo FIFO (também conhecido como pipe ). Um programa gravará no arquivo e outro lerá os dados e os receberá quando o primeiro enviar.

Escolha um exemplo:

$ mkfifo foo.log.fifo
$ while true; do cat foo.log.fifo | sed -e "s/^/$(date -R) /" >> foo.log; done;

# have to open a second terminal at this point
$ echo "foo" > foo.log.fifo
$ echo "bar" > foo.log.fifo
$ echo "baz" > foo.log.fifo

$ cat foo.log      

Tue, 20 Nov 2012 15:32:56 +0400 foo
Tue, 20 Nov 2012 15:33:27 +0400 bar
Tue, 20 Nov 2012 15:33:30 +0400 baz

Como funciona:

  1. mkfifo cria um pipe nomeado

  2. while true; do sed ... ; doneexecuta um loop infinito e a cada iteração é executado sedcom o redirecionamento foo.log.fifopara sua entrada padrão; sed bloqueia a espera dos dados de entrada , processa uma mensagem recebida e a imprime na saída padrão redirecionada para foo.log.

    Nesse ponto, você precisa abrir uma nova janela do terminal porque o loop ocupa o terminal atual.

  3. echo ... > foo.log.fifoimprime uma mensagem em sua saída padrão redirecionada para o arquivo fifo e a sedrecebe, processa e grava em um arquivo regular.

A nota importante é o fifo, assim como qualquer outro tubo não faz sentido se um de seus lados não estiver conectado a nenhum processo. Se você tentar gravar em um canal, o processo atual será bloqueado até que alguém leia os dados do outro lado do canal. Se você quiser ler de um canal, o processo será bloqueado até que alguém escreva dados no canal. O sedloop no exemplo acima não faz nada (dorme) até você fazer echo.

Para sua situação específica, basta configurar seu aplicativo para gravar mensagens de log no arquivo fifo. Se você não pode configurá-lo - simplesmente exclua o arquivo de log original e crie um arquivo fifo. Mas observe novamente que, se o sedloop morrer por algum motivo - seu programa será bloqueado ao tentar acessar writeo arquivo até que alguém reado faça do fifo.

O benefício é o carimbo de data / hora atual avaliado e anexado a uma mensagem enquanto o programa a grava no arquivo.

Processamento assíncrono com tailf

Para tornar a gravação no log e o processamento mais independentes, você pode usar dois arquivos regulares com tailf. Um aplicativo grava a mensagem em um arquivo bruto e outro processo lê novas linhas (siga as gravações de forma assíncrona) e processa os dados gravando no segundo arquivo.

Vamos dar um exemplo:

# will occupy current shell
$ tailf -n0 bar.raw.log | while read line; do echo "$(date -R) $line" >> bar.log; done;

$ echo "foo" >> bar.raw.log
$ echo "bar" >> bar.raw.log
$ echo "baz" >> bar.raw.log

$ cat bar.log

Wed, 21 Nov 2012 16:15:33 +0400 foo
Wed, 21 Nov 2012 16:15:36 +0400 bar
Wed, 21 Nov 2012 16:15:39 +0400 baz

Como funciona:

  1. Execute o tailfprocesso que seguirá as gravações bar.raw.loge as imprimirá na saída padrão redirecionada para o while read ... echoloop infinito . Esse loop executa duas ações: ler dados da entrada padrão em uma variável de buffer chamada linee, em seguida, gravar o registro de data e hora gerado com os seguintes dados em buffer no bar.log.

  2. Escreva algumas mensagens para o bar.raw.log. Você deve fazer isso em uma janela de terminal separada, porque a primeira ocupará a tailfqual seguirá as gravações e fará seu trabalho. Bem simples.

A vantagem é que seu aplicativo não bloquearia se você matar tailf. Os contras são carimbos de data e hora menos precisos e duplicação de arquivos de log.

Dmitry Vasilyanov
fonte
Obrigado .Fifo parece muito apto para o meu uso. O programa já grava em um log file.txt, mas esse arquivo precisa ser redirecionado para o seu foo.log.fifo. Mas fazer $ tailf file.txt> foo.log.fifo ! Então, como posso redirecionar meu conteúdo em um arquivo de log de atualização para este foo.log.fifo para que ele também inclua o tempo.
Kratos
Apenas melhorou a resposta. Explicou por que o fifo bloqueia o seu tailf, adicionado o caminho certo para usá-lo. Na verdade, o caminho com tailfparece ser mais elegante, mas saí do quinto caminho com esperança de que seja útil para alguém.
Dmitry Vasilyanov
O uso da resposta sed para anotar a saída do vmstat gera um registro de data e hora que não muda, vmstat 1 | sed -e "s / ^ / $ (date -R) /"
ChuckCottrill 6/17/17
6

Você pode usar o tsscript perl em moreutils:

$ echo test | ts %F-%H:%M:%.S
2012-11-20-13:34:10.731562 test
Stéphane Chazelas
fonte
2

Modificado a partir da resposta de Dmitry Vasilyanov.

No script bash, você pode redirecionar e agrupar a saída com registro de data e hora linha por linha em tempo real.

Quando usar:

  • Para trabalhos de script bash, insira a linha antes do script principal
  • Para trabalhos sem script, crie um script para chamar o programa.
  • Para o controle de serviços pelo sistema, é melhor usar tailfo arquivo de log, como disse Dmitry Vasilyanov.

Um exemplo chamado foo.sh:

#!/bin/bash
exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)

echo "foo"
sleep 1
echo "bar" >&2
sleep 1
echo "foobar"

E o resultado:

$ bash foo.sh
$ cat foo.log
May 12 20:04:11 foo
May 12 20:04:12 bar
May 12 20:04:13 foobar

Como funciona

  1. exec &> Redirecionar stdout e stderr para o mesmo local
  2. >( ... ) canaliza saídas para um comando interno assíncrono
  3. A parte restante funciona como Dmitry Vasilyanov expandido.

Por exemplo:

  • registro de data e hora do pipe e log para arquivo

    #!/bin/bash        
    exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)
    
    echo "some script commands"
    /path-to/some-thrid-party-programs
    
  • Ou imprima o carimbo de data e hora e faça logon no stdout

    #!/bin/bash        
    exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line"; done;)
    
    echo "some script commands"
    /path-to/some-thrid-party-programs
    

    salve-os na /etc/crontabconfiguração

    * * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
    
Jethro Yu
fonte
1

Usei tsdessa maneira para obter uma entrada com registro de data e hora em um log de erro de um script que eu uso para obter o Cacti preenchido com estatísticas de um host remoto.

Para testar o Cacti, eu randadiciono alguns valores aleatórios que eu uso nos gráficos de temperatura para monitorar a temperatura do meu sistema.

Pushmonstats.sh é um script que coleta estatísticas de temperatura do sistema do meu PC e envia para um Raspberry Pi no qual o Cacti é executado. Algum tempo atrás, a rede estava presa. Eu só tenho tempos limite de SSH no meu log de erros. Infelizmente, não há entradas de tempo nesse log. Não sabia como adicionar um carimbo de data / hora a uma entrada de log. Então, depois de algumas pesquisas na Internet, me deparei com este post e foi isso que fiz usando ts.

Para testá-lo, usei uma opção desconhecida para rand. O que deu um erro ao stderr. Para capturá-lo, eu o redireciono para um arquivo temporário. Então eu uso o gato para mostrar o conteúdo do arquivo e canalizá-lo ts, adicionar um formato de hora que encontrei nesta postagem e finalmente registrá-lo no arquivo de erro. Em seguida, limpo o conteúdo do arquivo temporário, caso contrário, recebo entradas duplas pelo mesmo erro.

Crontab:

* * * * * /home/monusr/bin/pushmonstats.sh 1>> /home/monusr/pushmonstats.log 2> /home/monusr/.err;/bin/cat /home/monusr/.err|/usr/bin/ts %F-%H:%M:%.S 1>> /home/monusr/pushmonstats.err;> /home/monusr/.err

Isso fornece o seguinte no meu log de erros:

2014-03-22-19:17:53.823720 rand: unknown option -- '-l'

Talvez essa não seja uma maneira muito elegante de fazê-lo, mas funciona. Gostaria de saber se existe uma abordagem mais elegante.

Frank
fonte