modules - python logging level values
Usando el registro de Python en múltiples módulos (7)
Tengo un pequeño proyecto de pitón que tiene la siguiente estructura:
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
Planeo usar el módulo de registro predeterminado para imprimir mensajes a stdout y a un archivo de registro. Para usar el módulo de registro, se requiere alguna inicialización:
import logging.config
logging.config.fileConfig(''logging.conf'')
logger = logging.getLogger(''pyApp'')
logger.info(''testing'')
Actualmente, realizo esta inicialización en cada módulo antes de comenzar a registrar mensajes. ¿Es posible realizar esta inicialización solo una vez en un lugar, de manera que se reutilicen las mismas configuraciones registrando todo el proyecto?
¡También podrías pensar en algo como esto!
def get_logger(name=None):
default = "__app__"
formatter = logging.Formatter(''%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s'',
datefmt=''%Y-%m-%d %H:%M:%S'')
log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"}
if name:
logger = logging.getLogger(name)
else:
logger = logging.getLogger(default)
fh = logging.FileHandler(log_map[name])
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.setLevel(logging.DEBUG)
return logger
Ahora podría usar múltiples registradores en el mismo módulo y en todo el proyecto si lo anterior se define en un módulo separado y se importa en otros módulos donde se requiere el inicio de sesión.
a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starting logging!")
b.debug("Debug Mode")
En realidad, cada registrador es hijo del registrador de paquetes del padre (es decir, package.subpackage.module
hereda la configuración de package.subpackage)
, por lo que todo lo que necesita hacer es simplemente configurar el registrador de raíz. Esto se puede lograr con logging.config.fileConfig
(su propia configuración para registradores) o logging.basicConfig
(establece el registrador de raíz). Configure el inicio de sesión en su módulo de entrada ( __main__.py
o lo que sea que desee ejecutar, por ejemplo, main_script.py
. __init__.py
funciona)
usando basicConfig:
# package/__main__.py
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
usando fileConfig:
# package/__main__.py
import logging
import logging.config
logging.config.fileConfig(''logging.conf'')
y luego crea cada registrador usando:
# package/submodule.py
# or
# package/subpackage/submodule.py
import logging
log = logging.getLogger(__name__)
log.info("Hello logging!")
Para obtener más información, consulte el Tutorial de registro avanzado .
La mejor práctica es, en cada módulo, tener un registrador definido así:
import logging
logger = logging.getLogger(__name__)
cerca de la parte superior del módulo, y luego en otro código en el módulo, por ejemplo
logger.debug(''My message with %s'', ''variable data'')
Si necesita subdividir la actividad de registro dentro de un módulo, use, por ejemplo,
loggerA = logging.getLogger(__name__ + ''.A'')
loggerB = logging.getLogger(__name__ + ''.B'')
y log a loggerA
y loggerB
según corresponda.
En su programa principal o programas, haga, por ejemplo:
def main():
"your program code"
if __name__ == ''__main__'':
import logging.config
logging.config.fileConfig(''/path/to/logging.conf'')
main()
o
def main():
import logging.config
logging.config.fileConfig(''/path/to/logging.conf'')
# your program code
if __name__ == ''__main__'':
main()
Vea here para el registro desde múltiples módulos, y here para la configuración de registro para el código que se utilizará como un módulo de biblioteca por otro código.
Actualización: Al llamar a fileConfig()
, es posible que desee especificar disable_existing_loggers=False
si está utilizando Python 2.6 o posterior (consulte los documentos para obtener más información). El valor predeterminado es True
para compatibilidad con versiones anteriores, lo que hace que todos los registradores existentes sean deshabilitados por fileConfig()
menos que ellos o sus antecesores sean explícitamente nombrados en la configuración. Con el valor establecido en False
, los registradores existentes se quedan solos. Si usa Python 2.7 / Python 3.2 o posterior, puede considerar la API dictConfig()
que es mejor que fileConfig()
ya que le da más control sobre la configuración.
La solución de @ Yarkee parecía mejor. Me gustaría añadir algo más a eso:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances.keys():
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class LoggerManager(object):
__metaclass__ = Singleton
_loggers = {}
def __init__(self, *args, **kwargs):
pass
@staticmethod
def getLogger(name=None):
if not name:
logging.basicConfig()
return logging.getLogger()
elif name not in LoggerManager._loggers.keys():
logging.basicConfig()
LoggerManager._loggers[name] = logging.getLogger(str(name))
return LoggerManager._loggers[name]
log=LoggerManager().getLogger("Hello")
log.setLevel(level=logging.DEBUG)
Entonces LoggerManager puede ser conectable a toda la aplicación. Espero que tenga sentido y valor.
Lanzando en otra solución.
En el init principal de mi módulo, tengo algo como:
import logging
def get_module_logger(mod_name):
logger = logging.getLogger(mod_name)
handler = logging.StreamHandler()
formatter = logging.Formatter(
''%(asctime)s %(name)-12s %(levelname)-8s %(message)s'')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
return logger
Luego en cada clase necesito un registrador, lo hago:
from [modname] import get_module_logger
logger = get_module_logger(__name__)
Cuando se pierden los registros, puede diferenciar su origen del módulo del que provienen.
Siempre lo hago como abajo.
Use un solo archivo python para configurar mi registro como un patrón singleton que nombre '' log_conf.py
''
#-*-coding:utf-8-*-
import logging.config
def singleton(cls):
instances = {}
def get_instance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return get_instance()
@singleton
class Logger():
def __init__(self):
logging.config.fileConfig(''logging.conf'')
self.logr = logging.getLogger(''root'')
En otro módulo, solo importa la configuración.
from log_conf import Logger
Logger.logr.info("Hello")
Este es un patrón singleton para iniciar sesión, de manera simple y eficiente.
Varias de estas respuestas sugieren que en la parte superior de un módulo lo haces
import logging
logger = logging.getLogger(__name__)
Entiendo que esto se considera una mala práctica . La razón es que la configuración del archivo desactivará todos los registradores existentes de forma predeterminada. P.ej
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logger.info(''Hi, foo'')
class Bar(object):
def bar(self):
logger.info(''Hi, bar'')
Y en tu módulo principal:
#main
import logging
# load my module - this now configures the logger
import my_module
# This will now disable the logger in my module by default, [see the docs][1]
logging.config.fileConfig(''logging.ini'')
my_module.foo()
bar = my_module.Bar()
bar.bar()
Ahora el registro especificado en logging.ini estará vacío, ya que el registrador existente fue deshabilitado por la llamada fileconfig.
Si bien es posible evitar esto (disable_existing_Loggers = False), de forma realista, muchos clientes de su biblioteca no conocerán este comportamiento y no recibirán sus registros. Facilítelo a sus clientes llamando siempre a logging.getLogger localmente. Sombrero Sugerencia: aprendí sobre este comportamiento del sitio web de Victor Lin .
Entonces, una buena práctica es llamar siempre a logging.getLogger localmente. P.ej
#my_module
import logging
logger = logging.getLogger(__name__)
def foo():
logging.getLogger(__name__).info(''Hi, foo'')
class Bar(object):
def bar(self):
logging.getLogger(__name__).info(''Hi, bar'')
Además, si usa fileconfig en su main, establezca disable_existing_loggers = False, en caso de que los diseñadores de su biblioteca usen instancias de registrador de nivel de módulo.