Динамически изменяя уровень журнала без перезапуска приложения

Можно ли изменить уровень ведения журнала, используя fileConfig в Python без перезапуска приложения. Если он не может быть достигнуто через fileConfig есть другой способ получить тот же результат?

Обновление: это было за приложение, запущенное на сервере, я хотел, чтобы системные администраторы могли изменить конфигурационный файл, который будет принят во время выполнения приложения и динамически изменять уровень лог. Я работал с gevent в то время, следовательно, я'ве добавил мой код как один из ответов, который использует inotify для выбрать изменения в файл config.

Комментарии к вопросу (3)
Решение

fileConfig - это механизм, чтобы настроить уровень журнала для вас на основе файла; вы можете изменить его в любое время в вашей программе.

Звоните .setLevel() на объекте ведение журнала, для которого вы хотите изменить уровень журнала. Как правило, вы'd сделать это на корню:

logging.getLogger().setLevel(logging.DEBUG)
Комментарии (1)

В дополнение к принятым ответ: в зависимости от того, как вы инициализировали регистратор, вам может также потребоваться обновить регистратор'обработчики с:

import logging

level = logging.DEBUG
logger = logging.getLogger()
logger.setLevel(level)
for handler in logger.handlers:
    handler.setLevel(level)
Комментарии (1)

Можно конечно использовать fileConfig (), чтобы изменить конфигурацию ведения журнала на лету, хотя для простого изменения программного подхода, как полагают в Мартин Питерс' ответ может быть соответствующий. Лесозаготовки еще предоставляет сервер сокет для прослушивания для настройки с помощьюслушать ()stopListening /Апис ()`, как описано здесь. Чтобы сделать ведение журнала, чтобы слушать определенный порт, вы используете

t = logging.config.listen(PORT_NUMBER)
t.start()

и чтобы остановить прослушивание, звоните

logging.config.stopListening()

Чтобы отправить данные на сервер, можно использовать, например,

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', PORT_NUMBER))
with open(CONFIG_FILE) as f:
    data_to_send = f.read()
s.send(struct.pack('>L', len(data_to_send)))
s.send(data_to_send)
s.close()

Обновление: из-за обратной совместимости ограничения, внутренние реализации fileConfig()вызов означает, что вы можете'т указать disable_existing_loggers=false в вызов, который делает эту функцию менее полезны в определенных ситуациях. Вы можете использовать тот же API для отправки JSON-файл с помощью dictConfig схемы, что позволит лучше контролировать реконфигурации. Это требуется Python 2.7/3.2 или выше (где dictConfig () был добавлен). Или, вы можете использовать stdlib код, чтобы реализовать свой собственный слушатель, который работает таким же образом, но с учетом ваших конкретных потребностей.

Комментарии (2)

Расширение на sfinken'ы ответ, и Стармена'с последующим комментарием, вы также можете проверить тип обработчика для конкретного outputter - например:

ведение журнала импорта регистратор = лесозаготовок.getLogger() для обработчика в регистратор.обработчики: если isinstance(обработчик, тип(лесозаготовки.StreamHandler())): обработчик.setLevel(лесозаготовки.Отладки) логгер.отладка('ведение журнала отладки включен')

Комментарии (0)

Это может быть то, что вы ищете:

import logging
logging.getLogger().setLevel(logging.INFO)

Обратите внимание, что getLogger() вызывается без аргументов возвращает корневой регистратор.

Комментарии (0)

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

import gevent
import gevent_inotifyx as inotify
from gevent.queue import Queue

class FileChangeEventProducer(gevent.Greenlet):
    def __init__(self, fd, queue):
        gevent.Greenlet.__init__(self)
        self.fd = fd
        self.queue = queue

    def _run(self):
        while True:
            events = inotify.get_events(self.fd)
            for event in events:
                self.queue.put(event)
                gevent.sleep(0)

class FileChangeEventConsumer(gevent.Greenlet):
    def __init__(self, queue, callBack):
        gevent.Greenlet.__init__(self)
        self.queue = queue
        self.callback = callBack

    def _run(self):
        while True:
            _ = self.queue.get()
            self.callback()
            gevent.sleep(0)

class GeventManagedFileChangeNotifier:
    def __init__(self, fileLocation, callBack):
        self.fileLocation = fileLocation
        self.callBack = callBack
        self.queue = Queue()
        self.fd = inotify.init()
        self.wd = inotify.add_watch(self.fd, self.fileLocation, inotify.IN_CLOSE_WRITE)

    def start(self):
        producer = FileChangeEventProducer(self.fd, self.queue)
        producer.start()
        consumer = FileChangeEventConsumer(self.queue, self.callBack)
        consumer.start()
        return (producer, consumer)

Приведенный выше код используется как ниже,

    def _setUpLoggingConfigFileChangeNotifier(self):
        loggingFileNameWithFullPath = self._getFullPathForLoggingConfig()
        self.gFsNotifier = GeventManagedFileChangeNotifier(loggingFileNameWithFullPath, self._onLogConfigChanged)
        self.fsEventProducer, self.fsEventConsumer = self.gFsNotifier.start()

    def _onLogConfigChanged(self):
        self.rootLogger.info('Log file config has changed - examining the changes')
        newLoggingConfig = Config(self.resourcesDirectory, [self.loggingConfigFileName]).config.get('LOG')
        self.logHandler.onLoggingConfigChanged(newLoggingConfig)

Когда у меня появится новый лог-файл конфигурации, я могу перевести в нужный уровень детализации для каждого регистратор из конфига. Я просто хотел поделиться ответом, и это может помочь кому-то, если они пытаются использовать его с gevent.

Комментарии (0)

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

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

Использование потоков.Таймер:

import threading
import time

def reset_level():
    # you can reload your own config file or use logging.config.fileConfig here
    print 'Something else'
    pass

t = threading.Timer(10, reset_level)
t.start()

while True:
    # your app code
    print 'Test'
    time.sleep(2)

Выход:

Test
Test
Test
Test
Test
Something else
Test
Test

Обновление: Пожалуйста, проверьте решение, предложенное Мартейн Питерс.

Комментарии (2)