How can I call xtail
by tornado.proces.Subprocess
?
import subprocess
from tornado.ioloop import IOLoop
from tornado import gen
from tornado import process
class Reader(object):
def __init__(self, xwatch_path, max_idle=600, ioloop=None):
self.xwatch_path = xwatch_path
self.ioloop = ioloop
self.max_idle = max_idle
@gen.coroutine
def call_subprocess(self, cmd, stdin_data=None, stdin_async=False):
stdin = STREAM if stdin_async else subprocess.PIPE
sub_process = process.Subprocess(
cmd, stdin=stdin, stdout=STREAM, stderr=STREAM, io_loop=self.ioloop
)
if stdin_data:
if stdin_async:
yield gen.Task(sub_process.stdin.write, stdin_data)
else:
sub_process.stdin.write(stdin_data)
if stdin_async or stdin_data:
sub_process.stdin.close()
result, error = yield [
gen.Task(sub_process.stdout.read_until, '\n'),
gen.Task(sub_process.stderr.read_until, '\n')
]
print result
raise gen.Return((result, error))
@gen.coroutine
def popen(self):
while True:
result, error = yield self.call_subprocess(['xtail', self.xwatch_path])
print result, error
def read_log(ioloop):
access_reader = AccessLogReader(
'/home/vagrant/logs')
ioloop.add_callback(access_reader.popen)
def main():
ioloop = IOLoop.instance()
read_log(ioloop)
ioloop.start()
if __name__ == '__main__':
main()
I would like to collect a few of the log changes in the log folder, ready to use xtail multiple folders to collect logs, and then I develop the environment for debugging.
I use Vim to modify the ~/log/123.txt
file, but I can't see the output.
The statement
result, error = yield [
gen.Task(sub_process.stdout.read_until, '\n'),
gen.Task(sub_process.stderr.read_until, '\n')
]
reads one line of the process's standard output and one line of standard error, and blocks until it has read both lines. If xtail
only writes to one of the two streams, this will never complete.
You probably want to read in a loop (note that gen.Task
is not necessary):
@gen.coroutine
def read_from_stream(stream):
try:
while True:
line = yield stream.read_until('\n')
print(line)
except StreamClosedError:
return
If you care about the difference between stdout and stderr, read from them separately. This will print lines from each stream as they arrive, and stop when both streams are closed:
yield [read_from_stream(sub_process.stdout), read_from_stream(sub_process.stderr)]
If you don't, merge them by passing stdout=STREAM, stderr=subprocess.STDOUT
when creating the subprocess, and only read from sub_process.stdout.