Як додати часову позначку до журналу скриптів bash?


94

У мене постійно працює сценарій, який виводяться в файл журналу:

script.sh >> /var/log/logfile

Я хотів би додати часову позначку перед кожним рядком, який додається до журналу. Подібно до:

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

Чи є який-небудь джуджіцу, який я можу використовувати?


2
Дивіться цей квест. serverfault.com/questions/80749/… . Тут відповість пара відповідей.
Zoredache

Про рішення awk / gawk дивіться: stackoverflow.com/questions/21564/…
Користувач

Ось комплексна реалізація журналів для bash: github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Відповіді:


88

Ви можете передавати висновок сценарію через цикл, який префіксує поточну дату та час:

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

Якщо ви багато використовуєте це, легко зробити функцію bash для обробки циклу:

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 це хитрість запобігти readобрізанню пробілів на початку та в рядку. Він встановлює IFS (bash's Internal Field Separator, в основному список символів пробілу) порожнім для readкоманди.
Гордон Девіссон

2
... і -r ігнорує символ втечі "\". Це дійсно має спрацювати у всіх випадках - чудова сценарія сценаріїв.
Нілс

7
@Nils це не зовсім бронезахищеність, оскільки деякі реалізації echoінтерпретують послідовності втечі. Якщо ви дійсно хочете, щоб він не псувався зі змістом (крім додавання дат), замініть echoкоманду наprintf "%s %s\n" "$(date)" "$line"
Гордон Девіссон

4
Можливо, вас зацікавить дата / часова позначка, сумісна з ISO-8601 : date -u +"%Y-%m-%dT%H:%M:%SZ"або, можливо, більш красива date +"%Y-%m-%d %T".
Пабло А

1
хоча цей сценарій працює, як очікувалося, він породжує новий процес (виконання date) для кожного рядка журналу, який може бути величезним недоліком залежно від вашої машини та кількості журналів. Я б запропонував використовувати, tsякщо є, дивіться відповідь від @willem
Michael Schaefers

56

Дивіться tsу moreutilsпакеті Ubuntu :

command | ts

Або якщо $commandавтоматична буферизація (потрібен expect-devпакет):

unbuffer command | ts

18

Команда дати надасть цю інформацію

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

щоб ви могли

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

це те, чого ти хотів?


Використання команди date було таким, що я мав на увазі, але я не можу реально додати це до самого сценарію, тому я шукаю спосіб змінити цей рядок: "script.sh >> / var / log / logfile ", щоб додати дату.
Антоній Блох

У такому випадку перенаправляйте висновок вашого скрипту на іменовану трубу і демонструйте прослуховування для виводу, який приймає вихід сценарію та додає дату перед записом у файл журналу. Ви можете, можливо, змінити сценарій, який я написав тут, щоб це зробити. Я б це зробив, тому що мене це цікавить, але у Великобританії вже пізно, і завтра у мене ранній початок.
користувач9517

12

Ви можете просто відлучити командні виходи до журналу. тобто

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

Це справді працює :)

Приклад:

[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

8
Це ставить часову позначку перед усім виходом '' ./script.sh '', а не перед кожним рядком.
клак

8

Складіть config.shфайл

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

Коли вам потрібно відправити в журнал використання файлів

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

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

do_what_you_want >> $LOGFILE

Файл журналу виглядатиме так

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

Тож їх буде легко сортувати за датою


8
Ваш 'config.sh' 'запустить' 'date' 'рівно один раз у' 'source ... / config.sh' '.
clacke

5

Ви маєте на увазі, як:

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

Мій боже, люди, всі роблять заміну кліщів, називають труби тощо. Просто додайте і команду дати, і сценарій до паролів! Хлопець, який має цю функцію, має законний випадок, якщо є багаторядковий вихід і журнал повинен виглядати досить з датою в кожному рядку, але більшість цих рішень є надмірними, які не використовують семантику оболонки.
cjc

8
Це додасть часову позначку лише один раз за виконання script.sh. ОП потребує позначки часу на рядок.
Дейв Forgac

1
хоча це не відповідає на питання ОП, я все-таки вважав його корисною інформацією.
Користувач

4

Спробуйте це

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

Викликайте цю функцію часової позначки в кожній команді echo:

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

@ shazbot: Дякую за редагування, це була помилка друку, я не помічав.
Санджай Ядав

4

Прийнята відповідь https://serverfault.com/a/310104 може бути трохи повільною, якщо потрібно обробити багато рядків, накладні витрати на початок dateпроцесу дозволяють в Ubuntu приблизно 50 рядків на секунду, і лише близько 10 -20 у Cygwin.

Коли bashможна припустити, більш швидкою альтернативою буде printfвбудований з його %(...)Tспецифікатором формату. Порівняйте

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

Ви можете відзначити, що awk працює швидко,

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

Але сед працює набагато швидше,

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

Однак, при більш детальному огляді, набір, здається, не змінює час,

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

1
це тому, що це баш оцінювання "s/^/$(date -R) /"та запуску дати один раз перед sed. Sed передається статична рядок.
Еван Бенн

Звичайний баш: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cякий набагато повільніше, ніж гоук. tsутиліта має аналогічні показники, як і bash loop.
акхан

Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cякий трохи повільніше, ніж awk.
акхан

1

Нижче наведено вміст мого файлу журналу

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

деякий вміст моєї оболонки наведено нижче

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

Цей сценарій друкує вихід у терміналі, а також зберігає файл журналу.

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

Вибірка зразка:

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

ваша команда першого побачення повинна використовувати одинарні лапки, а не подвійні лапки.
Джейсон Харрісон

1

Інший варіант - налаштувати функцію для виклику кожного разу, коли ви бажаєте вивести дані у свій код:

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

Потім кожен раз у своєму коді потрібно відправляти його на виклик файлу журналу

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

Простенька....


0

Труба "sed":

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

що стосується іншої відповіді, то це просто ударна дата запуску один раз. sed не оновлює час за рядком.
Еван Бенн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.