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?

Antonius Bloch
la source
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
Gordon Davisson
la source
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
Willem
la source
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?

utilisateur9517
la source
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:

[[email protected]]$ ./script.sh 
Hello Worldy
[[email protected]]$ echo "`date -u` `./script.sh`" >> logfile.txt
[[email protected]]$ cat logfile.txt 
Mon Sep 12 20:18:28 UTC 2011 Hello Worldy
[[email protected]]$ 
SparX
la source
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

scls
la source
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
cjc
la source
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
Sanjay Yadav
la source
@ 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
kdb
la source
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) /"
ChuckCottrill
la source
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

[email protected]:~/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 
Jayhello
la source
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
Seff
la source
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....

Josh Williams
la source
0

Pipe a "sed":

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile
eubide
la source
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