O Caminho Geral
$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log
Como funciona:
cat
lê o arquivo chamado input.log
e 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 cat
padrão para a entrada padrão de sed
.
sed
lê dados (como os cat
produz), processa-os (de acordo com o script fornecido com a -e
opçã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 -R
comando (a construção geral do comando replace é:) s/pattern/replace/
.
Então, de acordo com >>
bash
redireciona a saída de sed
para 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:
mkfifo
cria um pipe nomeado
while true; do sed ... ; done
executa um loop infinito e a cada iteração é executado sed
com o redirecionamento foo.log.fifo
para 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.
echo ... > foo.log.fifo
imprime uma mensagem em sua saída padrão redirecionada para o arquivo fifo e a sed
recebe, 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 sed
loop 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 sed
loop morrer por algum motivo - seu programa será bloqueado ao tentar acessar write
o arquivo até que alguém read
o 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:
Execute o tailf
processo que seguirá as gravações bar.raw.log
e as imprimirá na saída padrão redirecionada para o while read ... echo
loop infinito . Esse loop executa duas ações: ler dados da entrada padrão em uma variável de buffer chamada line
e, em seguida, gravar o registro de data e hora gerado com os seguintes dados em buffer no bar.log
.
Escreva algumas mensagens para o bar.raw.log
. Você deve fazer isso em uma janela de terminal separada, porque a primeira ocupará a tailf
qual 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.
tailf
, adicionado o caminho certo para usá-lo. Na verdade, o caminho comtailf
parece ser mais elegante, mas saí do quinto caminho com esperança de que seja útil para alguém.Você pode usar o
ts
script perl emmoreutils
:fonte
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:
tailf
o arquivo de log, como disse Dmitry Vasilyanov.Um exemplo chamado
foo.sh
:E o resultado:
Como funciona
exec &>
Redirecionar stdout e stderr para o mesmo local>( ... )
canaliza saídas para um comando interno assíncronoPor exemplo:
registro de data e hora do pipe e log para arquivo
Ou imprima o carimbo de data e hora e faça logon no stdout
salve-os na
/etc/crontab
configuraçãofonte
Usei
ts
dessa 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
rand
adiciono 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á-lots
, 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:
Isso fornece o seguinte no meu log de erros:
Talvez essa não seja uma maneira muito elegante de fazê-lo, mas funciona. Gostaria de saber se existe uma abordagem mais elegante.
fonte