once you dive into the logging

本文详细解析了OpenStack中的日志记录机制,包括如何配置和使用日志,以及日志文件的位置和级别设定等内容。介绍了logging.setup的作用,并通过代码示例展示了不同组件如何共享日志系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我看的时候还是I版和J版,这个时候对log的使用是import logging,现在k版oslo库的进入,log改用oslo_log库了,当然了,差别不大。

要使用log其实蛮简单的,在配置文件中配置log_dir或者log_file, 设置log的level就可以了, 但是如果你比较好奇log是怎么运作的,怎么使用log的,你可以看看:

各个openstack的module对于log的使用大同小异的,以nova为例,我们见得第一眼就是:

    logging.setup('nova')

感觉很神奇,貌似加上这一句,然后在各个要使用的类中:

LOG = logging.getLogger(__name__)

LOG.xxx(info,debug,warn)等等就可以使用了

作为调试代码,查看openstack运行原理的利器,虽然我们每个人都有最适合紫的开发方法,有的可能用pdb,有的用远程调试,但是打log几乎是大型分布式系统或

多进程多线程的系统不二方式,就我看类没有比打log更广泛的方式。

这就是setup(你可以用pip或者easy_install下载logging):

def setup(product_name, version='unknown'):
    """Setup logging."""
    if CONF.log_config_append:
        _load_log_config(CONF.log_config_append)
    else:
        _setup_logging_from_conf(product_name, version) #正常情况下,我们用openstack给出的log,不配置log_config_append
    sys.excepthook = _create_logging_excepthook(product_name)

在_setup_logging_from_conf中最重要的是这几句的理解:


    log_root = getLogger(None).logger

  def getLogger(name='unknown', version='unknown'):
    if name not in _loggers:
        _loggers[name] = ContextAdapter(logging.getLogger(name), name,version)
       return _loggers[name]

此处返回的ContextAdapater中,logging.getLogger指的是logging包中的RootLogger
    for handler in log_root.handlers:
        log_root.removeHandler(handler)
#不同的进程会得到不同的RootLogger
    logpath = _get_log_file_path()

#得到log文件

if logdir:
        binary = binary or _get_binary_name()#os.path.basename(inspect.stack()[-1][1])
        return '%s.log' % (os.path.join(logdir, binary),)

是怎么办到的呢,归功于inspect.stack,在mark的link中有介绍,难道执行到当前程序行的调用栈,使用[-1][1]取出的最顶层调用文件,

我想你明白了,我们是如何启动nova的服务的呢,执行的是/usr/bin/nova-api或者/usr/bin/nova-xxx,对应的文件为nova-api或者nova-xxx,

所以!我们在log_dir,也就是/var/log/nova下面对应的log文件是nova-api.log等等

这里,我们知道了日志写到哪里去,且root logger默认的是warning的level,因此默认情况下,你改动程序用debug或者info的level是没有输出的.

于是我们解决了一半的问题,另一半的问题在于:

LOG = logging.getLogger(__name__)

同样的回到getLogger函数:

def getLogger(name='unknown', version='unknown'):
    if name not in _loggers:
        _loggers[name] = ContextAdapter(logging.getLogger(name),
                                        name,
                                        version)
    return _loggers[name]

此时name不为None,返回:

    if name:
        return Logger.manager.getLogger(name)

magic在哪里,我们trace  getLogger有   self._fixupParents(rv)

查看fixupParents:

name = alogger.name
        i = name.rfind(".")
        rv = None
        while (i > 0) and not rv:
            substr = name[:i]
            if substr not in self.loggerDict:
                self.loggerDict[substr] = PlaceHolder(alogger)
            else:
                obj = self.loggerDict[substr]
                if isinstance(obj, Logger):
                    rv = obj
                else:
                    assert isinstance(obj, PlaceHolder)
                    obj.append(alogger)
            i = name.rfind(".", 0, i - 1)
        if not rv:
            rv = self.root
        alogger.parent = rv

根据name,得到顶层的logger,也就是前面的root logger

在不同的.py文件中使用log时,比如nova/conductor/manager.py,那么最终根据nova.conductor.manager.py,最终

log会写入nova-conductor.log中

我们根据这个规则,我们就能根据module name找到log的位置。


当然了,logger我们有file handler,也有别的handler,不受这些file handler handle的log就会写到满足条件的logger中,

关于这一点可以看Logger的callHandlers方法。


最后一点,如何写log的,文件写入到哪一行等,在Logger的findCaller中可以去详细的看。

事实上,我还没听说哪个团队在开发log的部分,当然了每个模块都少不了,值得看:)


mark link:

http://hyry.dip.jp/tech/book/page/python/debug_stack.html

http://pymotw.com/2/inspect/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值