Sello de marca de tiempo anexa junto con líneas de archivo de registro

11

Tengo un archivo de registro y necesito agregar marcas de tiempo a cada línea a medida que se agregan. Entonces, estoy buscando un script que agregue marcas de tiempo a cada entrada en las líneas de registro y que pueda ejecutarse como un trabajo cron.

Kratos
fuente

Respuestas:

18

El camino general

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

Cómo funciona:

  1. catlee el archivo llamado input.logy simplemente lo imprime en su flujo de salida estándar.

    Normalmente, la salida estándar está conectada a un terminal, pero este pequeño script contiene, |por lo que Shell redirige la salida estándar de cata la entrada estándar de sed.

  2. sedlee los datos (a medida que los catproduce), los procesa (de acuerdo con el script proporcionado con la -eopción) y luego los imprime en su salida estándar. El script "s/^/$(date -R) /"significa reemplazar cada inicio de línea por un texto generado por date -Rcomando (la construcción general para el comando de reemplazo es:) s/pattern/replace/.

  3. Luego, de acuerdo con >> bashredirige la salida seda un archivo llamado output.log( >significa reemplazar el contenido del archivo y >>significa agregar al final).

El problema se $(date -R)evalúa una vez cuando ejecuta el script para que inserte la marca de tiempo actual al comienzo de cada línea. La marca de tiempo actual puede estar lejos de un momento en que se generó un mensaje. Para evitarlo, debe procesar los mensajes tal como están escritos en el archivo, no con un trabajo cron.

FIFO

La redirección de flujo estándar descrita anteriormente se llama tubería . Puede redirigirlo no solo |entre comandos en el script, sino a través de un archivo FIFO (también conocido como pipe ). Un programa escribirá en el archivo y otro leerá los datos y los recibirá como los primeros envíos.

Elige un ejemplo:

$ 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

Cómo funciona:

  1. mkfifo crea una tubería con nombre

  2. while true; do sed ... ; doneejecuta un bucle infinito y en cada iteración se ejecuta sedcon la redirección foo.log.fifoa su entrada estándar; sed bloquea la espera de datos de entrada y luego procesa un mensaje recibido y lo imprime a la salida estándar redirigida a foo.log.

    En este punto, debe abrir una nueva ventana de terminal porque el bucle ocupa el terminal actual.

  3. echo ... > foo.log.fifoimprime un mensaje a su salida estándar redirigida al archivo fifo y lo sedrecibe y procesa y escribe en un archivo normal.

La nota importante es el Fifo al igual que cualquier otra tubería no tiene sentido si uno de sus lados no está conectado a ningún proceso. Si intenta escribir en una tubería, el proceso actual se bloqueará hasta que alguien lea los datos al otro lado de la tubería. Si desea leer desde una tubería, el proceso se bloqueará hasta que alguien escriba datos en la tubería. El sedbucle en el ejemplo anterior no hace nada (duerme) hasta que lo haga echo.

Para su situación particular, simplemente configure su aplicación para escribir mensajes de registro en el archivo fifo. Si no puede configurarlo, simplemente elimine el archivo de registro original y cree un archivo fifo. Pero tenga en cuenta nuevamente que si el sedbucle muere por alguna razón, su programa se bloqueará al intentar ingresar al writearchivo hasta que alguien lo haga readdesde el quinto.

El beneficio es la marca de tiempo actual evaluada y adjuntada a un mensaje a medida que el programa lo escribe en el archivo.

Procesamiento asincrónico con tailf

Para que la escritura en el registro y el procesamiento sean más independientes, puede usar dos archivos normales con tailf. Una aplicación escribirá un mensaje en un archivo sin procesar y otro proceso leerá nuevas líneas (siga las escrituras de forma asincrónica) y procesará los datos con la escritura en el segundo archivo.

Tomemos un ejemplo:

# 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

Cómo funciona:

  1. Ejecute el tailfproceso que seguirá las escrituras bar.raw.loge imprimirá a la salida estándar redirigida al while read ... echobucle infinito . Este bucle realiza dos acciones: leer datos desde la entrada estándar a una variable de búfer llamada liney luego escribir la marca de tiempo generada con los siguientes datos almacenados en el búfer bar.log.

  2. Escribe algunos mensajes al bar.raw.log. Debe hacer esto en una ventana de terminal separada porque la primera estará ocupada por la tailfque seguirá las escrituras y hará su trabajo. Bastante sencillo.

La ventaja es que tu aplicación no se bloquearía si matas tailf. Las desventajas son las marcas de tiempo menos precisas y la duplicación de archivos de registro.

Dmitry Vasilyanov
fuente
Gracias .Fifo parece muy apto para mi uso. Mi programa ya escribe en un registro file.txt pero este archivo debe ser redirigido a su foo.log.fifo. Pero se cuelga $ tailf file.txt> foo.log.fifo ! Entonces, ¿cómo puedo redirigir mis contenidos en un archivo de registro de actualización a este foo.log.fifo para que también pueda agregar la hora?
Kratos
Solo mejoré la respuesta. Explicó por qué fifo bloquea su tailf, agregó la forma correcta de usarlo. En realidad, el camino con tailfparece ser más elegante, pero salí del quinto camino con la esperanza de que sea útil para alguien.
Dmitry Vasilyanov
El uso de su respuesta sed para anotar la salida de vmstat produce una marca de tiempo que no cambia, vmstat 1 | sed -e "s / ^ / $ (date -R) /"
ChuckCottrill
6

Puede usar el tsscript perl de moreutils:

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

Modificado de la respuesta de Dmitry Vasilyanov.

En el script bash, puede redirigir y ajustar la salida con marca de tiempo línea por línea sobre la marcha.

Cuándo usar:

  • Para trabajos de script bash, inserte la línea antes del script principal
  • Para trabajos sin guión, cree un guión para llamar al programa.
  • Para el control de servicios por sistema, es mejor usarlo tailfpara el archivo de registro como dijo Dmitry Vasilyanov.

Un ejemplo llamado 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"

Y el 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

Cómo funciona

  1. exec &> Redireccionar stdout y stderr al mismo lugar
  2. >( ... ) salidas de tubería a un comando interno asíncrono
  3. La parte restante funciona cuando Dmitry Vasilyanov se expandió.

Por ejemplo:

  • marcar la hora de la tubería e iniciar sesión en el archivo

    #!/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
    
  • O imprima la marca de tiempo e inicie sesión en 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
    

    luego guardarlos en la /etc/crontabconfiguración

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

Utilicé tsesta manera para obtener una entrada con una marca de tiempo en un registro de errores para un script que utilizo para llenar Cacti con estadísticas de un host remoto.

Para probar Cacti, utilizo randpara agregar algunos valores aleatorios que utilizo para los gráficos de temperatura para controlar la temperatura de mis sistemas.

Pushmonstats.sh es un script que recopila estadísticas de temperatura del sistema de mi PC y las envía a una Raspberry Pi en la que se ejecuta Cacti. Hace algún tiempo, la red estaba atascada. Solo obtuve tiempos de espera de SSH en mi registro de errores. Desafortunadamente, no hay entradas de tiempo en ese registro. No sabía cómo agregar una marca de tiempo a una entrada de registro. Entonces, después de algunas búsquedas en Internet, me topé con esta publicación y esto es lo que hice usando ts.

Para probarlo, utilicé una opción desconocida para rand. Lo que le dio un error a stderr. Para capturarlo, lo redirijo a un archivo temporal. Luego uso cat para mostrar el contenido del archivo y canalizarlo ts, agregar un formato de hora que encontré en esta publicación y finalmente registrarlo en el archivo de error. Luego borro el contenido del archivo temporal, de lo contrario obtengo entradas dobles para el mismo error.

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

Esto da lo siguiente en mi registro de errores:

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

Quizás esta no sea una forma muy elegante de hacerlo, pero funciona. Me pregunto si hay un enfoque más elegante.

Franco
fuente