Como adicionar um carimbo de data / hora ao registro de script do bash?

94

Eu tenho um script em execução constante que eu envio para um arquivo de log:

script.sh >> /var/log/logfile

Eu gostaria de adicionar um carimbo de data e hora antes de cada linha anexada ao log. Gostar:

Sat Sep 10 21:33:06 UTC 2011 The server has booted up.  Hmmph.

Existe algum jujitsu que eu possa usar?

Antonius Bloch
fonte
2
Veja esta missão. serverfault.com/questions/80749/… . Algumas respostas se aplicam aqui.
Zoredache
Para uma solução awk / gawk, consulte: stackoverflow.com/questions/21564/…
User
Aqui está uma implementação abrangente do log para o bash: github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Respostas:

88

Você pode canalizar a saída do script por meio de um loop que prefixa a data e a hora atuais:

./script.sh | while IFS= read -r line; do printf '%s %s\n' "$(date)" "$line"; done >>/var/log/logfile

Se você usar muito isso, é fácil criar uma função bash para lidar com o loop:

adddate() {
    while IFS= read -r line; do
        printf '%s %s\n' "$(date)" "$line";
    done
}

./thisscript.sh | adddate >>/var/log/logfile
./thatscript.sh | adddate >>/var/log/logfile
./theotherscript.sh | adddate >>/var/log/logfile
Gordon Davisson
fonte
3
@ Nils é um truque para impedir que apare os readespaços em branco no início e / ou na linha. Ele define o IFS (Internal Field Separator, basicamente uma lista de caracteres de espaço em branco) para esvaziar o readcomando.
Gordon Davisson
2
... e -r ignora o caractere de escape "\". Isso realmente deve funcionar em todos os casos - um ótimo preço de script.
Nils
7
@ Nils não é completamente à prova de balas, já que algumas implementações de echoseqüências de escape de interpretação. Se você realmente deseja que não mexa com o conteúdo (exceto a adição de datas), substitua o echocomando porprintf "%s %s\n" "$(date)" "$line"
Gordon Davisson
4
Você pode estar interessado em uma data / carimbo de data / hora compatível com ISO-8601 : date -u +"%Y-%m-%dT%H:%M:%SZ"ou talvez mais bonita date +"%Y-%m-%d %T".
Pablo A
1
Embora esse script funcione conforme o esperado, ele gera um novo processo (execução date) para cada linha de log, o que pode ser uma grande desvantagem, dependendo da sua máquina e da quantidade de logs. Eu preferiria sugerir o uso, tsse disponível, veja a resposta de @willem #
Michael Schaefers
56

Veja tsno moreutilspacote Ubuntu :

command | ts

Ou, se $commando buffer automático (requer expect-devpacote):

unbuffer command | ts
Willem
fonte
18

O comando date fornecerá essas informações

date -u
Sat Sep 10 22:39:24 UTC 2011

então você pode

echo $(date -u) "Some message or other"

é isso que você queria?

user9517
fonte
Usar o comando date era o que eu tinha em mente, mas não posso realmente adicioná-lo ao próprio script, então o que estou procurando é uma maneira de mudar essa linha: "script.sh >> / var / log / logfile "para acrescentar a data.
Antonius Bloch
Nesse caso, redirecione a saída do seu script para um pipe nomeado e faça com que um daemon atenda a saída, que pega a saída do script e adiciona uma data antes de gravá-la em um arquivo de log. Você provavelmente pode modificar o script que escrevi aqui para fazer isso. Eu faria isso porque me interessa, mas é tarde no Reino Unido e eu começo cedo amanhã.
user9517
12

Você pode simplesmente fazer eco das saídas de comando para o arquivo de log. ou seja,

echo "`date -u` `./script.sh`" >> /var/log/logfile

Realmente funciona :)

Exemplo:

[sparx@E1]$ ./script.sh 
Hello Worldy
[sparx@E1]$ echo "`date -u` `./script.sh`" >> logfile.txt
[sparx@E1]$ cat logfile.txt 
Mon Sep 12 20:18:28 UTC 2011 Hello Worldy
[sparx@E1]$ 
SparX
fonte
Hmm não está funcionando para mim.
Antonius Bloch
O que você está recebendo quando executa o comando?
SparX 12/09/11
8
Isso coloca um registro de data e hora antes de toda a saída de '' ./script.sh '', não antes de cada linha.
22415 clacke
8

Faça um config.sharquivo

#!/usr/bin/env bash
LOGFILE="/path/to/log.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`

Quando você precisar enviar para o arquivo de log, use

#!/usr/bin/env bash
source /path/to/config.sh

echo "$TIMESTAMP Say what you are doing" >> $LOGFILE

do_what_you_want >> $LOGFILE

O arquivo de log será semelhante

2013-02-03 18:22:30 Say what you are doing

Portanto, será fácil classificar por data

scls
fonte
8
Seu '' config.sh '' executará '' date '' exatamente uma vez, em '' source ... / config.sh ''.
clacke
5

Você quer dizer como:

(date && script.sh) >> /var/log/logfile
cjc
fonte
Meu Deus, pessoal, todo mundo está fazendo substituição de ticks atrasados, pipes nomeados, etc. Apenas coloque o comando date e o script em parens! O cara que tem a função tem um caso legítimo se houver saída em várias linhas e o log precisar ficar bonito com a data em todas as linhas, mas a maioria dessas soluções é um exagero que não usa semântica de shell.
cjc 12/09
8
Isso adicionará o registro de data e hora apenas uma vez por execução de script.sh. O OP precisa de um carimbo de data / hora por linha.
Dave Forgac
1
embora isso não responda à pergunta do OP, ainda achei informações úteis.
Utilizador
4

Tente isto

timestamp()
{
 date +"%Y-%m-%d %T"
}

Chame esta função de carimbo de data / hora em todos os comandos de eco:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log
Sanjay Yadav
fonte
@ shazbot: Obrigado pela edição, que foi um erro de digitação, eu não percebi.
Sanjay Yadav
4

A resposta aceita https://serverfault.com/a/310104 pode ser um pouco lenta, se muitas linhas tiverem que ser processadas, com a sobrecarga de iniciar o dateprocesso permitindo cerca de 50 linhas por segundo no Ubuntu e apenas 10 -20 em Cygwin.

Quando se bashpode supor que uma alternativa mais rápida seria a printfincorporada com seu %(...)Tespecificador de formato. Comparar

>> while true; do date; done | uniq -c
     47 Wed Nov  9 23:17:18 STD 2016
     56 Wed Nov  9 23:17:19 STD 2016
     55 Wed Nov  9 23:17:20 STD 2016
     51 Wed Nov  9 23:17:21 STD 2016
     50 Wed Nov  9 23:17:22 STD 2016

>> while true; do printf '%(%F %T)T\n'; done | uniq -c
  20300 2016-11-09 23:17:56
  31767 2016-11-09 23:17:57
  32109 2016-11-09 23:17:58
  31036 2016-11-09 23:17:59
  30714 2016-11-09 23:18:00
kdb
fonte
1

Você pode notar que o awk roda rápido,

gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }'

yes |head -5000000 |gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' |uniq -c
 461592 [2017-02-28 19:46:44] y
 488555 [2017-02-28 19:46:45] y
 491205 [2017-02-28 19:46:46] y
 498568 [2017-02-28 19:46:47] y
 502605 [2017-02-28 19:46:48] y
 494048 [2017-02-28 19:46:49] y
 493299 [2017-02-28 19:46:50] y
 498005 [2017-02-28 19:46:51] y
 502916 [2017-02-28 19:46:52] y
 495550 [2017-02-28 19:46:53] y
  73657 [2017-02-28 19:46:54] y

Mas, sed corre muito mais rápido,

sed -e "s/^/$(date -R) /"

yes |head -5000000 |sed -e "s/^/$(date -R) /" |uniq -c
5000000 Tue, 28 Feb 2017 19:57:00 -0500 y

No entanto, em uma inspeção mais detalhada, o conjunto parece não mudar o tempo,

vmstat 1 | sed -e "s/^/$(date -R) /"
ChuckCottrill
fonte
1
isso ocorre porque ele está avaliando "s/^/$(date -R) /"e executando a data uma vez antes da sed. Sed passa uma string estática.
Evan Benn
Bash simples: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cque é muito mais lento que o gawk. tsO utilitário possui desempenho semelhante ao do bash loop.
akhan 27/09
Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cque é um pouco mais lento que o awk.
akhan 28/09
1

Abaixo está o conteúdo do meu arquivo de log

xiongyu@ubuntu:~/search_start_sh$ tail restart_scrape.log 

2017-08-25 21:10:09 scrape_yy_news_main.py got down, now I will restart it

2017-08-25 21:10:09 check_yy_news_warn.py got down, now I will restart it

2017-08-25 21:14:53 scrape_yy_news_main.py got down, now I will restart it

parte do conteúdo do meu shell é como abaixo

log_file="restart_scrape.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`
echo "$TIMESTAMP $search_py_file got down, now I will restart it" | tee -a $log_file 
Jayhello
fonte
1

Este script imprime a saída no terminal e também salva no arquivo de log.

#!/bin/bash

MY_LOG=/var/log/output.log

echolog(){
    if [ $# -eq 0 ]
    then cat - | while read -r message
        do
                echo "$(date +"[%F %T %Z] -") $message" | tee -a $MY_LOG
            done
    else
        echo -n "$(date +'[%F %T %Z]') - " | tee -a $MY_LOG
        echo $* | tee -a $MY_LOG
    fi
}

echolog "My script is starting"
whoami | echolog

Saída de amostra:

[2017-10-29 19:46:36 UTC] - My script is starting
[2017-10-29 19:46:36 UTC] - root
Seff
fonte
seu primeiro comando de data deve usar aspas simples, não aspas duplas.
Jason Harrison
1

Outra opção é configurar uma função para chamar sempre que você desejar gerar dados no seu código:

PrintLog(){
  information=$1
  logFile=$2
  echo "$(date +'%Y-%m-%d %H:%M:%S" $information} >> $logFile
}

Toda vez em seu código, você deseja enviá-lo para a chamada do arquivo de log

PrintLog "Stuff you want to add..." ${LogFileVariable}

Mole-mole....

Josh Williams
fonte
0

Conduza um "sed":

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile
eubide
fonte
quanto à outra resposta, essa é apenas a data de execução do bash uma vez. sed não está atualizando o tempo por linha.
Evan Benn