Timbro timestamp aggiunto insieme alle righe del file di registro


11

Ho un file di registro e devo aggiungere i timestamp a ciascuna riga man mano che vengono aggiunti. Quindi sto cercando uno script che aggiunge timestamp a ciascuna voce nelle righe del registro e che potrebbe essere eseguito come cron job.

Risposte:


18

Il modo generale

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

Come funziona:

  1. catlegge il file chiamato input.loge lo stampa sul suo flusso di output standard.

    Normalmente l'output standard è collegato a un terminale, ma questo piccolo script contiene in |modo che la shell reindirizzi l'output catstandard dell'input standard di sed.

  2. sedlegge i dati (come li catproduce), li elabora (secondo lo script fornito con l' -eopzione) e quindi li stampa sul suo output standard. Lo script "s/^/$(date -R) /"significa sostituire ogni inizio di riga con un testo generato dal date -Rcomando (la costruzione generale per il comando di sostituzione è:) s/pattern/replace/.

  3. Quindi, secondo i >> bashreindirizzamenti, l'output di sedun file chiamato output.log( >significa sostituire il contenuto del file e >>significa aggiungere alla fine).

Il problema è $(date -R)valutato una volta quando si esegue lo script in modo da inserire il timestamp corrente all'inizio di ogni riga. Il timestamp corrente potrebbe essere lontano da un momento in cui è stato generato un messaggio. Per evitarlo devi elaborare i messaggi mentre vengono scritti nel file, non con un processo cron.

FIFO

Il reindirizzamento stream standard descritto sopra chiamato pipe . Puoi reindirizzarlo non solo |tra i comandi nello script, ma attraverso un file FIFO ( detto anche pipe ). Un programma scriverà sul file e un altro leggerà i dati e li riceverà al primo invio.

Scegli un esempio:

$ 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

Come funziona:

  1. mkfifo crea una pipa denominata

  2. while true; do sed ... ; doneesegue un ciclo infinito e ad ogni iterazione corre sedcon il reindirizzamento foo.log.fifoal suo input standard; sed si blocca in attesa di dati di input, quindi elabora un messaggio ricevuto e lo stampa sull'output standard reindirizzato a foo.log.

    A questo punto devi aprire una nuova finestra del terminale perché il loop occupa il terminale corrente.

  3. echo ... > foo.log.fifostampa un messaggio sul suo output standard reindirizzato al file fifo e lo sedriceve, lo elabora e scrive su un file normale.

La nota importante è il fifo proprio come qualsiasi altra pipe non ha senso se uno dei suoi lati non è collegato a nessun processo. Se si tenta di scrivere su una pipe, il processo corrente si bloccherà fino a quando qualcuno non leggerà i dati dall'altra parte della pipe. Se si desidera leggere da una pipe, il processo si bloccherà fino a quando qualcuno non scriverà i dati nella pipe. Il sedciclo nell'esempio sopra non fa nulla (dorme) fino a quando non lo fai echo.

Per la tua situazione particolare, devi solo configurare l'applicazione per scrivere i messaggi di registro nel file FIFO. Se non è possibile configurarlo, è sufficiente eliminare il file di registro originale e creare un file FIFO. Ma nota ancora che se il sedloop morirà per qualche motivo - il tuo programma verrà bloccato quando si tenta di accedere writeal file fino a quando qualcuno non lo farà readdal FIFO.

Il vantaggio è il timestamp corrente valutato e allegato a un messaggio mentre il programma lo scrive nel file.

Elaborazione asincrona con tailf

Per rendere più indipendente la scrittura nel registro e l'elaborazione, è possibile utilizzare due file regolari con tailf. Un'applicazione scriverà un messaggio in un file non elaborato e altri processi leggeranno nuove righe (segui per scrivere in modo asincrono) ed elaboreranno i dati con la scrittura nel secondo file.

Facciamo un esempio:

# 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

Come funziona:

  1. Eseguire il tailfprocesso che seguirà le scritture bar.raw.loge stamparle sull'output standard reindirizzato al while read ... echociclo infinito . Questo ciclo esegue due azioni: leggere i dati dall'input standard in una variabile buffer chiamata linee quindi scrivere il timestamp generato con i seguenti dati bufferizzati nel file bar.log.

  2. Scrivi alcuni messaggi al bar.raw.log. Devi farlo in una finestra terminale separata perché la prima sarà occupata dalla tailfquale seguirà le scritture e farà il suo lavoro. Abbastanza semplice.

I pro è che la tua applicazione non si bloccherebbe se uccidi tailf. I contro sono timestamp meno accurati e file di registro duplicati.


Grazie .Fifo sembra molto adatto al mio uso. Il mio programma scrive già in un registro file.txt ma questo file deve essere reindirizzato al tuo foo.log.fifo. Ma facendo $ tailf file.txt> foo.log.fifo si blocca ! Quindi, come posso reindirizzare i miei contenuti in un file di registro di aggiornamento a questo foo.log.fifo in modo che possa aggiungere anche il tempo.
Kratos,

Ho appena migliorato la risposta. Spiegato perché FIFO blocca il tuo tailf, ha aggiunto il modo giusto di usarlo. In realtà il modo in cui tailfsembra essere più elegante, ma ho lasciato la quindicesima via con la speranza che possa essere utile per qualcuno.
Dmitry Vasilyanov,

L'uso della risposta sed per annotare l'output di vmstat produce un timestamp che non cambia, vmstat 1 | sed -e "s / ^ / $ (date -R) /"
ChuckCottrill


2

Modificato dalla risposta di Dmitry Vasilyanov.

Nello script bash, puoi reindirizzare e avvolgere l'output con timestamp riga per riga al volo.

Quando usare:

  • Per i lavori di script bash, inserire la riga prima dello script principale
  • Per i lavori non script, creare uno script per chiamare il programma.
  • Per il controllo dei servizi da parte del sistema, è meglio usare tailfper il file di registro come ha detto Dmitry Vasilyanov.

Un esempio chiamato 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 il risultato:

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

Come funziona

  1. exec &> Reindirizza stdout e stderr nello stesso posto
  2. >( ... ) pipe emette un comando interno asincrono
  3. La parte restante funziona con l'espansione di Dmitry Vasilyanov.

Per esempio:

  • timestamp pipe e accedere al file

    #!/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
    
  • Oppure stampa il timestamp e accedi a 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
    

    quindi salvarli /etc/crontabnell'impostazione

    * * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
    

1

Ho usato in tsquesto modo per ottenere una voce con un timestamp in un registro errori per uno script che utilizzo per riempire i cactus con le statistiche di un host remoto.

Per testare i cactus utilizzo randper aggiungere alcuni valori casuali che utilizzo per i grafici della temperatura per monitorare la temperatura dei miei sistemi.

Pushmonstats.sh è uno script che raccoglie le statistiche di temperatura del sistema del mio PC e le invia a un Raspberry Pi su cui viene eseguito Cacti. Qualche tempo fa, la rete era bloccata. Ho avuto solo timeout SSH nel mio registro errori. Sfortunatamente, nessuna voce temporale nel registro. Non sapevo come aggiungere un timestamp a una voce del registro. Quindi, dopo alcune ricerche su Internet, mi sono imbattuto in questo post e questo è quello che ho fatto usando ts.

Per testarlo, ho usato un'opzione sconosciuta a rand. Che ha dato un errore a stderr. Per catturarlo, lo reindirizzo a un file temporaneo. Quindi uso cat per mostrare il contenuto del file e inserirlo ts, aggiungere un formato orario che ho trovato in questo post e infine registrarlo nel file di errore. Quindi deseleziono il contenuto del file temporaneo, altrimenti ottengo doppie voci per lo stesso errore.

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

Ciò fornisce quanto segue nel mio registro errori:

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

Forse questo non è un modo molto elegante per farlo, ma funziona. Mi chiedo se esista un approccio più elegante.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.