Как получить последние 10 минут журналов с удаленного хоста - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь получить последние x минут журналов с /var/log/maillog с удаленного хоста (я использую этот скрипт в icinga2), но безуспешно.

Я пробовал несколько комбинаций awk, sed и grep, но ни одна из них не сработала. Я думал, что это была проблема с двойными кавычками против одинарных кавычек, но я играл с ними, и ничего не помогло.

host=$1
LOG_FILE=/var/log/maillog

hour_segment=$(ssh -o 'StrictHostKeyChecking=no' myUser@${host} 2>/dev/null "sed -n "/^$(date --date='10 minutes ago' '+%b %_d %H:%M')/,\$p" ${LOG_FILE}")

echo "${hour_segment}"

При запуске скрипта с помощью bash -x я получаю следующий вывод:

bash -x ./myScript.sh host.domain
+ host=host.domain
+ readonly STATE_OK=0
+ STATE_OK=0
+ readonly STATE_WARN=1
+ STATE_WARN=1
+ LOG_FILE=/var/log/maillog
+++ date '--date=10 minutes ago' '+%b %_d %H:%M'
++ ssh -o StrictHostKeyChecking=no myUser@host.domain 'sed -n /^Jan' 8 '12:56/,$p /var/log/maillog'
+ hour_segment=
+ echo ''

Вывод файла журнала почты. Мне бы хотелось, чтобы $hour_segment выглядел так же, как показано ниже, чтобы я мог применить к нему фильтры:

head -n 5 /var/log/maillog
Jan  6 04:03:36 hostname imapd: Disconnected, ip=[ip_address], time=5
Jan  6 04:03:36 hostname postfix/smtpd[9501]: warning: unknown[ip_address]: SASL LOGIN authentication failed: authentication failure
Jan  6 04:03:37 hostname imapd: Disconnected, ip=[ip_address], time=5
Jan  6 04:03:37 hostname postfix/smtpd[7812]: warning: unknown[ip_address]: SASL LOGIN authentication failed: authentication failure
Jan  6 04:03:37 hostname postfix/smtpd[7812]: disconnect from unknown[ip_address]

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Использование функций времени GNU awk:

$ awk '
BEGIN {
    m["Jan"]=1               # convert month abbreviations to numbers 
    # fill in the rest       # fill in the rest of the months
    m["Dec"]=12
    nowy=strftime("%Y")      # assume current year, deal with Dec/Jan below
    nowm=strftime("%b")      # get the month, see above comment
    nows=strftime("%s")      # current epoch time
}
{                            # below we for datespec for mktime
    dt=(nowm=="Jan" && $1=="Dec"?nowy-1:nowy) " " m[$1] " " $2 " " gensub(/:/," ","g",$3)
    if(mktime(dt)>=nows-600) # if timestamp is less than 600 secs away
        print                # print it
}' file

Текущий год принят. Если это январь, а в журнале декабрь, мы вычитаем один год из даты mktime: (nowm=="Jan" && $1=="Dec"?nowy-1:nowy). Даты: Jan 6 04:03:37 -> 2019 1 6 04 03 37 и для сравнения в форме эпохи: 1546740217.

Редактировать : Поскольку никто не реализовал мои спецификации в комментариях, я сделаю это сам. tac выводит файл в обратном порядке, и awk печатает записи, когда они находятся в заданном временном интервале (t - сейчас или в будущем), и завершает работу, как только он встречает дату вне временного интервала:

$ tac file | awk -v t=600 '   # time in seconds go here
BEGIN {
    m["Jan"]=1
    # add more months
    m["Dec"]=12
    nowy=strftime("%Y")
    nowm=strftime("%b")
    nows=strftime("%s")
} {
    dt=(nowm=="Jan" && $1=="Dec"?nowy-1:nowy) " " m[$1] " " $2 " " gensub(/:/," ","g",$3)
    if(mktime(dt)<nows-t)     # this changed some
        exit                
    else 
        print
}' 
0 голосов
/ 08 января 2019

Найти надежное решение, которое будет работать на 100% пуленепробиваемо, очень сложно, так как нам не хватает самой важной информации, год .

Представьте, что вам нужны последние 10 минут доступных данных 01 марта 2020 в 00: 05: 00 . Это немного раздражает, поскольку существует 29 февраля 2020 . Но в 2019 году это не так.

Я представляю здесь уродливое решение, которое рассматривает только третье поле (время), и сделаю следующие предположения:

  • Лог-файл отсортирован по времени
  • В каждый день есть как минимум один журнал!

В этих условиях мы можем отслеживать скользящее окно , начиная с первого доступного времени.

Если вы сохраните следующее в файле extractLastLog.awk

{ t=substr($3,1,2)*3600 + substr($3,4,2)*60 + substr($3,7,2) + offset}
(t < to) { t+=86400; offset+=86400 }
{ to = t }
(NR==1) { startTime = t; startIndex = NR }
{ a[NR]=$0; b[NR]=t }
{ while ( startTime+timeSpan*60 <= t ) { 
      delete a[startIndex]
      delete b[startIndex]
      startIndex++; startTime=b[startIndex]
  }
}
END { for(i=startIndex; i<=NR; ++i) print a[i] }

, затем вы можете извлечь последние 23 минуты следующим образом:

awk -f extractLastLog.awk -v timeSpan=23 logfile.log

Второе условие, которое я дал ( Существует хотя бы один журнал каждый день! ), необходимо, чтобы результаты не испортились. В приведенном выше коде я вычисляю время довольно просто, HH*3600 + MM*60 + SS + offset. Но я утверждаю, что если текущее время меньше предыдущего, это означает, что мы находимся в другой день, поэтому мы обновляем смещение на 86400 секунд. Так что если у вас есть две записи, такие как:

Jan 09 12:01:02 xxx 
Jan 10 12:01:01 xxx 

это будет работать, но это

Jan 09 12:01:00 xxx 
Jan 10 12:01:01 xxx 

не будет работать. Он не осознает, что день изменился. Другие случаи, которые потерпят неудачу:

Jan 08 12:01:02 xxx 
Jan 10 12:01:01 xxx 

поскольку он не знает, что прыгнул два дня. Исправления для этого не легко из-за месяцев (все благодаря високосным годам).

Как я уже сказал, это ужасно, но может сработать.

...