Có tập lệnh Bash chờ thông báo trạng thái trước khi tiếp tục


10

Tôi đang kích hoạt máy chủ Selenium với tập lệnh bash và như bạn có thể thấy từ dấu thời gian trên nhật ký bên dưới, phải mất khoảng 32 giây để điều này hoàn toàn xuất hiện trực tuyến:

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

Thay vì sử dụng lệnh "ngủ 32" sau khi khởi động máy chủ (để trì hoãn tập lệnh trước khi tiếp tục), tôi muốn tập lệnh bash của mình đợi cho đến khi thấy chuỗi "Đã bắt đầu SocketListener", rồi tiếp tục. Điều đó có thể không?

Câu trả lời:


8

Bạn có thể sử dụng tail -fđể tiếp tục đọc từ tệp khi nó phát triển. Hãy cẩn thận với những gì bạn ăn tail -fvào. Bạn có thể tail -fchuyển vào một bộ lọc chờ cho đến khi dòng nhật ký mong muốn và thoát. Những gì sẽ không hoạt động là nếu bạn tail -fchuyển vào một bộ lọc chuyển sang bộ lọc khác, bởi vì bộ lọc trung gian sẽ đệm đầu ra của nó. Những công việc này:

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

Lưu ý rằng tôi đặt tailtrong nền. Điều này là do khi sedtìm thấy dòng mong muốn, nó sẽ thoát, nhưng đường ống tiếp tục chạy miễn taillà chờ dòng tiếp theo, có thể không đến ngay lập tức nếu có. tailsẽ thoát khi dòng tiếp theo đến và nó nhận được a SIGPIPE. Điều này có thể để lại một tailquá trình đi lạc nếu nhật ký bị xóa mà không có bất kỳ dòng nào được ghi vào nó (có được PID của tailquá trình để giết nó khi sedthoát ra có thể nhưng khó khăn).

¹ Nhờ Peter.O để chỉ ra các lỗi trong phiên bản trước đây.


Một ghi chú (pedantry, có lẽ) - Tôi không biết bất kỳ shell nào thực sự cần noop để cho phép viết một tập tin trống.
Chris Down

@ChrisDown Cả tôi cũng vậy. Nhưng tôi thấy rõ ràng hơn khi viết no-op một cách rõ ràng.
Gilles 'SO- đừng trở nên xấu xa'

Nice (+1) ... nói về bộ đệm: Tôi không hiểu các âm mưu của bộ đệm, nhưng có một vấn đề cần lưu ý, nếu dòng đích không được theo sau bởi nhiều dòng nhật ký. Nó treo cho đến khi có nhiều dòng được viết, mặc dù sed đã khớp với mẫu đó (<- Tôi không hiểu phần đó). Một sedlệnh đã sửa đổi ghi đủ vào nhật ký để buộc tuôn ra (?), Sẽ khởi động nó ngay lập tức (tôi đã kiểm tra nó), nhưng tôi nghĩ rằng có khả năng dữ liệu được chèn xen kẽ với dòng phiên selenium .. .
Peter.O

@ Peter.O IIRC một số triển khai sed đọc trước dòng tiếp theo, bởi vì có một trường hợp nó hữu ích ( $địa chỉ, cho một). Tôi đã không thấy điều đó xảy ra trong các thử nghiệm của mình (với GNU sed). Làm thế nào chính xác bạn đã thể hiện lỗi, trên hệ điều hành gì?
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles: paste.ubfox.com/863326 .. và: GNU sed phiên bản 4.2.1 , đuôi (GNU coreutils) 7.4
Peter.O

3

Nó khó hơn một chút trong kịch bản shell shell, nhưng đây là thứ tôi đã sử dụng khá lâu cho tomcat và 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

Các alarmsẽ xử lý bất kỳ treo tiềm năng nơi tomcat thất bại. Số lượng dòng trở lại từ EOF có thể điều chỉnh (từ tệp cấu hình).

Cuối cùng tôi đã chuyển toàn bộ thứ sang trăn; trong khi nó dài hơn một chút, nó hiệu quả hơn một chút:

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

Bạn có thể thêm phần này vào tập lệnh của mình để thực hiện tạm dừng:

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

Nó sử dụng mô-đun perl File :: Tail để hành xử như thế nào tail -f logfile | grep Started SocketListener.

Thay thế / var / log / message bằng tệp nhật ký thích hợp. Lưu ý rằng nó sẽ bị treo vĩnh viễn nếu "Started SocketListener" không bao giờ xuất hiện.


1

Có lẽ bạn nên sử dụng thời gian chờ thay vì chờ đợi vô thời hạn.

Hàm bash bên dưới sẽ chặn cho đến khi cụm từ tìm kiếm nhất định xuất hiện hoặc đạt đến thời gian chờ đã cho.

Trạng thái thoát sẽ là 0 nếu chuỗi được tìm thấy trong thời gian chờ.

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
}

Có lẽ tệp nhật ký chưa tồn tại ngay sau khi khởi chạy Selenium. Trong trường hợp đó, bạn nên đợi nó xuất hiện trước khi tìm kiếm chuỗi:

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

Đây là cách bạn có thể sử dụng nó:

wait_selenium_server "/var/log/selenium.log" 5m && \
echo -e "\n-------------------------- Selenium READY --------------------------\n"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.