Используя Python 2.7.15rc1, который поставляется с Linux Mint 19.1, я собираю некоторые данные в rsyslog 8.32.0-1ubuntu4. Выполнение этого по TCP ошибочно объединяет несколько сообщений журнала в одну строку в / var / log / syslog, в то время как UDP правильно не выполняет эту агрегацию.
Я хочу использовать TCP вместо UDP для надежности, но мне нужен некатентированный вывод.
Если я изменю одну строку в моей программе с:
socktype = socket.SOCK_DGRAM
... чтобы:
socktype = socket.SOCK_STREAM
... тогда вещи начинают странно кататься. Одна строка - это единственное изменение кода, необходимое для воспроизведения проблемы из заведомо исправного кода.
Вот как я получаю обработчик регистрации:
handler = logging.handlers.SysLogHandler(address=address, socktype=socktype)
Сообщения журнала в хорошем случае (с UDP) выглядят так (для EG):
Jun 11 15:59:25 2019-06-11 15: 59:25,870|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading xgb_factory
Jun 11 15:59:25 2019-06-11 15: 59:25,871|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading lgb_factory
Jun 11 15:59:25 2019-06-11 15: 59:25,871|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading rf_factory
Jun 11 15:59:39 2019-06-11 15: 59:39,161|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading xgb_factory
Jun 11 15:59:39 2019-06-11 15: 59:39,161|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading lgb_factory
Jun 11 15:59:39 2019-06-11 15: 59:39,162|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading rf_factory
Сообщения журнала в плохом случае (с TCP) выглядят так (для EG):
Jun 11 11:55:04 2019-06-11 11: 53:43,139|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading xgb_factory#000<14>2019-06-11 11:53:43,140|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading lgb_factory#000<14>2019-06-11 11:53:43,141|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading rf_factory#000<14>2019-06-11 11:53:57,842|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading xgb_factory#000<14>2019-06-11 11:53:57,843|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading lgb_factory#000<14>2019-06-11 11:53:57,843|_|INFO|_|dstromberg-inspiron-5570|_|domain.classifier.factories.classifier_academy|_|classifier_academy.py|_|load|_|132|_|loading rf_factory
Отметка времени всегда содержит это паразитное пространство (ASCII 32 после часа в «2019-06-11 11: 53: 43,139») в случае TCP, и несколько сообщений были объединены в одно сообщение. Сообщения, кажется, объединены чем-то вроде: "# 000 <14>". Часть # 000 непротиворечива, но числовая часть 14 в данном случае изменяется от частоты к частоте. Это всегда небольшое число.
Это ошибка в SyslogHandler? Это известная проблема? Кто-нибудь знает исправление, кроме перехода на UDP?
Единственная даже немного необычная вещь, которую я делаю (кроме syslog через TCP), - это добавление фильтра для добавления имени хоста (docker). Это выглядит так:
class ContainerFilter(logging.Filter):
"""This is a filter that just adds the container name (hostname)."""
def __init__(self, name='', container_id=None):
"""Initialize."""
super(ContainerFilter, self).__init__(name)
self.container_id = container_id
def filter(self, record):
"""Set record's metric and container_id attributes, if available."""
record.container = self.container_id
return True
filter_ = ContainerFilter(container_id=_DOCKER_CONTAINER_ID)
handler.addFilter(filter_)
Я думаю, что это слишком много, чтобы быть Nagle.
Что касается TCP по сравнению с UDP - мне нравится надежность TCP, и мне нравится, что когда он не работает, вместо просто отбрасывания сообщений есть исключение.
Также: я знаю, что Python 2.x скоро не будет поддерживаться, но этот конкретный код будет еще на 2.x еще дольше.