Витая. Как записать уникальный префикс в журнал для каждого запроса
Я крутил сервер. Он запускается с плагином. Я хочу написать уникальный префикс для каждой записи в зависимости от запроса.
Это означает, что когда 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
как показано выше.
Потенциально еще есть много оснований, связанных с ведением журнала, которые я здесь не освещал, но я надеюсь, что этого достаточно, чтобы вы начали и продемонстрировали некоторые возможные направления.