Comment ajouter un horodatage au journal de script bash?


95

J'ai un script en cours d'exécution que je sortie dans un fichier journal:

script.sh >> /var/log/logfile

J'aimerais ajouter un horodatage avant chaque ligne ajoutée au journal. Comme:

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

Y a-t-il un jujitsu que je peux utiliser?


2
Voir cette question. serverfault.com/questions/80749/… . Une réponse de couple s'appliquerait ici.
Zoredache

Pour une solution awk / gawk, voir: stackoverflow.com/questions/21564/…
Utilisateur

Voici une implémentation complète de la journalisation pour bash: github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Réponses:


88

Vous pouvez diriger la sortie du script via une boucle qui préfixe la date et l'heure actuelles:

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

Si vous l'utilisez souvent, il est facile de créer une fonction bash pour gérer la boucle:

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

3
@Nils c'est un truc pour éviter readde rogner les espaces au début et à la fin de la ligne. Il définit IFS (le séparateur de champs interne de bash, essentiellement une liste de caractères d'espacement) à vide pour la readcommande.
Gordon Davisson

2
... et -r ignore le caractère d'échappement "\". Cela devrait vraiment fonctionner dans tous les cas - une excellente pièce de script.
Nils

7
@Nils n'est pas complètement à l'épreuve des balles, certaines implémentations echointerprétant des séquences d'échappement. Si vous voulez vraiment que le contenu ne soit pas gâché (autre que l'ajout de dates), remplacez la echocommande parprintf "%s %s\n" "$(date)" "$line"
Gordon Davisson le

4
Vous pourriez être intéressé par une date / un horodatage conforme à la norme ISO-8601 : date -u +"%Y-%m-%dT%H:%M:%SZ"ou peut-être plus jolie date +"%Y-%m-%d %T".
Pablo Un

1
Bien que ce script fonctionne comme prévu, il génère un nouveau processus (exécution date) pour chaque ligne de journal, ce qui peut constituer un inconvénient majeur en fonction de votre ordinateur et du nombre de journaux. Je préférerais plutôt utiliser, tssi disponible, voir la réponse de @willem
Michael Schaefers

57

Voir tsle moreutilspaquet Ubuntu :

command | ts

Ou, si $commandla mise en mémoire tampon automatique ( expect-devpackage requis):

unbuffer command | ts

18

La commande date fournira cette information

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

afin que vous puissiez

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

c'est ce que tu voulais?


Utiliser la commande date était un peu ce que j'avais en tête, mais je ne peux pas vraiment l'ajouter au script lui-même. Ce que je recherche, c'est un moyen de changer cette ligne: "script.sh >> / var / log / logfile "pour ajouter la date.
Antonius Bloch

Dans ce cas, redirigez la sortie de votre script vers un canal nommé et demandez à un démon d'écouter la sortie qui prend la sortie du script et ajoute une date avant de l'écrire dans un fichier journal. Vous pouvez probablement modifier le script que j'ai écrit ici pour le faire. Je le ferais parce que cela m'intéresse, mais il est tard au Royaume-Uni et je commence tôt demain.
user9517

12

Vous pouvez simplement faire écho aux sorties de commande dans le fichier journal. c'est à dire,

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

Ça marche vraiment :)

Exemple:

[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]$ 

Hmm ne travaille pas pour moi.
Antonius Bloch

Qu'obtenez-vous lorsque vous exécutez la commande?
SparX

8
Cela met un horodatage avant la sortie entière de '' ./script.sh '', pas avant chaque ligne.
clacke

8

Faire un config.shfichier

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

Lorsque vous devez envoyer à utiliser le fichier journal

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

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

do_what_you_want >> $LOGFILE

Le fichier journal ressemblera à

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

Il sera donc facile de trier par date


8
Votre '' config.sh '' exécutera '' la date '' exactement une fois, sur '' source ... / config.sh ''.
clacke

5

Tu veux dire comme:

(date && script.sh) >> /var/log/logfile

Mon dieu, tout le monde, tout le monde est en train de remplacer les tiques, les pipes nommées, etc. Le type qui a la fonction a un cas légitime s'il existe une sortie multiligne et que le journal doit être joli avec la date sur chaque ligne, mais la plupart de ces solutions sont excessives et n'utilisent pas la sémantique du shell.
cjc

8
Cela n’ajoutera l’horodatage qu’une fois par exécution de script.sh. Le PO nécessite un horodatage par ligne.
Dave Forgac

1
bien que cela ne réponde pas à la question OP, je l’ai toujours trouvée utile.
Utilisateur

4

Essaye ça

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

Appelez cette fonction d'horodatage dans chaque commande echo:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log

@ shazbot: Merci pour l'édition, c'était une erreur de frappe, je n'ai pas remarqué.
Sanjay Yadav

4

La réponse acceptée https://serverfault.com/a/310104 peut être un peu lente s'il faut traiter un grand nombre de lignes, le temps système nécessaire au démarrage du dateprocessus autorisant environ 50 lignes par seconde sous Ubuntu et seulement 10 environ. -20 dans Cygwin.

Quand bashpeut être supposé une alternative plus rapide serait le printfconstruit avec son %(...)Tspécificateur de format. Comparer

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

1

Vous remarquerez peut-être que awk court vite,

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

Mais Sed court beaucoup plus vite.

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

Cependant, à y regarder de plus près, l’ensemble ne semble pas changer de temps,

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

1
c’est parce que c’est une évaluation bash "s/^/$(date -R) /"et une date d’exécution une fois avant sed Sed reçoit une chaîne statique.
Evan Benn

Plain bash: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cce qui est beaucoup plus lent que gawk. tsl'utilitaire a des performances similaires à celles de la boucle bash.
Akhan

Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cce qui est légèrement plus lent que awk.
Akk

1

Ci-dessous le contenu de mon fichier journal

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

une partie de mon contenu est comme ci-dessous

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 

1

Ce script imprime la sortie dans le terminal et enregistre également dans le fichier journal.

#!/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

Exemple de sortie:

[2017-10-29 19:46:36 UTC] - My script is starting
[2017-10-29 19:46:36 UTC] - root

votre commande first date doit utiliser des guillemets simples et non des guillemets doubles.
Jason Harrison

1

Une autre option consiste à configurer une fonction à appeler chaque fois que vous souhaitez générer des données dans votre code:

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

Ensuite, chaque fois dans votre code, vous voulez l'envoyer à l'appel du fichier journal

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

Peasy facile....


0

Pipe a "sed":

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile

Pour ce qui est de l’autre réponse, il ne s’agit que d’une seule fois. sed ne met pas à jour le temps par ligne.
Evan Benn
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.