根据Twisted客户端应用程序中的连接打印到不同的日志文件

时间:2015-12-23 14:39:59

标签: python twisted

我在Twisted应用程序中为TCP客户端提供了以下代码:

from twisted.internet import reactor, protocol
from twisted.python import log
import time

class EchoClient(protocol.Protocol):
    def connectionMade(self):
        if(self.factory.server_name == 'server1'):
          log.startLogging(open('server1.log','w'))
        else:
          log.startLogging(open('server2.log','w'))
        log.msg("Connected to "+self.factory.server_name)

    def connectionLost(self,reason):
        log.msg("Connection is lost " + reason.getErrorMessage())

    def dataReceived(self,data):
        log.msg("Server said: " + data)

class EchoFactory(protocol.ClientFactory):
    def __init__(self,server_name):
        self.server_name = server_name

    def buildProtocol(self, addr):
        client = EchoClient()
        client.factory = self
        return client

    def clientConnectionFailed(self, connector, reason):
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        time.sleep(10)
        connector.connect()

conn1 = EchoFactory('server1')
conn2 = EchoFactory('server2')

reactor.connectTCP("localhost",8000,conn1)
reactor.connectTCP("localhost",8001,conn2)

reactor.run()

现在,当我运行该程序时,我发现 server1.log 包含Connected to server1Connected to server2行,而 server2.log Connected to server2

我该如何解决这个问题?感谢。

1 个答案:

答案 0 :(得分:1)

你在这里遇到的问题是log.startLogging是有意的 每个进程生命周期调用一次,打开一个日志文件。如果你认为 关于它,Twisted如何知道特定的log.msg日志文件 打电话应该在你的例子中?您没有传递日志文件或任何日志文件 关于使用哪一个的信息。

您的示例中还有许多内容正在使用 老式的Twisted成语,所以我要完全彻底改变这个例子 使用较新的Twisted API:

  1. 我没有使用旧的和被破坏的twisted.python.log模块,而是去了 使用new logging hotnesstwisted.logger
  2. 而不是使用旧的和被破坏的IReactorTCP.connectTCP,我会去 使用 Endpoints 这有很多好处。
  3. 我没有直接进口反应堆并直接运行反应堆 twisted.internet.task.react 所以我依靠全球反应堆(这是 bad)。
  4. 还有一些你正在做的事情总是一个坏事 扭曲的想法:

    1. 永远不要在任何Twisted程序中使用time.sleep()。它阻止 整个反应堆,这意味着你扭曲的所有未完成的任务 程序(除了线程中的程序)在您等待时停止。 有异步API,例如 deferLater, 你可以用它来处理时间的推移。
    2. 您永远不应该使用字符串格式来组合日志消息。 twisted.logger使这更简单,语法更好,但即便如此 twisted.python.log始终支持日志中的结构化数据 消息。
    3. 你在几个地方有2个空格的缩进。羞耻:))。
    4. 我将使用Twisted日志系统回答您的问题,但是 从您的连接仅向专门的观察​​者发送日志。原因 我这样做是因为拦截日志消息有点棘手 用于全局日志并说服现有的全局日志记录 它不应该将这些消息写入主日志文件的基础结构。 这是设计的:一旦设置了日志记录,它通常可以作为一切 必须捕获导致错误的消息。另一个潜力 答案是简单地从每个连接打开一个文本文件而不涉及 完全是Twisted的日志记录系统。

      以下是如何执行此操作的示例:

      import io
      
      from twisted.internet import protocol
      from twisted.logger import Logger, jsonFileLogObserver
      
      class EchoClient(protocol.Protocol):
          log = Logger()
      
          def connectionMade(self):
              log = self.log
              log.observer = jsonFileLogObserver(
                  io.open(self.factory.server_name + ".json.log", "tw")
              )
              self.log = log
      
              self.log.info("Connected to {log_source.factory.server_name}")
      
          def dataReceived(self, data):
              self.log.info("server said: {data!r}",
                            data=data)
      
          def connectionLost(self, reason):
              self.log.info("Connection is lost: {reason}",
                            reason=reason)
      
      class EchoFactory(protocol.Factory):
          protocol = EchoClient
          def __init__(self, server_name):
              self.server_name = server_name
      
      from twisted.internet.task import react
      from twisted.internet.endpoints import HostnameEndpoint
      from twisted.internet.defer import Deferred
      
      def main(reactor):
          for portNumber in 8001, 8002:
              endpoint = HostnameEndpoint(reactor, "localhost", portNumber)
              endpoint.connect(
                  EchoFactory("server_" + str(portNumber - 8000))
              )
          return Deferred()
      
      react(main)
      

      请注意,在connectionMade中,我们获得Loggerself.log个实例, 但由于类属性EchoClient.log是描述符,因此它创建了一个 每次新的实例。确保我们修改了observer属性状态 如果持续存在,我们会将self.log重新分配给生成的对象。

      这将生成一些包含丰富结构化信息的日志文件,但是 人类阅读可能有些困难。如果你真正关心的是 文字日志文件由人们阅读,你不想做任何日志 分析,你可以使用textFileLogObserver而不是。{ jsonFileLogObserver;但是,只需一点点代码,您就可以获得最佳效果 这两个世界。这是一个非常短的程序,它将读取其中一个日志 这里生成的文件并发出一个人可以阅读或管道的经典日志文本 grep:

      import io
      from twisted.logger import eventsFromJSONLogFile, formatEventAsClassicLogText
      
      for event in eventsFromJSONLogFile(io.open("server_1.json.log", "rt")):
          print(formatEventAsClassicLogText(event))