Пусть Bash скрипт ожидает сообщения о состоянии, прежде чем продолжить


10

Я запускаю сервер Selenium с помощью bash-скрипта, и, как вы можете видеть из временных меток в журнале, приведенном ниже, требуется около 32 секунд, чтобы вещь полностью подключилась к сети:

Feb 28, 2012 10:19:02 PM org.openqa.grid.selenium.GridLauncher main
INFO: Launching a standalone server
22:19:02.835 INFO - Java: Sun Microsystems Inc. 20.0-b11
22:19:02.836 INFO - OS: Linux 2.6.32-220.4.1.el6.x86_64 amd64
22:19:02.852 INFO - v2.19.0, with Core v2.19.0. Built from revision 15849
22:19:02.988 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
22:19:02.990 INFO - Version Jetty/5.1.x
22:19:02.992 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
22:19:02.993 INFO - Started HttpContext[/selenium-server,/selenium-server]
22:19:02.993 INFO - Started HttpContext[/,/]
22:19:34.552 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler@488e32e7
22:19:34.552 INFO - Started HttpContext[/wd,/wd]
22:19:34.555 INFO - Started SocketListener on 0.0.0.0:4444
22:19:34.555 INFO - Started org.openqa.jetty.jetty.Server@7d29f3b5

Вместо использования команды «sleep 32» после запуска сервера (чтобы отложить выполнение сценария перед продолжением), я бы хотел, чтобы мой сценарий bash подождал, пока он увидит строку «Started SocketListener», а затем продолжил. Это возможно?

Ответы:


8

Вы можете использовать, tail -fчтобы продолжить чтение из файла по мере его роста. Будьте осторожны с тем, что вы кормите tail -f. Вы можете направить tail -fв фильтр, который ждет, пока нужная строка журнала не завершится. Что не сработает, так это если вы направите канал tail -fв фильтр, который направляет в другой фильтр, потому что промежуточный фильтр будет буферизовать свой вывод. Это работает:

: >file.log  # create an empty log file
start-selenium-session --log-file=file.log &
{ tail -n +1 -f file.log & } | sed -n '/Started SocketListener/q'
speak-to-socket

Обратите внимание, что я поставил tailв фоновом режиме. Это связано с тем, что, когда sedнаходит нужную строку, она завершается, но конвейер продолжает работать до тех пор, tailпока ожидает следующую строку, которая может не появиться немедленно, если вообще будет ». tailвыйдет, когда придет следующая строка и он получит SIGPIPE. Это может привести к сбоям в tailпроцессе, если журнал удаляется без записи в него какой-либо строки (получение PID tailпроцесса для его уничтожения при sedвыходе может быть возможно, но сложно).

¹ Благодаря Peter.O за указание на ошибку в предыдущей версии.


Примечание (возможно, педантизм) - я не знаю каких-либо оболочек, для которых на самом деле требуется noop, чтобы разрешить запись пустого файла.
Крис Даун

@ChrisDown Я тоже не знаю. Но я нахожу более понятным написать неоперативный текст явно.
Жиль "ТАК - перестань быть злым"

Приятно (+1) ... говорить о буферах: я не понимаю махинации буферизации, но есть одна проблема, о которой следует знать, если за целевой строкой сразу не следует больше строк журнала. Он зависает, пока не написано больше строк, даже если sed уже соответствует шаблону (<- я не понимаю эту часть). Модифицированная sedкоманда, которая записывает достаточно в журнал, чтобы вызвать сброс (?), Немедленно запускает его (я проверял это), но я думаю, что есть вероятность, что вставленные данные будут чередоваться со строкой сеанса селена. .
Peter.O

@ Peter.O IIRC Некоторые реализации sed читают следующую строку заранее, потому что есть случаи, когда это полезно ( $адрес, например). Я не видел, чтобы это случилось в моих тестах (с GNU sed). Как именно вы выставили ошибку, на какой ОС?
Жиль "ТАК ... перестать быть злым"

@Gilles: paste.ubuntu.com/863326 .. и: GNU sed версия 4.2.1 , tail (GNU coreutils) 7.4
Peter.O

3

Это немного сложнее в прямом сценарии оболочки, но это то, что я использовал довольно долго для tomcat и oc4j:

perlscr='
alarm 120;
open F, "<$ARGV[0]";
seek F -($ARGV[1]*80),2;
while (1) {exit if (<F>=~$ARGV[2]);}'

window=10
scanfor="^INFO: Server startup in \d+ ms"
perl -e "$perlscr" $logfile $window "$scanfor" 2>&1 0<&1

Он alarmбудет обрабатывать любые потенциальные зависания в случае сбоя tomcat. Количество строк, возвращаемых из EOF, регулируется (из файла конфигурации).

В конце концов я переместил все это на Python; хотя он немного длиннее, он немного эффективнее:

class Alarm:
    import signal
    signal_signal = signal.signal
    signal_SIGALRM = signal.SIGALRM
    signal_SIG_DFL = signal.SIG_DFL
    del signal
    def __init__(self, delay)
       self.howlong = delay
       self.clear()
    def __del__(self):
       self.reset_signals()
    def __nonzero__(self):
       return self.state
    def clear(self):
       self.state = False
       self.reset_signals()
    def _start_alarm(self):
       from signal import alarm
       alarm(self.howlong)
    def _set_sigalarm(self, handler):
        if handler:
            self.signal_signal(self.signal_SIGALRM, handler)
        else:
            self.signal_signal(self.signal_SIGALRM, self.signal_SIG_DFL)
    def reset_signals(self):
        self._set_sigalarm(None)
    def set_signals(self):
        self._set_sigalarm(self.handler)
    def handler(self, signo, frame):
        self.state = False
    def start(self):
        self.state = True
        self.set_signals()
        self._start_alarm()
    def stop(self):
        self.reset_signals()
        self.state = False
found = False
scanfor = re.compile('^INFO: Server startup in \d+ ms')
window = 10
logfile = open(logfilename, 'r')
logfile.seek(window * 80, 2)
alarm = Alarm(timeout)
try:
    alarm.start()
    while alarm:
        line = logfile.readline()
        if line:
            m = scanfor.search(line)
            if m:
                alarm.stop()
                found = True
                break
        time.sleep(0.1)
finally:
    alarm.clear()

1

Вы можете добавить это в ваш скрипт для реализации паузы:

perl -e 'use File::Tail;
    my $ref=tie *FH,"File::Tail",(name=>"/var/log/messages",maxinterval=>1);
    while(<FH>) { exit if /Started SocketListener/ };'

Он использует модуль perl File :: Tail, чтобы вести себя как tail -f logfile | grep Started SocketListener.

Замените / var / log / message соответствующим файлом журнала. Обратите внимание, что он будет зависать вечно, если «Started SocketListener» никогда не появляется.


1

Может быть, вы должны использовать тайм-аут, а не ждать бесконечно.

Приведенная ниже функция bash будет блокироваться до тех пор, пока не появится заданное условие поиска или не истечет заданное время ожидания.

Статус выхода будет 0, если строка найдена в течение времени ожидания.

wait_str() {
  local file="$1"; shift
  local search_term="$1"; shift
  local wait_time="${1:-5m}"; shift # 5 minutes as default timeout

  (timeout $wait_time tail -F -n0 "$file" &) | grep -q "$search_term" && return 0

  echo "Timeout of $wait_time reached. Unable to find '$search_term' in '$file'"
  return 1
}

Возможно, файл журнала еще не существует сразу после запуска Selenium. В этом случае вам следует подождать, пока он появится, прежде чем искать строку:

wait_selenium_server() {
  echo "Waiting for Selenium server..."
  local server_log="$1"; shift
  local wait_time="$1"; shift

  wait_file "$server_log" 10 || { echo "Selenium log file missing: '$server_log'"; return 1; }

  wait_str "$server_log" "Started SocketListener" "$wait_time"
}

wait_file() {
  local file="$1"; shift
  local wait_seconds="${1:-10}"; shift # 10 seconds as default timeout

  until test $((wait_seconds--)) -eq 0 -o -f "$file" ; do sleep 1; done

  ((++wait_seconds))
}

Вот как вы можете использовать это:

wait_selenium_server "/var/log/selenium.log" 5m && \
echo -e "\n-------------------------- Selenium READY --------------------------\n"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.