根据 Twisted 客户端应用程序中的连接打印到不同的日志文件
Printing to different log file based on connection in Twisted client application
我的 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
.
我该如何解决这个问题?谢谢
你在这里遇到的问题是 log.startLogging
本来就是
每个进程生命周期调用 一次,以打开单个日志文件。如果你认为
关于它,Twisted 应该如何知道特定的日志文件 log.msg
在你的例子中应该调用?您没有传递日志文件或任何
有关使用哪一个的信息。
你的例子中还有很多地方用得非常好
老式的 Twisted 习语,所以我要彻底修改这个例子
使用较新的 Twisted API:
- 与其使用旧的和损坏的
twisted.python.log
模块,我要
使用 new logging hotness
在
twisted.logger
.
- 而不是使用旧的和破坏的
IReactorTCP.connectTCP
,我打算
采用
Endpoints
有很多优点。
- 与其直接导入反应堆 运行,不如使用
twisted.internet.task.react
所以我依赖于全球反应堆(这是
bad).
还有一些你正在做的事情总是很糟糕
Twisted 中的想法:
- 永远不要在任何 Twisted 程序中使用
time.sleep()
。它阻止
整个反应堆,这意味着你的 Twisted 中所有未完成的任务
程序(线程中的程序除外)在您等待时停止。
有异步API,例如
deferLater
,
你可以用它来处理时间的流逝。
- 切勿使用字符串格式将日志消息放在一起。
twisted.logger
使这更容易一些并且具有更好的语法,但即使
twisted.python.log
一直支持日志中的结构化数据
消息。
- 你在几个地方有 2-space 个缩进。羞耻:).
我将使用 Twisted 日志系统来回答你的问题,但是
仅从您的连接向专门的观察者发送日志。原因
我这样做是因为 intercept 记录消息有点棘手
用于全局日志并说服现有的全局日志记录
不应该 将这些消息写入主日志文件的基础设施。
这是设计使然:一旦设置了日志记录,它通常用作万能的
捕获导致错误的消息所必需的。另一个潜力
答案是简单地从每个连接打开一个文本文件而不涉及
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
中,我们使用 self.log
获得 Logger
实例,
但是由于 class 属性 EchoClient.log
是一个描述符,它正在创建一个
每次都是新实例。确保我们修改的observer
属性状态
持久化后,我们将 self.log
重新分配给结果对象。
这将产生一些包含丰富结构化信息的日志文件,但是
人类阅读可能有些困难。如果你真正关心的是
供人们阅读的文字文本日志文件,而您不想做任何日志
分析,你可以只使用 textFileLogObserver
而不是
jsonFileLogObserver
;但是,只需一点点代码,您就可以获得最好的
两个世界。这是一个非常短的程序,它将读取其中一个日志
此处生成的文件并发出人们可以阅读或通过管道传输的 classic 日志文本
grep:
import io
from twisted.logger import eventsFromJSONLogFile, formatEventAsClassicLogText
for event in eventsFromJSONLogFile(io.open("server_1.json.log", "rt")):
print(formatEventAsClassicLogText(event))
我的 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
.
我该如何解决这个问题?谢谢
你在这里遇到的问题是 log.startLogging
本来就是
每个进程生命周期调用 一次,以打开单个日志文件。如果你认为
关于它,Twisted 应该如何知道特定的日志文件 log.msg
在你的例子中应该调用?您没有传递日志文件或任何
有关使用哪一个的信息。
你的例子中还有很多地方用得非常好 老式的 Twisted 习语,所以我要彻底修改这个例子 使用较新的 Twisted API:
- 与其使用旧的和损坏的
twisted.python.log
模块,我要 使用 new logging hotness 在twisted.logger
. - 而不是使用旧的和破坏的
IReactorTCP.connectTCP
,我打算 采用 Endpoints 有很多优点。 - 与其直接导入反应堆 运行,不如使用
twisted.internet.task.react
所以我依赖于全球反应堆(这是 bad).
还有一些你正在做的事情总是很糟糕 Twisted 中的想法:
- 永远不要在任何 Twisted 程序中使用
time.sleep()
。它阻止 整个反应堆,这意味着你的 Twisted 中所有未完成的任务 程序(线程中的程序除外)在您等待时停止。 有异步API,例如deferLater
, 你可以用它来处理时间的流逝。 - 切勿使用字符串格式将日志消息放在一起。
twisted.logger
使这更容易一些并且具有更好的语法,但即使twisted.python.log
一直支持日志中的结构化数据 消息。 - 你在几个地方有 2-space 个缩进。羞耻:).
我将使用 Twisted 日志系统来回答你的问题,但是 仅从您的连接向专门的观察者发送日志。原因 我这样做是因为 intercept 记录消息有点棘手 用于全局日志并说服现有的全局日志记录 不应该 将这些消息写入主日志文件的基础设施。 这是设计使然:一旦设置了日志记录,它通常用作万能的 捕获导致错误的消息所必需的。另一个潜力 答案是简单地从每个连接打开一个文本文件而不涉及 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
中,我们使用 self.log
获得 Logger
实例,
但是由于 class 属性 EchoClient.log
是一个描述符,它正在创建一个
每次都是新实例。确保我们修改的observer
属性状态
持久化后,我们将 self.log
重新分配给结果对象。
这将产生一些包含丰富结构化信息的日志文件,但是
人类阅读可能有些困难。如果你真正关心的是
供人们阅读的文字文本日志文件,而您不想做任何日志
分析,你可以只使用 textFileLogObserver
而不是
jsonFileLogObserver
;但是,只需一点点代码,您就可以获得最好的
两个世界。这是一个非常短的程序,它将读取其中一个日志
此处生成的文件并发出人们可以阅读或通过管道传输的 classic 日志文本
grep:
import io
from twisted.logger import eventsFromJSONLogFile, formatEventAsClassicLogText
for event in eventsFromJSONLogFile(io.open("server_1.json.log", "rt")):
print(formatEventAsClassicLogText(event))