标签:.com ctime 过滤 roc 查询 log span 常用 htm
Python在日志记录处理上是非常灵活的,且功能完备,足以满足所有对日志方面的需求。
如此强大,当然是日志系统设计非常的流弊了。
除此之外,了解其设计时,要梳理清楚模块中几个重要对象之间的关系,和他们各自负责的Mission任务!
可以参考JAVA的日志系统设计,这篇文章采用幽默诙谐的语言基调,从需求出发,阐明日志系统是怎么设计出来的。
我这里按照这篇文章,简单勾画下重点
这样根据需求围绕核心几个类的关系
Logger包含Handler,Handler包含Formatter。都处理LogRecord。Logger和Handler都可以添加Filter对LogRecord进行过滤。
1.就是通过logger的名字的命名层级来查找其parent logger。使用‘.‘来表示继承关系。
2.logger的继承其实是继承几个方面
2.1. level的继承:子logger写日志的时候,优先使用本身设置的level,如果没有设置,则逐层向上级父logger查询,直到查询到为止。最极端的情况是,使用rootlogger的默认日志级别——WARNING.可以使用logger.getEffectivaLeve()获取有效的等级。
2.2. handler的继承,先将日志对象传递给子logger的所有handler处理,处理完毕,如果孩子的logger的propagate属性设置的是1(TRUE),那么日志record对象会被传播给上级父logger,该父logger的handler都会进行处理,如果父logger的propagate也是1,那么会继续向上。如果子logger的propagate就是0,就不会传播,极端,如果是子logger都没有handler,且不传播,那么就会极端的给logging.lastResort这是一个内置的handler,不会和任何一个logger关联,and acts like StreamHandler which the event description message to the current value of sys.stderr.这个logging.lastResort是没有formatted的,所以我们会看到就message原始格式,输出到标准输出中。
3. 总的来说,其实是逻辑上的继承,只是利用层级关系,可以来使用父logger的level和handler。
logger的构建是通过logger的命名创建出的。名字在整个程序中都是唯一的表示。
这样说的设计就可以实现将你自己的日志和使用第三方模块所产生的日志结合在一起。不用在自己的代码中去刻意再写兼容第三方模块产生的日志的处理。都交给logging就可以整合处理了。
Logger 间继承关系的表示:
该模块级函数是设置root logger.如果root logger已经有handler的化,那么调用函数是没有作用的,以下是源码:
def basicConfig(**kwargs):
_acquireLock()
try:
if len(root.handlers) == 0:
filename = kwargs.get("filename")
if filename:
mode = kwargs.get("filemode", ‘a‘)
hdlr = FileHandler(filename, mode)
else:
stream = kwargs.get("stream")
hdlr = StreamHandler(stream)
fs = kwargs.get("format", BASIC_FORMAT)
dfs = kwargs.get("datefmt", None)
fmt = Formatter(fs, dfs)
hdlr.setFormatter(fmt)
root.addHandler(hdlr)
level = kwargs.get("level")
if level is not None:
root.setLevel(level)
finally:
_releaseLock()
- Loggers are never instantiated directly,but always through the module-level function logging.getLogger(name).
- logger对象不能直接通过Logger类实例,都是通过模块级函数logging.getLogger(name)调用产生的。
- Mutiple calls to getLogger() with the same name will always return a refernece to the same Logger object.
方法 | 用法 | 注释 |
---|---|---|
logger.info() | ||
logger.debug() | ||
logger.setLevel | ||
logger.getEffectiveLevel() | ||
logger.getChild(suffix) | 返回一个子logger,子logger的名字会是父logger名字加上suffix | |
logger.addFilter(filt) | ||
logger.removeFilter(filt) | ||
logger.addHandler(hd) | ||
logger.removeHandler(hd) |
Handler是一个基础类,其它不同类型的handler都是继承于它。同样,handler也不会直接实例化对象,而是使用它的子类。
常用类型Handler
Handler | 所在模块 | 注释 |
---|---|---|
StreamHandler | logging | |
FileHandler | logging | |
NullHandler | loggging | |
BaseRotatingHandler | logging.handlers | |
RotatingFileHandler | logging.handlers | |
TimedRotatingFileHandler | logging.handlers | |
SocketHandler | logging.handlers |
等等。。。
Handler常用方法:
该类对象是用于对LogRecord进行格式化处理的。
Formtter对象的初始化需要指定日志字符串格式,还可以指定时间格式,和格式化字符串使用的风格。
Fomatter对象是添加到Handler对象中的。
Filter对象初始化需要指定过滤logger名,只有指定的logger名所产生的LogRecord才会通过该filter,不然会被它过滤掉。logger名过滤是指不会过滤指定logger名及其子logger。
日志内容的载体。
LogRecord的实例都是通过Logger对象的方法实例的
LogRecord的主要分类就是在日志级别上的分类,分为DEBUG,INFO,WARNING,ERROR,CRITICAL
import logging
logging.basicConfig(filename=‘logging_train.log‘,level=logging.DEBUG)
logger1 = logging.getLogger(‘1‘)
logger2 = logger1.getChild(‘2‘) # logger2继承于logger1:即会是1.2
logger2.propagate = True # 是否向上传递LogRecord对象
class myfilter(logging.Filter): # 定义自己的Filter类
def __init__(self, s): # 过滤所有不包含指定字符串的日志
self.filter_string = s
def filter(self, red): # logger和handler会调用这个方法判定过滤结果。
if self.filter_string in red.getMessage():
return True
else:
return False
filter1 = myfilter(‘world‘)
handler1 = logging.FileHandler(‘logging_train1.log‘)
handler2 = logging.StreamHandler()
formatter1 = logging.Formatter(‘%(asctime)s %(name)s %(threadName)s %(process)s %(levelname)s %(message)s‘)
handler2.setFormatter(formatter1)
logger1.addHandler(handler1)
logger2.addHandler(handler2)
logger2.addFilter(filter1)
logger2.setLevel(logging.CRITICAL)
logger2.error("hello world!")
logger2.critical("Python is the best all over the world!")
标签:.com ctime 过滤 roc 查询 log span 常用 htm
原文地址:https://www.cnblogs.com/ZJiQi/p/8966865.html