我正在使用 bash 脚本启动 Selenium 服务器,正如您从下面日志中的时间戳中看到的那样,该服务器完全上线大约需要 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
我希望我的 bash 脚本等到看到字符串“Started SocketListener”,然后继续,而不是在启动服务器后使用“sleep 32”命令(以在继续之前延迟脚本)。那可能吗?
答案1
您可以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
管道就会一直运行,而下一行可能不会立即出现(如果有的话)。当下一行到来并且它收到一个 时将退出。如果在没有写入任何行的情况下删除日志,这可能会留下一个杂散进程(获取进程的 PID 以在退出时杀死它是可能的,但很棘手)。tail
tail
SIGPIPE
tail
tail
sed
1感谢彼得·O指出早期版本中的错误。
答案2
在直接的 shell 脚本中有点困难,但这是我在 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()
答案3
您可以将其添加到脚本中以实现暂停:
perl -e 'use File::Tail;
my $ref=tie *FH,"File::Tail",(name=>"/var/log/messages",maxinterval=>1);
while(<FH>) { exit if /Started SocketListener/ };'
它利用了 perl文件::尾巴模块的行为类似于tail -f logfile | grep Started SocketListener
.
将 /var/log/message 替换为适当的日志文件。请注意,如果“Started SocketListener”从未出现,它将永远挂起。
答案4
也许您应该使用超时而不是无限期地等待。
下面的 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"