我有扭曲的服务器。它使用插件运行。我想根据请求为每个条目编写唯一的前缀。
这意味着当 user1 发出请求时,它将生成一个唯一的字符串,该字符串将作为日志记录的前缀(仅适用于该请求)。当 user2 发出请求时,它将是日志记录的另一个唯一前缀。
我认为它应该是日志观察者记录器,但是如何在用户请求之间对记录进行分组?
这个问题有几个部分。
首先,简单的部分——你如何给日志事件一个自定义前缀?当然,有几种方法可以解决这个问题。你可以做一些非常非常简单的事情:
from twisted.python.log import msg
def myLog(message):
msg("my prefix" + message)
也就是说,只需在日志消息前面加上所需的前缀即可。不过,这可能不是您真正想要的,因为它会破坏您的日志消息并将前缀文本与日志消息以一种难以逆转的方式混合(考虑一些记录的消息可能来自不同的系统并且没有任何前缀 -但你会怎么说?)。
因此,您可以在日志事件中使用另一个键,而不是使用前缀:
from twisted.python.log import msg
def myLog(message):
msg(message, system="my prefix")
这将导致发出的日志事件看起来有点(不完全是,足够接近),例如:
{"message": message, "system": "my prefix"}
而“系统”键恰好是一个特殊的键。它被 Twisted 中的默认文件日志观察器识别,其内容最终出现在写入文件的日志消息中:
2013-07-23 06:25:35-0400 [my prefix] message
不过,您可能不想为基于用户的信息选择“系统”键。毕竟,系统很可能与 HTTP 服务器有关。用户不是系统。
您可以传递msg
任何其他您想要的关键字参数:
from twisted.python.log import msg
def myLog(message):
msg(message, userIdentifier="alice")
userIdentifier
将被 Twisted 附带的文件日志观察者忽略,但您可以编写自己的观察者来关注它。例如:
from twisted.python.log import FileLogObserver, textFromEventDict, addObserver
class MyObserver(FileLogObserver):
def emit(self, event):
text = textFromEventDict(event)
if text and event.get("userIdentifier"):
adjusted = event.copy()
adjusted["message"] = "(%s) %s" % (event["userIdentifier"], text)
FileLogObserver.emit(self, adjusted)
addObserver(MyObserver(...).emit)
这为您提供了一个观察者,可以注意到您的特殊类型的日志事件并在将它们发送到正常的文件写入逻辑之前修改它们的文本。我刚刚在这里做了一些简单的文本格式化,但你可以做一些更好的事情,比如将每个用户的事件写入他们自己的专用日志文件,或者使用更容易解析的结构化日志格式。
我希望到目前为止这一切都很有用,但它并不能帮助您真正将正确的用户标识符放入特定的日志事件中。到目前为止,每个用户都是“爱丽丝”。
首先,让我们看看我们如何能够改变用户。一种方法是制作userIdentifier
一个参数:
from twisted.python.log import msg
def myLog(message, userIdentifier):
msg(message, userIdentifier=userIdentifier)
当然,myLog
现在看起来有点傻。你可以打电话msg
。也许你想要比这更自动的东西。您可以将用户标识符包装在可调用对象中,这样您就不必继续传递它:
from functools import partial
from twisted.python.log import msg
aliceLog = partial(msg, userIdentifier="alice")
现在您可以通过执行aliceLog("login")
. 您可能不想在顶层定义它,因为您还不知道用户名,并且大概您将拥有多个用户。幸运的是,您可以随时轻松制作这些内容。
让我们暂时把它放在一边,考虑如何识别用户。
有很多方法,所以我只是假设这request.getUser()
是合适的。将其替换为您实际想要使用的任何其他机制。
现在您需要跟踪这些信息。一种简单的方法是将其作为参数传递给任何想要记录与用户相关的事件的代码。我希望这实际上不是负担,因为任何想要记录与用户相关的事件的代码可能已经需要知道它正在为哪个用户行事。
这进入了 Twisted Web 的一个有点毛茸茸的区域。遍历系统(即 getChild)非常灵活,根据您使用它的方式,您将信息传递给最终消费者的方式可能会有很大差异。
一种方法是使用透明的 IResource 包装器。这里的想法是您将 IResource 插入到不消耗任何段的层次结构中,只需检查请求并创建一些有用的状态,例如用户标识符。例如,
from twisted.web.resource import IResource
from twisted.python.components import proxyForInterface
class GiveChildrenUserInfo(proxyForInterface(IResource)):
def getChild(self, request, segment):
child = self.original.getChild(request, segment)
child.setUser(request.getUser())
return GiveChildrenUserInfo(child)
rootResource = GiveChildrenUserInfo(actualRootResource)
...
请注意两件事。首先,我发明了一种setUser
方法,您的所有资源现在都必须实施。它将在每个资源上调用,用户从请求中获取。现在,这些资源可以使用该用户信息——例如调用msg(message, userIdentifier=user)
或定义这样的日志助手partial
,如上所示。
仍然有很多与日志记录相关的基础知识我没有在这里介绍,但我希望这足以让你开始并展示一些可能的方向。