Витая. Как записать уникальный префикс в журнал для каждого запроса

Я крутил сервер. Он запускается с плагином. Я хочу написать уникальный префикс для каждой записи в зависимости от запроса.

Это означает, что когда user1 сделает запрос, он сгенерирует уникальную строку, в которой будет добавлен префикс записей журнала (только для этого запроса). Когда user2 сделает запрос, это будет еще один уникальный префикс для записи в журнал.

Я думаю, что это должен быть журнал наблюдателя журнала, но как сгруппировать записи между запросами пользователей?

1 ответ

Решение

Есть несколько частей к этому вопросу.

Во-первых, самая легкая часть - как вы даете событию журнала свой префикс? Конечно, есть несколько способов сделать это. Вы можете сделать что-то очень, очень простое:

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 как показано выше.

Потенциально еще есть много оснований, связанных с ведением журнала, которые я здесь не освещал, но я надеюсь, что этого достаточно, чтобы вы начали и продемонстрировали некоторые возможные направления.

Другие вопросы по тегам