扭曲了.如何为每个请求在日志中写入唯一的前缀



我有扭曲的服务器。它是用插件运行的。我想根据请求为每个条目写唯一的前缀。

这意味着,当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)

这为您提供了一个观察者,它会注意到您的特殊类型的日志事件,并在将它们发送到正常的文件编写逻辑之前修改它们的文本。我刚刚在这里做了一些简单的文本格式化,但您可以做得更好,比如将每个用户的事件写入他们自己的专用日志文件,或者使用更容易解析的结构化日志格式。

到目前为止,我希望这一切都很有用,但它并不能帮助您在特定的日志事件中获得正确的用户标识符。到目前为止,每个用户都是"alice"。

首先,让我们看看我们如何使不同的用户成为可能。一种方法是使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")即可为alice记录事件。您可能不想在顶层定义它,因为您还不知道用户名,而且可能会有多个用户。幸运的是,你可以很容易地在任何时候制作这些。

让我们暂时抛开这一点,考虑一下如何识别用户。

有很多方法,所以我只假设request.getUser()是合适的。用你真正想使用的任何其他机制来替换它。

现在您需要跟踪这些信息。一种简单的方法是将其作为参数传递给任何想要记录与用户相关的事件的代码。我希望这实际上不是一个负担,因为任何想要记录与用户相关的事件的代码都可能已经需要知道它是为哪个用户代理的。

这就进入了TwistedWeb的一个略显粗糙的区域。遍历系统(即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定义这样的日志助手,如上所述。

还有很多潜在的与伐木有关的地方我还没有在这里介绍,但我希望这足以让你开始并展示一些可能的方向。

相关内容

  • 没有找到相关文章