2011-11-16 5 views
9

目標を介してクライアントに提供しています。 Windows 7クライアントでwxPython GUIを実行していて、ログを生成するUbuntuサーバー上でプログラムを実行しています。私の現在の試みは、ログをtail -fし、出力をねじれたサーバーにパイプし、正規表現の条件を満たすデータをクライアントに提供することです。私はすでにトンネルを開いているので、SSHを使って物事を複雑にする必要はありません。次のコードブロックを実行していますが、入力の最初の行のみを処理します。私は、改行の入力をチェックしてからそれをトランスポートに書き留める必要があることを知っていますが、接続を切断することなくそれを行う方法がわかりません。テールは、その後、ねじれ

完全なソリューションを一緒に修正するのに十分な情報を見つけることができませんでした。私はソケットやファイルIOを使っていろいろな方法を試しましたが、Twistedはこの問題の良いツールと思われます。正しい軌道にいるのですか?すべての推奨は高く評価されます。ありがとう

#! /usr/bin/python 

import optparse, os, sys 

from twisted.internet.protocol import ServerFactory, Protocol 

def parse_args(): 
    usage = """usage: %prog [options] 
""" 

    parser = optparse.OptionParser(usage) 

    help = "The port to listen on. Default to a random available port." 
    parser.add_option('--port', type='int', help=help) 

    help = "The interface to listen on. Default is localhost." 
    parser.add_option('--iface', help=help, default='localhost') 

    options =parser.parse_args() 

    return options#, log_file 

class LogProtocol(Protocol): 
    def connectionMade(self): 
     for line in self.factory.log: 
      self.transport.write(line) 

class LogFactory(ServerFactory): 
    protocol = LogProtocol 

    def __init__(self,log): 
     self.log = log 

def main(): 
    log = sys.stdin.readline() 
    options, log_file = parse_args() 

    factory = LogFactory(log) 

    from twisted.internet import reactor 

    port = reactor.listenTCP(options.port or 0, factory, 
          interface=options.iface) 

    print 'Serving %s on %s.' % (log_file, port.getHost()) 

    reactor.run() 


if __name__ == '__main__': 
    main() 

最初のコメントに答えるために、私もPython内からログを読み込もうとしましたが、プログラムがハングしました。コードは次のとおりです。

#! /usr/bin/python 

import optparse, os, sys, time 
from twisted.internet.protocol import ServerFactory, Protocol 

def parse_args(): 
    usage = """ usage: %prog [options]""" 

    parser = optparse.OptionParser(usage) 

    help = "The port to listen on. Default to a random available port" 
    parser.add_option('--port', type='int', help=help, dest="port") 

    help = "The logfile to tail and write" 
    parser.add_option('--file', help=help, default='log/testgen01.log',dest="logfile") 

    options = parser.parse_args() 
    return options 

class LogProtocol(Protocol): 
    def connectionMade(self): 
     for line in self.follow(): 
      self.transport.write(line) 
     self.transport.loseConnection() 

    def follow(self): 
     while True: 
      line = self.factory.log.readline() 
      if not line: 
       time.sleep(0.1) 
       continue 
      yield line 

class LogFactory(ServerFactory): 
    protocol = LogProtocol 

    def __init__(self,log): 
     self.log = log 

def main(): 
    options, log_file = parse_args() 
    log = open(options.logfile) 
    factory = LogFactory(log) 

    from twisted.internet import reactor 

    port = reactor.listenTCP(options.port or 0, factory) #,interface=options.iface) 

    print 'Serving %s on %s.' % (options.logfile, port.getHost()) 

    reactor.run() 


if __name__ == '__main__': 
    main() 
+0

'tailからの出力をパイプするのではなく、Python内からログを読むことを考えましたか? – Velociraptors

+0

ジェネレータを使用してこれも同様に処理しようとしましたが、プログラムがハングします。トランスポートとジェネレータがそれぞれもう一方が終了するのを待っているように見えます。上記のコード。ジェネレータを使用するよりも、これを行うより良い方法はありますか? – jsucsy

答えて

7

ここで達成しようとしている目標は、いくつか簡単に分かれています。まず、ログファイルを見てみましょう。

発電機にはいくつかの問題があります。それらの1つは大きいです - それはtime.sleep(0.1)を呼び出します。 sleep機能ブロックは、それに渡された時間の長さです。それがブロックされている間、それを呼び出したスレッドは他のことを行うことはできません(それはおおよそ「ブロックする」という意味です)。 LogProtocol.connectionMadeが呼び出されたのと同じスレッドで(connectionMadeからfollowを呼び出して)ジェネレータを反復処理しています。は、Twistedがほぼシングルスレッドであるため、Twisted reactorが実行されているのと同じスレッドで呼び出されます。

したがって、リアクターはsleepコールでブロックしています。睡眠が原子炉をブロックしている限り、原子炉はソケットを介してバイトを送るような何もできません。ブロッキングは推移的です。だから、LogProtocol.connectionMadeはもっと大きな問題です。それは無期限に繰り返し、睡眠と読書を繰り返します。それで、原子炉を無期限にブロックします。

ブロックせずにファイルから行を読み込む必要があります。ポーリングによってこれを行うことができます。これは、あなたが現在取っているアプローチですが、スリープコールを避けることができます。あなたはまた、永遠に実行されるこのループを作る部分とLoopingCall契約をさせることができます

def follow(fObj): 
    line = fObj.readline() 
    reactor.callLater(0.1, follow, fObj) 

follow(open(filename)) 

:未来をファイルから読み込みスケジュールするreactor.callLaterを使用し

def follow(fObj): 
    line = fObj.readline() 

from twisted.internet.task import LoopingCall 

loop = LoopingCall(follow, open(filename)) 
loop.start(0.1) 

これらのどちらかは、あなたが新しい読み聞かせします反応炉をブロックすることなく時間の経過と共にファイルからのラインを生成する。もちろん、彼らはそれを読んだ後、床の上にラインを落とすだけです。これは第2の問題につながります...

ファイルの新しい行の表示に反応する必要があります。おそらくあなたはそれをあなたの接続に書きたいと思うでしょう。これはそれほど難しいことではありません。「反応する」というのは簡単ですが、通常は関数やメソッドを呼び出すことだけです。この場合、LogProtocolにログを設定し、表示される行を処理するためのコールバックオブジェクトを用意するのが最も簡単です。上からfollow機能へのこのわずかな調整を考えてみましょう:

def follow(fObj, gotLine): 
    line = fObj.readline() 
    if line: 
     gotLine(line) 

def printLine(line): 
    print line 

loop = LoopingCall(follow, open(filename), printLine) 
loop.start(0.1) 

今、あなたは非blockingly新ラインのログファイルをポーリングし 1が実際にアップ示されたときに学ぶことができます。

def connectionLost(self, reason): 
     self.loop.stop() 

ので、このソリューションはにより、ブロッキング回避:これは

class LogProtocol(Protocol): 
    def connectionMade(self): 
     self.loop = LoopingCall(follow, open(filename), self._sendLogLine) 
     self.loop.start() 

    def _sendLogLine(self, line): 
     self.transport.write(line) 

一つの細部は、接続が失われたとき、あなたはおそらく、ファイルを見て停止したいということです... LogProtocolと統合するのは簡単ですtime.sleepの代わりにLoopingCallを使用し、簡単なメソッド呼び出しを使用して見つかったときにプロトコルにプッシュします。

+0

優れた説明、ありがとうございます。美しく動作します。 – jsucsy

関連する問題