Como @offbyone comenta, es posible agregar manejadores redundantes a la misma instancia del registrador. Los python docs for logging decir-
"Múltiples llamadas a getLogger() con el mismo nombre, se devolverá una referencia al mismo objeto registrador."
Así que no tenemos que preocuparnos por hacer que la implementación sea única, como ya lo es.
Desafortunadamente lo mismo es no verdadero para los manejadores asociados con la misma instancia del registrador. Hay puede ser manejadores duplicados adjuntos.
Ejemplo-
Copia este código y guardarlo en main.py
import logging
print 'inside main.py',
print '-'*50
def logger():
print 'initializing logger....'
logPath = '.'
fileName = 'temp'
# configure log formatter
logFormatter = logging.Formatter("%(asctime)s [%(filename)s] [%(funcName)s] [%(levelname)s] [%(lineno)d] %(message)s")
# configure file handler
fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))
fileHandler.setFormatter(logFormatter)
# configure stream handler
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
# get the logger instance
logger = logging.getLogger(__name__)
# set the logging level
logger.setLevel(logging.DEBUG)
print 'adding handlers- '
#if not len(logger.handlers):
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
print 'logger initialized....\n'
print 'associated handlers - ', len(logger.handlers)
for handler in logger.handlers:
print handler
print
return logger
main_logger = logger()
main_logger.info('utilizing main.py logger.')
print 'exiting main.py',
print '-'*50
y el código siguiente en sub.py
print 'inside sub.py',
print '-'*50
print 'importing main.py'
import main
print 'imported main.py'
import logging
print 'getting logger instance in sub'
sub_logger = main.logger()
print 'got logger instance in sub'
sub_logger.info("utilizing sub_logger")
print 'exiting sub.py',
print '-'*50
Ejecutar Sub.PY
[email protected]:~/code/so$ python sub.py
inside sub.py --------------------------------------------------
importing main.py
inside main.py --------------------------------------------------
initializing logger....
adding handlers-
logger initialized....
associated handlers - 2
<logging.FileHandler object at 0x7f7158740c90>
<logging.StreamHandler object at 0x7f7158710b10>
2015-08-04 07:41:01,824 [main.py] [<module>] [INFO] [41] utilizing main.py logger.
exiting main.py --------------------------------------------------
imported main.py
getting logger instance in sub
initializing logger....
adding handlers-
logger initialized....
associated handlers - 4 # <===== 4 handlers (duplicates added)
<logging.FileHandler object at 0x7f7158740c90>
<logging.StreamHandler object at 0x7f7158710b10>
<logging.FileHandler object at 0x7f7158710bd0>
<logging.StreamHandler object at 0x7f7158710c10>
got logger instance in sub
2015-08-04 07:41:01,824 [sub.py] [<module>] [INFO] [10] utilizing sub_logger
2015-08-04 07:41:01,824 [sub.py] [<module>] [INFO] [10] utilizing sub_logger
exiting sub.py --------------------------------------------------
Por lo tanto múltiples llamadas al método que regresan el mismo registrador añaden manipuladores duplicados.
Ahora, para su pregunta-
¿Hay alguna manera puedo comprobar para ver si el controlador ya existe
Sí, hay iS-
logger.handlers
devuelve una lista de todos los controladores asociados con el dado logger
.
Antes de añadir controladores a una instancia del registrador, asegúrese de no agregar controladores duplicados En main.py, simplemente no-comentar la línea que dice if not len(logger.handlers):
y sangría a las dos líneas siguientes properly-
if not len(logger.handlers):
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
Ahora, de nuevo
ejecutar sub.py
[email protected]:~/code/so$ python sub.py
inside sub.py --------------------------------------------------
importing main.py
inside main.py --------------------------------------------------
initializing logger....
adding handlers-
logger initialized....
associated handlers - 2
<logging.FileHandler object at 0x7fd67a891c90>
<logging.StreamHandler object at 0x7fd67a862b10>
2015-08-04 08:14:45,620 [main.py] [<module>] [INFO] [41] utilizing main.py logger.
exiting main.py --------------------------------------------------
imported main.py
getting logger instance in sub
initializing logger....
adding handlers-
logger initialized....
associated handlers - 2 # <===== Still 2 handlers (no duplicates)
<logging.FileHandler object at 0x7fd67a891c90>
<logging.StreamHandler object at 0x7fd67a862b10>
got logger instance in sub
2015-08-04 08:14:45,620 [sub.py] [<module>] [INFO] [10] utilizing sub_logger
exiting sub.py --------------------------------------------------
Además, si desea limitar el tipo de manipuladores que se añadirán a la instancia registrador, se puede hacer algo como esto:
print 'adding handlers- '
# allows to add only one instance of file handler and stream handler
if len(logger.handlers) > 0:
print 'making sure we do not add duplicate handlers'
for handler in logger.handlers:
# add the handlers to the logger
# makes sure no duplicate handlers are added
if not isinstance(handler, logging.FileHandler) and not isinstance(handler, logging.StreamHandler):
logger.addHandler(fileHandler)
print 'added file handler'
logger.addHandler(consoleHandler)
print 'added stream handler'
else:
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
print 'added handlers for the first time'
Espero que ayude!
Editar:
Por desgracia, la misma no es cierto para los manipuladores asociados con la misma instancia del registrador. Hay puede ser duplicados manejadores adjuntos.
Resulta que esa declaración anterior no es del todo cierto.
Supongamos que hemos creado y configurado un registrador llamado 'main_logger' en el módulo principal (que simplemente configura el registrador, no devuelve nada).
# get the logger instance
logger = logging.getLogger("main_logger")
# configuration follows
...
Ahora en un sub-módulo, si creamos un registrador de niño después de la jerarquía de nombres 'main_logger.sub_module_logger', no es necesario configurarlo en el sub-módulo. Solo la creación del registrador siguiendo la jerarquía de nombres es suficiente.
# get the logger instance
logger = logging.getLogger("main_logger.sub_module_logger")
# no configuration needed
# it inherits the configuration from the parent logger
...
Y no agregará el controlador duplicado también.
Referencia-Using logging in multiple modules
creo que debería volver a evaluar las respuestas, porque la respuesta de mouad (en el momento de escribir esto) pasa por alto el hecho de que varias llamadas a un método devolver el mismo objeto registrador * CAN * agregar controladores duplicados. Narayan hace un buen trabajo al explicar esto. –