Как установить строку идентификатора при использовании logging.SysLogHandler в Python 2.6?
Я настроил ведение журнала с помощью logging.fileConfig(). У меня есть корневой логгер, идущий к обработчику, который использует SysLogHandler('/dev/log', handlers.SysLogHandler.LOG_USER)
Это все работает отлично, и я вижу свои записи в журнале /var/log/user.log
Вопрос в том, как установить строку идентификатора системного журнала в нечто отличное от python? Похоже, модуль системного журнала в стандартной библиотеке позволяет установить это при открытии журнала, но обработчик ведения журнала не предлагает эту функцию.
Будет ли решение подкласса SysLogHandler и использовать библиотеку syslog внутри его метода emit? Это программа только для Unix, поэтому использование syslog напрямую не создает проблем с переносимостью.
4 ответа
AFAIK, идентификатор строки является артефактом API системного журнала, см. Эту страницу. Он просто использует C argv[0], который, конечно, будет "python".
Я удивлен, что вы получаете это с помощью SysLogHandler
с сокетом домена, поскольку сообщение, отправляемое демонам системного журнала через домен или сокеты TCP, представляет собой просто строку с приоритетом в <угловых скобках>, за которой следует отформатированное сообщение и байт NUL. Там нет идентичной строки, указанной SysLogHandler
, поскольку он не использует API системного журнала (который имеет некоторые проблемы с безопасностью потоков в некоторых версиях, IIRC).
Это немного устарело, но здесь должна быть записана новая информация, чтобы люди не чувствовали необходимости писать собственный обработчик системного журнала.
Начиная с Python 3.3, SysLogHandler имеет атрибут класса .ident
именно для этого; по умолчанию для него используется ''.
Пример:
import logging
from logging.handlers import SysLogHandler
h = SysLogHandler(address=('some.destination.com',514), facility=SysLogHandler.LOG_LOCAL6)
h.setFormatter(
logging.Formatter('%(name)s %(levelname)s %(message)s')
)
h.ident = 'conmon'
syslog = logging.getLogger('syslog')
syslog.setLevel(logging.DEBUG)
syslog.addHandler(h)
syslog.debug('foo syslog message')
Реализации системного журнала, принимающие сообщения RFC3164, должны распознавать первую часть сообщения ("foo:"
в примере) как TAG.
Часть MSG имеет два поля, известные как поле TAG и поле CONTENT. Значением в поле TAG будет имя программы или процесса, который сгенерировал сообщение.
Код Python..
import logging
from logging.handlers import SysLogHandler
h = SysLogHandler(address='/dev/log')
h.setFormatter(logging.Formatter('foo: %(message)s'))
logging.getLogger().addHandler(h)
logging.error('bar')
... пошлю это в сокет системного журнала
connect(3, {sa_family=AF_UNIX, sun_path="/dev/log"}, 10) = 0
sendto(3, "<11>foo: bar\0", 13, 0, NULL, 0) = 13
close(3)
Который, в свою очередь, производит это в журнале systemd.
Dec 13 14:48:20 laptop foo[1928]: bar
Детали сообщения журнала:
{
..
"PRIORITY" : "3",
"SYSLOG_FACILITY" : "1",
"SYSLOG_IDENTIFIER" : "foo",
"MESSAGE" : "bar",
"_PID" : "1928",
}
Он работает с Py2.6, 2.7, 3.4, 3.5 и сервером системного журнала Systemd. Он также может работать с другими реализациями системного журнала (если они принимают RFC3164). Это решение, вероятно, сломается, когда SysLogHandler в Python по умолчанию установит новый RFC5424.
Для Python 2.7 вы можете сделать что-то вроде этого:
class MySysLogHandler(logging.handlers.SysLogHandler):
def __init__(self):
super(MySysLogHandler, self).__init__(address='/dev/log')
def emit(self, record):
priority = self.encodePriority(self.facility, self.mapPriority(record.levelname))
record.ident = "My[" + str(priority) + "]:"
super(MySysLogHandler, self).emit(record)
handler = MySysLogHandler()
handler.formatter = logging.Formatter(fmt="%(ident)s %(levelname)s: %(message)s")
logging.root.addHandler(handler)
logging.info("hello world")
Это выдаст в системном журнале:
Sep 3 16:28:53 hostname My[14]: INFO: hello world