openstack 中 log模块分析

1 . 所在模块,一般在openstack/common/log.py,其实最主要的还是调用了python中的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)
    sys.excepthook = _create_logging_excepthook(product_name)

如果配置文件中设置了log_config_append,log_config_append 就是logging的配置,形式如下面这样的:

在函数_load_log_config中实现:
def _load_log_config(log_config_append):
    try:
        logging.config.fileConfig(log_config_append,
                                  disable_existing_loggers=False)
    except moves.configparser.Error as exc:
        raise LogConfigError(log_config_append, str(exc))

LogConfigError是一个自定义的Exception,也在log.py中;

如果没有设置log_config_append,则通过_setup_logging_from_conf函数来进行log的设置;
508     log_root = getLogger(None).logger
509     for handler in log_root.handlers:
510         log_root.removeHandler(handler)
511
512     if CONF.use_syslog:
513         facility = _find_facility_from_conf()
514         # TODO(bogdando) use the format provided by RFCSysLogHandler
515         #   after existing syslog format deprecation in J
516         if CONF.use_syslog_rfc_format:
517             syslog = RFCSysLogHandler(address=‘/dev/log‘,
518                                       facility=facility)
519         else:
520             syslog = logging.handlers.SysLogHandler(address=‘/dev/log‘,
521                                                     facility=facility)
522         log_root.addHandler(syslog)
523
524     logpath = _get_log_file_path()
525     if logpath:
526         filelog = logging.handlers.WatchedFileHandler(logpath)
527         log_root.addHandler(filelog)
528
529     if CONF.use_stderr:
530         streamlog = ColorHandler()
531         log_root.addHandler(streamlog)
532
533     elif not logpath:
534         # pass sys.stdout as a positional argument
535         # python2.6 calls the argument strm, in 2.7 it‘s stream
536         streamlog = logging.StreamHandler(sys.stdout)
537         log_root.addHandler(streamlog)
538
539     if CONF.publish_errors:
540         handler = importutils.import_object(
541             "openstack.common.log_handler.PublishErrorsHandler",
542             logging.ERROR)
543         log_root.addHandler(handler)
544
545     datefmt = CONF.log_date_format
546     for handler in log_root.handlers:
547         # NOTE(alaski): CONF.log_format overrides everything currently.  This
548         # should be deprecated in favor of context aware formatting.
549         if CONF.log_format:
550             handler.setFormatter(logging.Formatter(fmt=CONF.log_format,
551                                                    datefmt=datefmt))
552             log_root.info(‘Deprecated: log_format is now deprecated and will ‘
553                           ‘be removed in the next release‘)
554         else:
555             handler.setFormatter(ContextFormatter(project=project,
556                                                   version=version,
557                                                   datefmt=datefmt))
558
559     if CONF.debug:
560         log_root.setLevel(logging.DEBUG)
561     elif CONF.verbose:
562         log_root.setLevel(logging.INFO)
563     else:
564         log_root.setLevel(logging.WARNING)
565
566     for pair in CONF.default_log_levels:
567         mod, _sep, level_name = pair.partition(‘=‘)
568         level = logging.getLevelName(level_name)
569         logger = logging.getLogger(mod)
570         logger.setLevel(level)

508~510 行;首先取得root logger,在logging中,有个默认的rootlogger,任何其他的logger都是这个rootlogger的继承,然后将handler清空,logger可以设置handler,handler是负责将传给logger的信息显示出来的,如显示到stdout,输出到文件等等;

512~522 行,是否写系统的syslog,一般linux 是/dev/log, mac是/var/run/syslog

524到527行,_get_log_file_path函数取得log path,实际上就是判断conf中是否有设置conf.log_file和conf.log_dir; 
watchedfilehandler是将log信息输出到文件,watched的具体含义是当发现输出到文件有变化(A file is deemed to have changed if its device or inode have changed),当发现文件有变化的时候,
会将之前的文件流关闭,文件会再一次用一个新的文件流打开;这个在使用log rotation机制的时候是有用的。

529到531行,如果设置了conf.stderr,,通过ColorHandler来进行

533到537行,如果没有设置logpath,  那么stream handler(标准输出)加入到root log里面;

539到543行,如果设置了publish_errors,则调用publisherrorhandler
22 class PublishErrorsHandler(logging.Handler):
23     def emit(self, record):
24         if (‘openstack.common.notifier.log_notifier‘ in
25                 cfg.CONF.notification_driver):
26             return
27         notifier.api.notify(None, ‘error.publisher‘,
28                             ‘error_notification‘,
29                             notifier.api.ERROR,
30                             dict(error=record.getMessage()))
publisherrorhandler重写了emit方法,将log信息用notifier发送出去;

545 到557行对log的格式进行设置的部分;

559 到 564 在DEBUG < INFO < WARNING 之间选择一个,作为rootlogger的log level,其他的log如果没有单独设置level,会默认继承rootLogger的level;DEBUG和VERBOSE可以通过配置文件进行配置;

566,570可以通过CONF./default_log_levels分别针对不同的模块进行不同的level级别的设置;

setup函数基本分析完毕,可以如下使用setup函数;
from higgs.agent.common import config
config.setup_logging(cfg.CONF)

但一般在开始的常用方法为
from openstack.common import log as logging
LOG = logging.getLogger(__name__)

这个时候其实时调用openstack/common/log.py中的ContextAdapter类;
ContextAdapter类继承了BaseLoggerAdapter类继承于logging.LoggerAdapter类;LoggerAdapter的作用主要是
可以允许你在打印日志时,对日志做一些统一的处理,加入一些上下文信息(contextual information),例如在一个网络应用程序里面,你很有可能想在log中包含一些客户端信息
(比如客户端的username,ipaddress等)。
LoggerAdapter的实现方式更像是一个代理或者适配器,实例化一个LoggerAdapter的时候,你需要传递一个Logger实例和一个dict-like object包含你的上下文信息,然后,LoggerAdapter也要info、debug、
error、critical等方法,并且他们的函数签名与Logger本身的签名是一样的,然后在LoggerAdapter所做的事情就类似于下面的片段;

def debug(self, msg, *args, **kwargs):
    """Delegate a debug call to the underlying logger,
    after adding contextual information from this adapter instance."""
    msg, kwargs =self.process(msg, kwargs)
    self.logger.debug(msg, *args, **kwargs)

首先调用process方法对参数进行一定的处理,然后再将处理后的参数传给底层的logger进行调用;
在openstack里面主要是为了在log中加入了一些project、version等信息;

还有一个LazyLogger,延迟加载的logger;

时间: 2024-10-30 15:35:05

openstack 中 log模块分析的相关文章

Openstack中RabbitMQ RPC代码分析

在Openstack中,RPC调用是通过RabbitMQ进行的. 任何一个RPC调用,都有Client/Server两部分,分别在rpcapi.py和manager.py中实现. 这里以nova-scheduler调用nova-compute为例子. nova/compute/rpcapi.py中有ComputeAPI nova/compute/manager.py中有ComputeManager 两个类有名字相同的方法,nova-scheduler调用ComputeAPI中的方法,通过底层的R

Openstack liberty源码分析 之 云主机的启动过程3

接上篇Openstack liberty源码分析 之 云主机的启动过程2, 简单回顾下:nova-conductor收到nova-scheduler返回的主机列表后,依次发送异步rpc请求给目标主机的nova-compute服务,下面继续来看nova-compute服务的处理过程: nova-compute 根据路由映射,nova-compute中处理云主机启动请求的方法为 nova/compute/manager.py.ComputeManager.py.build_and_run_insta

OpenStack Kolla 源码分析 --Ansible

OpenStack Kolla 源码分析 –Ansible Kolla介绍 Kolla项目利用Docker.Docker-Compose.Ansible来完成部署OpenStack,目前Kolla已经能够完成一个all-in-one的开发环境的部署.从Kolla项目spec中的描述来看,主要是利用Docker容器的隔离性来达到OpenStack的原子升级.回退在升级.整个升级.回退的过程更容易控制影响范围,降低整个OpenStack的运维复杂度.Kolla 提供了生产级别的 OpenStack

Android WIFI模块分析

一:什么是WIFI WIFI是一种无线连接技术,可用于手机.电脑.PDA等终端.WIFI技术产生的目的是改善基于IEEE802.11标准的无线网络产品之间的互通性,也就是说WIFI是基于802.11标准的,但WIFI不等同无线网络. 二:Android平台下的WIFI模块 简单介绍一下,WIFI模块的基本功能: 1. 开关WIFI 除了在WIFI设置界面可以开关WIFI,还有其他的方法可以设置,要查看这些开关状态是否一致.还有就是飞行模式对WIFI开关的影响,由于WIFI开和关都有一个时间过程,

探索 OpenStack 之(14):OpenStack 中 RabbitMQ 使用研究 (上半部分)

本文是 OpenStack 中的 RabbitMQ 使用研究 两部分中的第一部分,将介绍 RabbitMQ 的基本概念,即 RabbitMQ 是什么.第二部分将介绍其在 OpenStack 中的使用. 1 RabbitMQ 的基本概念 RabbitMQ 是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件). AMQP是一个定义了在应用或者组织之间传送消息的协议的开放标准 (an open standard for passing business messages be

openstack swift 源码分析之swift单机部署

本文对在单机部署swift 其中每一个细节做详细的介绍,并对配置做相应的解释 PC物理机    Ubuntu-12.04-desktop-64位 Swift 版本:1.13.1 Swift-client   1.2.0 注意:本文所有操作都是在root权限下进行的. 1 .下载swift 和swift-client 源代码,本文利用git从github获取其源代码 获取swift源代码 git clone https://github.com/openstack/swift.git 获取pyth

基于Android6.0的RIL框架层模块分析

本文与另外一篇分析RIL底层模块的文章是姐妹篇:基于Android6.0的RIL底层模块分析 根据手机网络制式的不同,通常系统中会扩展Phone.java这个类,扩展成GSMPhone和CDMAPhone.这个类主要是抽象整个手机来处理通信过程中与其他模块的交互.我们以GSMPhone为例,分析来电流程如何从底层传递到上层.该分析主要基于代码,所以会比较啰嗦. 以GSMPhone为例,在PhoneFactory类中有实例化该类的方法: public static Phone getGsmPhon

Openstack liberty源码分析 之 云主机的启动过程2

接上一篇: Openstack liberty源码分析 之 云主机的启动过程1 nova-conductor nova-api通过rpc发送启动云主机请求后,nova-conductor会收到该请求,根据路由映射,该请求会递交给 nova/conductor/manager.py.ComputeTaskManager.build_instances处理,如下(函数说明见注释): def build_instances(self, context, instances, image, filter

Node.js中的模块机制

本文为读书笔记. 一.CommonJS的模块规范 Node与浏览器以及 W3C组织.CommonJS组织.ECMAScript之间的关系 Node借鉴CommonJS的Modules规范实现了一套模块系统,所以先来看看CommonJS的模块规范. CommonJS对模块的定义十分简单,主要分为模块引用.模块定义和模块标识3个部分. 1. 模块引用 模块引用的示例代码如下: var math = require('math'); 在CommonJS规范中,存在require()方法,这个方法接受模