Я использую регистратор Python. Вот мой код:
import os
import time
import datetime
import logging
class Logger :
def myLogger(self):
logger = logging.getLogger('ProvisioningPython')
logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
У меня проблема в том, что я получаю несколько записей в файле журнала для каждого logger.info
вызова. Как я могу это решить?
Ответы:
Это
logging.getLogger()
уже синглтон. ( Документация )Проблема в том, что каждый раз, когда вы вызываете
myLogger()
, он добавляет к экземпляру еще один обработчик, что вызывает дублирование журналов.Возможно, что-то вроде этого?
источник
loggers.update(dict(name=logger))
? неloggers[name] = logger
проще?loggers.update(dict(name=logger))
создаст словарь с одним вызываемым ключомname
и будет постоянно обновлять этот же ключ. Я удивлен, что никто не упомянул об этом раньше, так как этот код сильно сломан :) Внесу необходимые поправки.loggers
словарь не избыточенlogging.getLogger
? так как вы действительно просто хотите избежать добавления дополнительных обработчиков, похоже, вы бы предпочли ответы ниже, которые проверяют обработчики напрямуюНачиная с Python 3.2, вы можете просто проверить, присутствуют ли уже обработчики, и если да, очистить их перед добавлением новых обработчиков. Это довольно удобно при отладке, и код включает инициализацию вашего регистратора.
источник
сделал трюк для меня
с использованием Python 2.7
источник
Я уже использовал в
logger
качестве синглтона и проверилif not len(logger.handlers)
, но все же получил дубликаты : это был форматированный вывод, за которым следовал неформатированный.Решение в моем случае:
logger.propagate = False
Кредиты на этот ответ и документы .
источник
Вы звоните
Logger.myLogger()
не один раз. Храните экземпляр регистратора он возвращает где - то и повторное использование , что .Также имейте в виду, что если вы войдете в систему до добавления любого обработчика,
StreamHandler(sys.stderr)
будет создано значение по умолчанию .источник
Реализация логгера уже одноэлементная.
Источник - использование журнала в нескольких модулях
Таким образом, вы должны использовать это -
Предположим, мы создали и настроили регистратор с именем main_logger в основном модуле (который просто настраивает регистратор, ничего не возвращает).
Теперь в подмодуле, если мы создадим дочерний регистратор, следуя иерархии имен «main_logger.sub_module_logger» , нам не нужно настраивать его в подмодуле. Достаточно просто создать регистратор в соответствии с иерархией именования.
И он также не добавит дублирующий обработчик.
См. Этот вопрос для более подробного ответа.
источник
logger = logging.getLogger('my_logger') ; logger.handlers = [logger.handlers[0], ]
Это дополнение к ответу @ rm957377, но с объяснением, почему это происходит . Когда вы запускаете лямбда-функцию в AWS, они вызывают вашу функцию из экземпляра оболочки, который остается активным для нескольких вызовов. Это означает, что если вы вызываете
addHandler()
в коде своей функции, она будет продолжать добавлять повторяющиеся обработчики в синглтон регистрации каждый раз, когда функция запускается. Одноэлементный журнал сохраняется через несколько вызовов вашей лямбда-функции.Чтобы решить эту проблему, вы можете очистить свои обработчики, прежде чем устанавливать их через:
источник
.info()
вызову, которого я не понимаю.Ваш регистратор должен работать как синглтон. Не следует создавать его более одного раза. Вот пример того, как это может выглядеть:
источник
Двойной (или тройной, или ..- в зависимости от количества перезагрузок) вывод журнала также может произойти, когда вы перезагружаете свой модуль через
importlib.reload
(по той же причине, что объяснена в принятом ответе). Я добавляю этот ответ только для справки в будущем, так как мне потребовалось время, чтобы выяснить, почему мой результат дублируется (тройной).источник
Один простой обходной путь похож на
Таким образом вы избегаете добавления нового обработчика к базовому списку «обработчиков».
источник
Итог: в большинстве случаев, когда это происходит, нужно вызывать logger.getLogger () только один раз для каждого модуля. Если у вас есть несколько классов, как у меня, я мог бы назвать это так:
У обоих будет собственное полное имя пакета и метод, в котором он будет зарегистрирован.
источник
Вы можете получить список всех обработчиков для конкретного регистратора, поэтому вы можете сделать что-то вроде этого
В приведенном выше примере мы проверяем, подключен ли уже обработчик указанного файла к регистратору, но наличие доступа к списку всех обработчиков дает вам возможность решить, по каким критериям вы должны добавить еще один обработчик или нет.
источник
Была эта проблема сегодня. Поскольку мои функции были @staticmethod, вышеуказанные предложения были разрешены с помощью random ().
Что-то вроде:
источник
источник