Cambio dinámico de nivel de registro en Python sin reiniciar la aplicación
logging gevent (6)
Además de la respuesta aceptada: Dependiendo de cómo inicializó el registrador, también podría tener que actualizar los manejadores del registrador:
import logging
level = logging.DEBUG
logger = logging.getLogger()
logger.setLevel(level)
for handler in logger.handlers:
handler.setLevel(level)
¿Es posible cambiar el nivel de registro utilizando fileConfig en python sin reiniciar la aplicación? Si no se puede lograr a través de fileConfig, ¿hay alguna otra manera de obtener el mismo resultado?
Actualización: Esto fue para una aplicación que se ejecuta en un servidor, quería que los administradores de los sistemas pudieran cambiar un archivo de configuración que la aplicación seleccionaría durante el tiempo de ejecución y cambiaría el nivel de registro de forma dinámica. Estaba trabajando con gevent en ese momento, por lo tanto, agregué mi código como una de las respuestas que utiliza inotify para elegir cambios en el archivo de configuración.
Dependiendo de su aplicación, primero necesita encontrar una forma de volver a cargar ese archivo o restablecer el nivel de registro según su propio archivo de configuración durante la ejecución.
La manera más fácil sería usar un temporizador. Use el subprocesamiento para hacer eso, o haga que su marco asíncrono haga eso (si usa alguno, generalmente lo implementan).
Usando threading.Timer:
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)
Salida:
Test
Test
Test
Test
Test
Something else
Test
Test
Actualización: verifique la solución propuesta por Martijn Pieters.
Esto podría ser lo que estás buscando:
import logging
logging.getLogger().setLevel(logging.INFO)
Tenga en cuenta que getLogger()
llamado sin ningún argumento devuelve el registrador de raíz.
Finalmente me conformé con el uso de inotify y gevent para verificar la operación de escritura del archivo, y una vez que sé que el archivo ha sido cambiado, voy y configuro el nivel para cada registrador que he basado en la configuración.
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)
El código anterior se usa como a continuación,
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)
Una vez que tenga la nueva configuración del archivo de registro, puedo conectar el nivel de registro correcto para cada registrador desde la configuración. Solo quería compartir la respuesta y podría ayudar a alguien si están intentando usarlo con gevent.
Sin duda es posible usar fileConfig()
para cambiar la configuración de registro sobre la marcha, aunque para cambios simples, un enfoque programático como el sugerido en la respuesta de Martijn Pieters podría ser apropiado. El registro incluso proporciona un servidor de socket para escuchar los cambios de configuración utilizando las API de listen()
/ stopListening()
, como se documenta aquí . Para iniciar sesión y escuchar en un puerto en particular, usa
t = logging.config.listen(PORT_NUMBER)
t.start()
y para dejar de escuchar, llama
logging.config.stopListening()
Para enviar datos al servidor, puede usar, por ejemplo
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()
Actualización: debido a restricciones de compatibilidad con versiones anteriores, la implementación interna de la llamada fileConfig()
significa que no puede especificar disable_existing_loggers=False
en la llamada, lo que hace que esta característica sea menos útil en ciertos escenarios. Puede usar la misma API para enviar un archivo JSON utilizando el esquema dictConfig, que permitirá un mejor control sobre la reconfiguración. Esto requiere Python 2.7 / 3.2 o superior (donde se agregó dictConfig()
). O bien, puede usar el código stdlib para implementar su propio oyente, que funciona de la misma manera pero que se adapta a sus necesidades específicas.
fileConfig
es un mecanismo para configurar el nivel de registro basado en un archivo; puede cambiarlo dinámicamente en cualquier momento en su programa.
Llame a .setLevel()
en el objeto de registro para el que desea cambiar el nivel de registro. Normalmente harías eso en la raíz:
logging.getLogger().setLevel(logging.DEBUG)