Lassen Sie das Bash-Skript auf die Statusmeldung warten, bevor Sie fortfahren


10

Ich starte den Selenium-Server mit einem Bash-Skript. Wie Sie den Zeitstempeln im folgenden Protokoll entnehmen können, dauert es ungefähr 32 Sekunden, bis das Ding vollständig online ist:

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

Anstatt nach dem Starten des Servers den Befehl "sleep 32" zu verwenden (um das Skript zu verzögern, bevor Sie fortfahren), möchte ich, dass mein Bash-Skript wartet, bis die Zeichenfolge "Started SocketListener" angezeigt wird, und dann fortfährt. Ist das möglich?

Antworten:


8

Sie können verwenden tail -f, um die Datei weiter zu lesen, während sie wächst. Seien Sie vorsichtig mit dem, was Sie füttern tail -f. Sie können tail -fin einen Filter leiten, der bis zur gewünschten Protokollzeile wartet und beendet wird. Was nicht funktioniert, ist, wenn Sie tail -fin einen Filter leiten, der in einen anderen Filter geleitet wird, da der Zwischenfilter seine Ausgabe puffert. Das funktioniert:

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

Beachten Sie, dass ich tailin den Hintergrund gestellt habe. Dies liegt daran, dass seddie gewünschte Leitung beendet wird, aber die Pipeline läuft weiter, solange tailsie auf die nächste Leitung wartet, die möglicherweise nicht sofort oder gar nicht kommt¹. tailwird beendet, wenn die nächste Zeile kommt und es eine erhält SIGPIPE. Dies kann zu einem Streuprozess führen tail, wenn das Protokoll entfernt wird, ohne dass eine Zeile darauf geschrieben wird (das Abrufen der PID des tailProzesses, um es zu beenden, wenn das sedBeenden möglich, aber schwierig wäre).

¹ Vielen Dank an Peter.O für den Hinweis auf den Fehler in einer früheren Version.


Eine Notiz (Pedanterie vielleicht) - Ich kenne keine Muscheln, die tatsächlich ein Noop erfordern , um eine leere Datei schreiben zu können.
Chris Down

@ChrisDown Ich auch nicht. Aber ich finde es klarer, das No-Op explizit zu schreiben.
Gilles 'SO - hör auf böse zu sein'

Nizza (+1) ... Apropos Puffer: Ich verstehe die Pufferungsmanipulationen nicht, aber es gibt ein Problem, das zu beachten ist, wenn auf die Zielzeile nicht sofort weitere Protokollzeilen folgen. Es hängt, bis mehr Zeilen geschrieben sind, obwohl sed bereits mit dem Muster übereinstimmt (<- ich verstehe diesen Teil nicht). Ein geänderter sedBefehl, der genug in das Protokoll schreibt, um einen Flush (?) Zu erzwingen, wird sofort aktiviert (ich habe ihn getestet), aber ich denke, dass die Möglichkeit besteht, dass die eingefügten Daten mit einer Selenium-Session-Zeile durchsetzt werden. .
Peter.O

@ Peter.O IIRC Einige Sed-Implementierungen lesen die nächste Zeile im Voraus, da es Fälle gibt, in denen dies nützlich ist (zum Beispiel die $Adresse). Ich habe das in meinen Tests allerdings nicht gesehen (mit GNU sed). Wie genau haben Sie den Fehler auf welchem ​​Betriebssystem gezeigt?
Gilles 'SO - hör auf böse zu sein'

@ Gilles: paste.ubuntu.com/863326 .. und: GNU sed Version 4.2.1 , Schwanz (GNU Coreutils) 7.4
Peter.O

3

In Straight-Shell-Skripten ist es etwas schwieriger, aber das habe ich eine ganze Weile für Tomcat und oc4j verwendet:

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

Das alarmwird jedes mögliche Hängen behandeln, bei dem Tomcat versagt hat. Die Anzahl der Zeilen, die vom EOF zurückgehen sollen, ist einstellbar (aus einer Konfigurationsdatei).

Ich habe das Ganze schließlich auf Python umgestellt. Es ist zwar etwas länger, aber etwas effizienter:

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

Sie können dies Ihrem Skript hinzufügen, um die Pause zu implementieren:

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

Es verwendet das Perl- Modul File :: Tail, um sich wie zu verhalten tail -f logfile | grep Started SocketListener.

Ersetzen Sie / var / log / message durch die entsprechende Protokolldatei. Beachten Sie, dass es für immer hängen bleibt, wenn "Started SocketListener" nie angezeigt wird.


1

Vielleicht sollten Sie eine Zeitüberschreitung verwenden, anstatt auf unbestimmte Zeit zu warten.

Die unten stehende Bash-Funktion wird blockiert, bis der angegebene Suchbegriff angezeigt wird oder ein bestimmtes Zeitlimit erreicht ist.

Der Exit-Status ist 0, wenn die Zeichenfolge innerhalb des Timeouts gefunden wird.

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
}

Möglicherweise existiert die Protokolldatei noch nicht direkt nach dem Start von Selenium. In diesem Fall sollten Sie warten, bis es angezeigt wird, bevor Sie nach der Zeichenfolge suchen:

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

So können Sie es verwenden:

wait_selenium_server "/var/log/selenium.log" 5m && \
echo -e "\n-------------------------- Selenium READY --------------------------\n"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.