Python 日志组件学习(一)

来源:互联网 发布:上海行知教育教学网点 编辑:程序博客网 时间:2024/06/01 18:57

Python log组件

主要 对以下python日志组件分析说明.
[TOC]

  • logging
  • twisted.python.log
  • twisted.logger

    python 日志的官方说明文档比较简单,一般使用没什么问题,不过了解一些基本的原理,可能在一些复杂的项目里使用起来比较方便一些

logging

logging 是python 标准的日志组件

使用:

import logging  logging.baseConfig()tag = 'test'  # 标签mylogger = logging.getLogger(tag) # 创建一个Logger类对象mylogger.info('This is a test msg') # 调用日志打印

原理:

logging.baseConfig() 设置配置参数,默认情况下会向root添加一个StreamHandler对象(一会再说root和Handler),
并且这个StreamHandler对象的stream属性为sys.stderr

当调用mylogger.info时做了哪些事情呢?不管是mylogger.info, mylogger.error,还是mylogger.log方法,都是调用了内部的_log方法,却别在于,日志的级别不同,当级别大于等于在logging.baseConfig()设置打印的级别时,_log方法将会被调用。

下面是重点了,以mylogger为例子(它是一个Logger对象),它有一个属性Handlers 列表,默认情况下是是个空列表,调用_log方法时,会触发Handlers 列表中的所有handle ,调用完这些handle 之后,还会去遍历mylogger.parent的Handlers (可以通过设置Logger的propagate=False,来禁止parent的handle被调用),默认情况下parten = root ,root 实际上也是一个Logger实例。

比如一个默认的StreamHandler对象s_handle,当s_handle被触发的时候,s_handle.stream.write(xxx)将被调用,前面说了,默认这个stream = sys.stderr, 意思就是这个handle会将信息打印到屏幕上。

如果你想让你的日志对象,做一些你希望的操作,可以自定义handle,将handle添加到mylogger的Handlers列表中,
在下面的例子中,添加了一个fluent的handle到mylogger(fluent可以将日志接到Kibana网页中显示)

line_format = {        'file_name': '%(module)s',        'log_level': '%(levelname)s',        'line': '%(lineno)d',        'server': '测试区'    }    l = logging.getLogger(log_name)    h = handler.FluentHandler(log_name, host='192.168.7.99', port=54224) # 创建一个fluent handle    formatter = handler.FluentRecordFormatter(line_format) # 创建fluent handle信息格式对象    h.setFormatter(formatter) # 将信息格式对象添加到handle    l.setLevel(logging.INFO)    l.addHandler(h) # 将handle 添加到l的Handlers列表里

总结:

python logging组件核心就是调用handle

twisted.python.log

这是twisted组件里的log模块

使用:

简单的用法如下面的例子

from twisted.python import loglog.msg('This is a test msg') # log普通信息# 或者log.err('This is a test err') # log错误级别的信息

原理:

(log.err 实际上就是将日志级别定义成ERROR后调用log.msg)

twisted组件里的log模块主要有个LogPublisher(分发者),姑且就叫它分发器吧。

当log.msg被调用的时候,会抛出一个log事件(实际上就是定义一个eventDict事件字典)给LogPublisher,接着LogPublisher会将这个log事件发送给所有observer(观察者)

LogPublisher(分发器)的_publishPublisher属性是一个绑定了ILogObserver接口类的类(也就是一个观察者)(听着有点拗口…),ILogObserver里面暴露了call方法,log.msg将log事件抛给 LogPublisher (分发器),在由分发器的 _publishPublisher属性的call方法里遍历了所有其他的observer, 是不是感觉似曾相识,twisted python log里的observer 和 python 标准库log的handle有异曲同工之处啊。

下面的例子,自定义了一个observer,并将这个observer添加到 LogPublisher 的Observers列表里

from twisted.python import logclass loogoo():    # 自定义观察者    implements(log.ILogObserver)    def __init__(self, path):        self.file = file(path, "a+")    def __call__(self, event):        text = formatEvent(event)        self.file.write(text + '\n')        self.file.flush()if __name__ == '__main__':    log.addObserver(loogoo('app.log')) # 添加观察者    log.startLogging(sys.stdout)

我感觉这里不用log.startLogging(sys.stdout)也是可以的, 那么log.startLogging(sys.stdout)有什么用呢?
我感觉主要做了2件事情:
第一,以sys.stdout作为file创建了一个observer加入到分发器,那么log日志就会被打印到屏幕上。
第二,log.startLogging(sys.stdout) 实际等于 log.startLogging(sys.stdout, setStdout=1),setStdout参数为真的情况下,sys.stdout 和 sys.stderr 会被重定向为 twisted.logger._io.LoggingFile对象,这个对象的write方法里面正是调用了log.msg,这就意味着,之后有调用到sys标准输出和标准错误,这个信息都会被LogPublisher(分发者)捕获到。
另外如果setStdout=0 或者False, sys.stdout 和 sys.stderr都不会被重定向
综合上面几点,可以看出twisted.python.log 模块仅仅只是能捕获自身抛出的log事件,如果要捕获 python logging 抛出的log信息, 那么log.startLogging(sys.stdout)就可以,因为默认情况下,python logging parent有执行sys.stderr的handle

twisted.logger

现在去查看twisted.python.log的文档就可以发现There is now a new logging system in Twisted ,正是twisted.logger,这两者其实没有什么却别,twisted.python.log是在twisted.logger的基础上又封装了一层

0 0
原创粉丝点击