我在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 server1
和Connected to server2
行,而 server2.log 有Connected to server2
。
我该如何解决这个问题?感谢。
答案 0 :(得分:1)
你在这里遇到的问题是log.startLogging
是有意的
每个进程生命周期调用一次,打开一个日志文件。如果你认为
关于它,Twisted如何知道特定的log.msg
日志文件
打电话应该在你的例子中?您没有传递日志文件或任何日志文件
关于使用哪一个的信息。
您的示例中还有许多内容正在使用 老式的Twisted成语,所以我要完全彻底改变这个例子 使用较新的Twisted API:
twisted.python.log
模块,而是去了
使用new logging hotness
在
twisted.logger
。IReactorTCP.connectTCP
,我会去
使用
Endpoints
这有很多好处。twisted.internet.task.react
所以我依靠全球反应堆(这是
bad)。还有一些你正在做的事情总是一个坏事 扭曲的想法:
time.sleep()
。它阻止
整个反应堆,这意味着你扭曲的所有未完成的任务
程序(除了线程中的程序)在您等待时停止。
有异步API,例如
deferLater
,
你可以用它来处理时间的推移。twisted.logger
使这更简单,语法更好,但即便如此
twisted.python.log
始终支持日志中的结构化数据
消息。我将使用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
中,我们获得Logger
个self.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))