En este momento tengo un módulo central en un marco que genera múltiples procesos utilizando el multiprocessing
módulo Python 2.6 . Debido a que utiliza multiprocessing
, no hay registro de multiprocesamiento-conscientes de nivel de módulo, LOG = multiprocessing.get_logger()
. Según los documentos , este registrador tiene bloqueos compartidos de proceso para que no pueda confundir las cosas sys.stderr
(o cualquier archivo de control) al tener múltiples procesos que escriben en él simultáneamente.
El problema que tengo ahora es que los otros módulos en el marco no son multiprocesadores. A mi modo de ver, necesito hacer que todas las dependencias de este módulo central utilicen el registro con reconocimiento de multiprocesamiento. Eso es molesto dentro del marco, y mucho menos para todos los clientes del marco. ¿Hay alternativas en las que no estoy pensando?
fuente
multiprocessing.get_logger()
? Parece que estas otras formas de hacer el registro son la funcionalidad de registromultiprocessing
de poco valor.get_logger()
es el registrador utilizado por elmultiprocessing
propio módulo. Es útil si desea depurar unmultiprocessing
problema.Respuestas:
La única forma de lidiar con esto de manera no intrusiva es:
select
partir de los descriptores de archivo de las tuberías, realice una ordenación por fusión en las entradas de registro disponibles y vacíe al registro centralizado. Repita).fuente
atexit
:-). El problema es que no te dará una lectura en tiempo real. Esto puede ser parte del precio del multiprocesamiento en lugar de multiproceso.multiprocessing.Queue
no será más sencillo si hay mucho código para volver a cablear para usarmultiprocessing.Queue
, y / o si el rendimiento es un problemaAcabo de escribir un controlador de registro propio que simplemente alimenta todo al proceso principal a través de una tubería. Solo lo he estado probando durante diez minutos, pero parece funcionar bastante bien.
( Nota: Esto está codificado
RotatingFileHandler
, que es mi propio caso de uso).Actualización: @javier ahora mantiene este enfoque como un paquete disponible en Pypi: consulte multiprocesamiento-registro en Pypi, github en https://github.com/jruere/multiprocessing-logging
Actualización: Implementación!
Esto ahora usa una cola para el manejo correcto de la concurrencia, y también se recupera de los errores correctamente. He estado usando esto en producción durante varios meses, y la versión actual a continuación funciona sin problemas.
fuente
multiprocessing.Queue
usa un hilo para adentroput()
. Por lo tanto, no invoqueput
(es decir, registre un mensaje con elMultiProcessingLog
controlador) antes de crear todos los subprocesos. De lo contrario, el hilo estará muerto en el proceso hijo. Una solución es llamarQueue._after_fork()
al comienzo de cada proceso secundario, o utilizarmultiprocessing.queues.SimpleQueue
en su lugar, lo que no implica subproceso, pero está bloqueando.multiprocessing-logging
.QueueHandler
es nativo en Python 3.2+, y hace exactamente esto. Se replica fácilmente en versiones anteriores.Los documentos de Python tienen dos ejemplos completos: iniciar sesión en un solo archivo desde múltiples procesos
Para aquellos que usan Python <3.2, simplemente copie
QueueHandler
en su propio código desde: https://gist.github.com/vsajip/591589 o, alternativamente, importe logutils .Cada proceso (incluido el proceso principal) coloca su registro en el
Queue
, y luego unlistener
hilo o proceso (se proporciona un ejemplo para cada uno) los recoge y los escribe a todos en un archivo, sin riesgo de corrupción o desorden.fuente
A continuación hay otra solución con un enfoque en la simplicidad para cualquier otra persona (como yo) que llegue aquí desde Google. ¡El registro debería ser fácil! Solo para 3.2 o superior.
fuente
QueueHandler
y tambiénQueueListener
se pueden usar en Python 2.7, disponible en ellogutils
paquete.Otra alternativa podría ser los diversos controladores de registro no basados en archivos en el
logging
paquete :SocketHandler
DatagramHandler
SyslogHandler
(y otros)
De esta manera, podría tener fácilmente un demonio de registro en algún lugar en el que podría escribir de forma segura y manejar los resultados correctamente. (Por ejemplo, un servidor de socket simple que simplemente desempaqueta el mensaje y lo emite a su propio controlador de archivos rotativo).
También
SyslogHandler
se encargaría de esto por ti. Por supuesto, puede usar su propia instanciasyslog
, no la del sistema.fuente
Una variante de los demás que mantiene separados el hilo de registro y la cola.
fuente
fileConfig()
en MainProcess y un registrador apenas configurado en PoolWorkers (solo consetLevel(logging.NOTSET)
). Como mencioné en otro comentario, estoy usando Pool, así que tuve que obtener mi Cola (proxy) del Administrador en lugar de multiprocesamiento para que pueda encurtirse. Esto me permite pasar la cola a un trabajador dentro de un diccionario (la mayoría de los cuales se deriva del uso del objeto argsparsevars()
). Creo que al final este es el mejor enfoque para MS Windows que carece de fork () y rompe la solución @zzzeak.fork
. De esa forma, cada proceso tendrá su propia cola inútil independiente. El segundo enfoque en el Q / A vinculado no funcionará en tales plataformas. Es una forma de código no portátil.multiprocessing.Queue
proceso principal y lo he estado usando constantemente desde entonces. Sin embargo, no pretendo entender por qué funciona.Todas las soluciones actuales están demasiado acopladas a la configuración de registro mediante un controlador. Mi solución tiene la siguiente arquitectura y características:
multiprocessing.Queue
logging.Logger
(y las instancias ya definidas) son parcheadas para enviar todos los registros a la colaEl código con el ejemplo de uso y la salida se puede encontrar en el siguiente Gist: https://gist.github.com/schlamar/7003737
fuente
daemon_thread.daemon
aTrue
. Tenía que hacer eso para que mi programa Python salga correctamente cuando ocurra una excepción dentro del administrador de contexto.func
delogged_call
, si no la excepción conseguiría ilegible con otra salida registrada. Aquí está mi versión modificada de esto: gist.github.com/blah238/8ab79c4fe9cdb254f5c37abfc5dc85bfDado que podemos representar el registro multiproceso como muchos editores y un suscriptor (escucha), usar ZeroMQ para implementar la mensajería PUB-SUB es una opción.
Además, el módulo PyZMQ , los enlaces de Python para ZMQ, implementa PUBHandler , que es un objeto para publicar mensajes de registro en un zmq.PUB socket.
Hay una solución en la web para el registro centralizado desde una aplicación distribuida usando PyZMQ y PUBHandler, que puede adoptarse fácilmente para trabajar localmente con múltiples procesos de publicación.
fuente
También me gusta la respuesta de zzzeek, pero Andre tiene razón en que se requiere una cola para evitar la confusión. Tuve un poco de suerte con la pipa, pero sí vi que era algo esperable. Implementarlo resultó ser más difícil de lo que pensaba, particularmente debido a que se ejecuta en Windows, donde hay algunas restricciones adicionales sobre variables globales y otras cosas (ver: ¿Cómo se implementa el multiprocesamiento de Python en Windows? )
Pero, finalmente lo conseguí funcionando. Este ejemplo probablemente no sea perfecto, por lo que los comentarios y sugerencias son bienvenidos. Tampoco admite la configuración del formateador o cualquier otra cosa que no sea el registrador raíz. Básicamente, debe reiniciar el registrador en cada uno de los procesos del grupo con la cola y configurar los otros atributos en el registrador.
Una vez más, cualquier sugerencia sobre cómo mejorar el código es bienvenida. Ciertamente todavía no conozco todos los trucos de Python :-)
fuente
if 'MainProcess' == multiprocessing.current_process().name:
se puede usar en lugar de pasarchild
.simplemente publique en alguna parte su instancia del registrador. de esa manera, los otros módulos y clientes pueden usar su API para obtener el registrador sin tener que hacerlo
import multiprocessing
.fuente
import logging; logging.basicConfig(level=logging.DEBUG); logging.debug('spam!')
desde cualquier lugar y hacer que funcione correctamente.Me gustó la respuesta de zzzeek. Simplemente sustituiría la Tubería por una Cola ya que si varios hilos / procesos usan el mismo extremo de la tubería para generar mensajes de registro, quedarán confusos.
fuente
¿Qué tal delegar todo el registro a otro proceso que lea todas las entradas de registro de una Cola?
Simplemente comparta LOG_QUEUE a través de cualquiera de los mecanismos multiproceso o incluso la herencia, ¡y todo funciona bien!
fuente
Tengo una solución similar a la de Ironhacker, excepto que utilizo logging.exception en algunos de mis códigos y descubrí que necesitaba formatear la excepción antes de pasarla de nuevo a la cola, ya que los rastreadores no son seleccionables:
fuente
A continuación se muestra una clase que se puede utilizar en un entorno Windows, requiere ActivePython. También puede heredar para otros controladores de registro (StreamHandler, etc.)
Y aquí hay un ejemplo que demuestra el uso:
fuente
multiprocessing.Lock()
lugar de Windows Mutex haría que la solución sea portátil.Aquí está mi truco / solución simple ... no es el más completo, pero es fácilmente modificable y más fácil de leer y entender, creo que cualquier otra respuesta que encontré antes de escribir esto:
fuente
Hay este gran paquete
Paquete: https://pypi.python.org/pypi/multiprocessing-logging/
código: https://github.com/jruere/multiprocessing-logging
Instalar en pc:
Luego añade:
fuente
Una de las alternativas es escribir el registro de multiprocesamiento en un archivo conocido y registrar un
atexit
controlador para unirse a esos procesos, leerlo nuevamente en stderr; sin embargo, no obtendrá un flujo en tiempo real a los mensajes de salida en stderr de esa manera.fuente
Si tiene puntos muertos en una combinación de bloqueos, hilos y bifurcaciones en el
logging
módulo, eso se informa en el informe de error 6721 (consulte también la pregunta SO relacionada ).Hay una pequeña solución de reparación publicada aquí .
Sin embargo, eso solo solucionará cualquier posible punto muerto
logging
. Eso no arreglará que las cosas estén distorsionadas. Vea las otras respuestas presentadas aquí.fuente
La idea más simple como se menciona:
[WatchedFileHandler][1]
. Las razones de este controlador se discuten en detalle aquí , pero en resumen hay ciertas peores condiciones de carrera con los otros controladores de registro. Este tiene la ventana más corta para la condición de carrera.fuente
Para quien necesite esto, escribí un decorador para el paquete multiprocessing_logging que agrega el nombre del proceso actual a los registros, por lo que queda claro quién registra qué.
También ejecuta install_mp_handler (), por lo que resulta inútil ejecutarlo antes de crear un grupo.
Esto me permite ver qué trabajador crea qué mensajes de registro.
Aquí está el plano con un ejemplo:
fuente
A mis hijos que enfrentan el mismo problema en décadas y encontraron esta pregunta en este sitio, les dejo esta respuesta.
Simplicidad vs sobrecomplicación. Solo usa otras herramientas. Python es impresionante, pero no fue diseñado para hacer algunas cosas.
El siguiente fragmento de logrotate daemon funciona para mí y no complica demasiado las cosas. Programe que se ejecute cada hora y
Así es como lo instalo (los enlaces simbólicos no funcionan para logrotate):
fuente