Wie füge ich einen Zeitstempel zum Bash-Skript-Protokoll hinzu?

94

Ich habe ein ständig laufendes Skript, das ich in eine Protokolldatei ausgebe:

script.sh >> /var/log/logfile

Ich möchte vor jeder Zeile, die an das Protokoll angehängt wird, einen Zeitstempel einfügen. Mögen:

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

Gibt es ein Jujitsu, das ich verwenden kann?

Antonius Bloch
quelle
2
Siehe diese Quest. serverfault.com/questions/80749/… . Eine paar Antwort würde hier gelten.
Zoredache
Eine awk / gawk-Lösung finden Sie unter: stackoverflow.com/questions/21564/…
User
Hier ist eine umfassende Implementierung der Protokollierung für Bash: github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Antworten:

88

Sie können die Ausgabe des Skripts durch eine Schleife leiten, die dem aktuellen Datum und der aktuellen Uhrzeit vorangestellt ist:

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

Wenn Sie dies häufig verwenden, ist es einfach, eine Bash-Funktion zum Behandeln der Schleife zu erstellen:

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
quelle
3
@Nils ist ein Trick, um zu verhindern, dass readLeerzeichen am Anfang und am Ende der Zeile abgeschnitten werden. Es setzt IFS (Bashs Internal Field Separator, im Grunde eine Liste von Whitespace-Zeichen) auf leer für den readBefehl.
Gordon Davisson
2
... und -r ignorieren das Escape-Zeichen "\". Dies sollte in jedem Fall wirklich funktionieren - ein großartiges Skripting.
Nils
7
@Nils ist nicht vollständig kugelsicher, da einige Implementierungen echoEscape-Sequenzen interpretieren. Wenn Sie wirklich möchten, dass der Inhalt nicht verfälscht wird (außer das Hinzufügen von Datumsangaben), ersetzen Sie den echoBefehl durchprintf "%s %s\n" "$(date)" "$line"
Gordon Davisson,
4
Sie könnten an einem interessiert sein ISO-8601 - konform : Datum / Zeitstempel date -u +"%Y-%m-%dT%H:%M:%SZ"oder vielleicht mehr recht date +"%Y-%m-%d %T".
Pablo A
1
Während dieses Skript wie erwartet funktioniert, wird datefür jede Protokollzeile ein neuer Prozess erzeugt (ausgeführt ). Dies kann je nach Computer und Anzahl der Protokolle ein schwerwiegender Nachteil sein. Ich würde eher vorschlagen , zu verwenden , tswenn vorhanden, siehe die Antwort von @willem
Michael Schaefers
56

Siehe tsaus dem Ubuntu- moreutilsPaket:

command | ts

Oder, wenn $commandautomatische Pufferung (erfordert expect-devPaket):

unbuffer command | ts
Willem
quelle
18

Der Datumsbefehl liefert diese Informationen

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

also kannst du

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

ist es das was du wolltest ?

user9517
quelle
Die Verwendung des Datumsbefehls war in etwa das, was ich vorhatte, aber ich kann das nicht wirklich zum Skript selbst hinzufügen. Ich suche also nach einer Möglichkeit, diese Zeile zu ändern: "script.sh >> / var / log / logfile ", um das Datum anzufügen.
Antonius Bloch
In diesem Fall leiten Sie die Ausgabe Ihres Skripts an eine Named Pipe um und lassen einen Daemon auf die Ausgabe warten, der die Skriptausgabe aufnimmt und ein Datum hinzufügt, bevor er sie in eine Protokolldatei schreibt. Sie können wahrscheinlich das Skript, das ich hier geschrieben habe, ändern , um dies zu tun. Ich würde es tun, weil es mich interessiert, aber es ist spät in Großbritannien und ich habe einen frühen Start morgen.
user9517
12

Sie können einfach echo den Befehl gibt an die Log - Datei. dh

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

Es funktioniert wirklich :)

Beispiel:

[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
quelle
Hmm arbeitet nicht für mich.
Antonius Bloch
Was bekommen Sie, wenn Sie den Befehl ausführen?
SparX
8
Das setzt einen Zeitstempel vor die gesamte Ausgabe von '' ./script.sh '', nicht vor jede Zeile.
Klackern Sie am
8

Machen Sie eine config.shDatei

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

Wenn Sie senden müssen, um die Protokolldatei zu verwenden

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

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

do_what_you_want >> $LOGFILE

Protokolldatei sieht aus wie

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

So ist es einfach, nach Datum zu sortieren

scls
quelle
8
Ihre '' config.sh '' führt '' date '' genau einmal in '' source ... / config.sh '' aus.
Klackern
5

Du meinst wie:

(date && script.sh) >> /var/log/logfile
cjc
quelle
Mein Gott, Leute, jeder macht Back Tick Replacement, Named Pipes, etc. Fügen Sie einfach sowohl das Datums-Kommando als auch das Skript in Parens ein! Der Typ, der die Funktion hat, hat einen legitimen Fall, wenn es eine mehrzeilige Ausgabe gibt und das Protokoll mit dem Datum in jeder Zeile hübsch aussehen muss, aber die meisten dieser Lösungen sind übertrieben und verwenden keine Shell-Semantik.
cjc
8
Dadurch wird der Zeitstempel nur einmal pro Ausführung von hinzugefügt script.sh. Das OP benötigt einen Zeitstempel pro Zeile.
Dave Forgac
1
Obwohl dies die OP-Frage nicht beantwortet, fand ich sie dennoch nützlich.
Benutzer
4

Versuche dies

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

Rufen Sie diese Zeitstempelfunktion in jedem Echo-Befehl auf:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log
Sanjay Yadav
quelle
@shazbot: Danke für die Bearbeitung, das war ein Tippfehler, ich habe es nicht bemerkt.
Sanjay Yadav
4

Die akzeptierte Antwort https://serverfault.com/a/310104 kann etwas langsam sein, wenn viele Zeilen verarbeitet werden müssen, wobei der Aufwand für das Starten des dateProzesses in Ubuntu etwa 50 Zeilen pro Sekunde und nur etwa 10 zulässt -20 in Cygwin.

Wann bashkann eine schnellere Alternative angenommen werden, wäre das printfeingebaute mit seinem %(...)TFormatbezeichner. Vergleichen Sie

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

Sie könnten feststellen, dass awk schnell läuft,

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

Aber sed läuft viel schneller,

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

Bei näherer Betrachtung scheint sich die Zeit jedoch nicht zu ändern.

vmstat 1 | sed -e "s/^/$(date -R) /"
ChuckCottrill
quelle
1
Dies liegt daran, dass es sich um eine Bash handelt, "s/^/$(date -R) /"die das Datum einmal vor dem Sed bewertet und ausführt. Sed wird eine statische Zeichenfolge übergeben.
Evan Benn
Plain Bash: Das yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cist viel langsamer als Gawk. tsDas Dienstprogramm hat eine ähnliche Leistung wie die Bash-Schleife.
27.
Perl: Das yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cist etwas langsamer als awk.
Akhan
1

Das Folgende ist der Inhalt meiner Protokolldatei

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

Einige meiner Shell-Inhalte sind wie folgt

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

Dieses Skript druckt die Ausgabe im Terminal und speichert sie auch in einer Protokolldatei.

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

Beispielausgabe:

[2017-10-29 19:46:36 UTC] - My script is starting
[2017-10-29 19:46:36 UTC] - root
Seff
quelle
Ihr erster Date-Befehl sollte einfache Anführungszeichen und keine doppelten Anführungszeichen verwenden.
Jason Harrison
1

Eine andere Möglichkeit besteht darin, eine Funktion einzurichten, die jedes Mal aufgerufen wird, wenn Sie Daten in Ihrem Code ausgeben möchten:

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

Anschließend möchten Sie den Code jedes Mal an den Protokolldateiaufruf senden

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

Kinderleicht....

Josh Williams
quelle
0

Pipe ein "sed":

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile
eubide
quelle
Was die andere Antwort betrifft, ist dies nur ein einziges Mal ein Bash-Laufdatum. sed aktualisiert die Zeit pro Zeile nicht.
Evan Benn