项目的结构化日志记录

时间:2016-03-24 16:37:38

标签: python python-2.7 logging

我在我的python项目上使用Logging。 我的问题是关于在我的项目中构建日志记录的正确和优雅的方法,因为我将首先描述我正在使用的结构。

我有3个主要的.py脚本,所以在启动时称为服务的acquisition.py,actus.py和management.py。 上面的3个脚本导入network.py和devices.py。

我想组织与3个主要脚本相关的每个文件的日志记录,所以我想拥有:acquisition.log,actuation.log和management.log。在这个日志里面我希望从对network.py的调用中得到相应的日志一个device.py(使用命名空间%(name)

示例(acquisition.log):

INFO acquisition.thread 2016-03-17 12:26:02,069 in Thread 70de3b66-e14b-11e5-8953-80fa5b0ae007
DEBUG acquisition 2016-03-17 12:26:02,070 Thread launched 70de3b66-e14b-11e5-8953-80fa5b0ae007
INFO acquisition.devices 2016-03-17 12:26:03,072  Variable_R read:  0013a20040c1bb0b  temperature1
ERROR acquisition.devices 2016-03-17 12:26:19,076 variable.read.DeviceConfigurationError: 0013a20040c1bb0b 
INFO acquisition.thread 2016-03-17 12:26:19,077 exit Thread 70ddfa20-e14b-11e5-8953-80fa5b0ae007
ERROR acquisition.devices 2016-03-17 12:26:25,085 variable.read.DeviceConfigurationError: 0013a20040c1bb0b 
INFO acquisition.thread 2016-03-17 12:26:25,086 exit Thread 70de3b66-e14b-11e5-8953-80fa5b0ae007

在这种情况下,您可以看到,对于同一个日志文件,我可以从不同的文件进行日志记录,可以在日志命名空间 acquisition.thread acquisition.devices <中看到它/强>

我实现这一点的方法是使用记录器功能,我用它在每个文件中创建一个后备记录器,我正在记录。并且,稍后如果我想记录该文件中的信息,我会在主脚本文件中更改导入文件中创建的记录器。

解释上述内容的代码示例:

acquisition.py(主脚本):

imports...
import logger_sys
import logging
import xnetwork
import xdevices

# Log configuration
log_name = os.path.basename(__file__).strip(".py")
logit = logger_sys.setup_logger(log_name, log_name) #internal logger for main file
logger_thread = logging.getLogger(log_name + '.thread')

#Log configuration of external files
xnetwork.logger = logging.getLogger(log_name + '.network')
xdevices.logger = logging.getLogger(log_name + '.devices')

logit.info("START acquisition_service")

# REST OF THE CODE... 

xdevices.py:

import logger_sys

# Fallback logger in case the calling script doesnt modify logger
log_name = __name__.strip(".py") + '_fallback'
logger = logger_sys.setup_logger(log_name, log_name, stream_hdlr=False)

# REST OF THE CODE...

xnetworks.py:

import logger_sys

# Fallback logger in case the calling script doesnt modify logger
log_name = __name__.strip(".py") + '_fallback'
logger = logger_sys.setup_logger(log_name, log_name, stream_hdlr=False)

# REST OF THE CODE...

logger_sys.py:

import logging, sys, os
from global_settings import RUNNING_MODE, DEBUG, STAGING, PRODUCTION

def setup_logger(namespace, filename, stream_hdlr=True):

    logger = logging.getLogger(namespace)

    handler_format = logging.Formatter("%(levelname)s %(name)s %(asctime)s %(message)s")

    log_handler = logging.FileHandler(filename + ".log")
    logger.addHandler(log_handler)
    log_handler.setFormatter(handler_format)

    if RUNNING_MODE == DEBUG:
        if stream_hdlr:
            log_handler = logging.StreamHandler(sys.stdout)
            logger.addHandler(log_handler)
            log_handler.setFormatter(handler_format)

        logger.setLevel(logging.DEBUG)

    elif RUNNING_MODE == STAGING or RUNNING_MODE == PRODUCTION:
        logger.setLevel(logging.INFO)

    return logger

目标?

  • 我想知道是否有更优雅的解决方案,不使用将记录器作为参数传递给被调用方法的逻辑。

  • 我想了解在更复杂的情况下,例如在使用外部模块时,日志记录的结​​构通常是什么。

  • 而且,我想阅读关于这种采伐策略的评论家。

提前谢谢

1 个答案:

答案 0 :(得分:2)

您应该学习官方logging cookbook和一些正确记录的复杂项目。我建议阅读requests source code以了解一个相当复杂的项目如何进行记录。

对你的案子来说,食谱的关键点可能是:

  

对logging.getLogger(&#39; someLogger&#39;)的多次调用会返回一个引用   到同一个记录器对象。不仅在同一个地方也是如此   模块,但也可以跨模块,只要它在同一个Python中   翻译过程。

一种典型的方法是在文件顶部添加以下内容:

.plot()

这会使import logging log = logging.getLogger(__name__) 成为全局,因此可以在函数中使用它而不传递log作为参数:

log

如果您正在创建一些长时间运行的服务并打算记录所有/大多数/多个函数调用,请考虑使用装饰器。我建议this post from the Fresh Books Dev Blog作为使用装饰器进行日志记录的介绍。听起来您的程序可能会受益于装饰器方法。