• 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;

  • 相关阅读:
    JavaScript语言和jQuery技术1
    JSP2
    JavaScript语言和jQuery技术2
    MYSQL2
    JSP1
    JSP5
    JSP3
    Spring框架
    JSP4
    MYSQL3(查询)
  • 原文地址:https://www.cnblogs.com/yuhan-TB/p/4052598.html
Copyright © 2020-2023  润新知