Python中logging模块

1、日志级别

日志级别

数值

Critical

50

Error

40

Warning

30

Info

20

Debug

10

Notset

0

 

日志级别指的是产生日志的事件的严重程度。

设置一个级别后,严重程度第一设置值得日志消息将被忽略。

Debug(),info(),warning(),error(),critical()方法;

2、格式字符串

属性

格式

描述

日志消息内容

%(message)s

The logged message,computed as msg %args,当调用 formatter.format()时候会被调用

Asctime

%(asctime)s

创建logrecord的可读时间,默认情况下,格式为2003-07-08 00:00:00,000(逗号后面的数字是毫秒部分的时间)

函数名

%(funcname)s

日志调用所在的函数名

日志级别名称

%(levelname)s

消息的级别名称‘debug,info,warning,error,critical’

日志级别数值

%(levelno)s

消息的级别数字,debug,info,warning,error,critical

行号

%(lineno)s

日志调用所在的源码行号

模块

%(module)s

模块(费了那么的名字部分)

进程ID

%(process)s

进程ID

线程ID

%(thread)d

线程ID

进程名

%(processname)s

进程名

线程名

%(threadname)s

线程名称

 

funName、threadName、processName都是小驼峰。

 

 

 

 

import logging

FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT)

logging.info('{}'.format(20))  #info不显示
logging.warning('{}'.format(20)) #默认级别的

 

2018-06-13 11:01:56,992         Thread info:420 MainThread 20

上栗info不显示的原因是因为logging.basicConfig(format=FORMAT)  后面的默认值level的值是logging.WARNING 低于此级别的不进行显示处理。

 

改造以后

import logging

FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.DEBUG)


logging.info('1{}'.format(0))  #info不显示
logging.warning('2{}'.format(0)) #默认级别的
logging.debug('3{}'.format(0))
logging.error('4{}'.format(0))
logging.critical('5{}'.format(0))

 

2018-06-13 11:39:28,053         Thread info:6212 MainThread 10

2018-06-13 11:39:28,053         Thread info:6212 MainThread 20

2018-06-13 11:39:28,053         Thread info:6212 MainThread 30

2018-06-13 11:39:28,053         Thread info:6212 MainThread 40

2018-06-13 11:39:28,053         Thread info:6212 MainThread 50

 

格式化字符串是需要定义的。Schools自定义的。打印输出的时候利用extra显示定义的新定义的消息等。

import logging

FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s %(school)s'
logging.basicConfig(format=FORMAT,level=logging.INFO)


d = {'school':'baidu.com'}
logging.info('i am %s %s',20,'years old.',extra = d)
logging.warning('i am %s %s',20,'years old.',extra = d)

 

2018-06-13 14:57:40,631         Thread info:8908 MainThread i am 20 years old. baidu.com

2018-06-13 14:57:40,631         Thread info:8908 MainThread i am 20 years old. baidu.com

3、修改日期格式

 

import logging

logging.basicConfig(format='%(asctime)s %(message)s',datefmt='%Y/%m/%d %I:%M:%S')
logging.warning('this event was logged')

 

2018/06/13 03:04:38 this event was logged

可以自己定义时间的格式,利用datefmt=新的时间格式即可以。

 

 

4、输出到文件

 

import logging
logging.basicConfig(format='%(asctime)s %(message)s',filename='test1.log')
for _ in range(5):
    logging.warning('this is event logged')

 

还可以输出日志到文件,只是需要filename指定文件存放地址

 

5、Logger类:

Loggin模块加载的时候,会创建一个root logger,跟logger对象的默认级别是WARNING,调用logging.basicConfig来调整级别,就是对这个跟logger的级别进行修改。

1)构造

Logging.getlogger([name=None])

使用工厂方法返回一个logger实例。

指定name,返回一个名称为name的logger的实例,如果再次使用相同的名字,就是实例化一个对象,未指定none,返回根logger实例。

2)层次结构

Logger是层次结构的,使用.点号分割,如a,a.b或者a.b.c.d,a是a.d的父parent,a.b是a的子child,对于foo来说,名字为foo.bar/foo.bar.bar/foo.bam都是foo的后代。

 

import logging

root = logging.getLogger()
print(root.name,type(root),root.parent,id(root))


logger = logging.getLogger(__name__)
print(logger.name,type(logger),id(logger.parent),id(logger))



loggerchild = logging.getLogger(__name__+'.child')
print(loggerchild.name,type(loggerchild),id(loggerchild.parent),id(loggerchild))

 

root <class 'logging.RootLogger'> None 283120699768

__main__ <class 'logging.Logger'> 283120699768 283118806968

__main__.child <class 'logging.Logger'> 283118806968 283118808872

 

3)level级别设置

 

import logging

FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.DEBUG)

logger = logging.getLogger(__name__)
print(logger.name,type(logger))
print(logger.getEffectiveLevel())

logger.info('hello')
logger.setLevel(28)

print(logger.getEffectiveLevel())
logger.info('hello2')
logger.warning('hello3 warning')

root = logging.getLogger()
root.info('hello4 info root')

 

2018-06-13 15:49:51,076         Thread info:8952 MainThread hello

__main__ <class 'logging.Logger'>

2018-06-13 15:49:51,076         Thread info:8952 MainThread hello3 warning

10

2018-06-13 15:49:51,076         Thread info:8952 MainThread hello4 info root

28

每一个logger创建后,都有一个等效的level。

Logger对象可以在创建后动态的修改自己的level。

 

 

 

 

不指定的话就是标准错误输出。

 

6、handler

Handler:主要工作的。

Handler控制日志信息的输出的目的地,可以是控制台、文件。

可以单独设置level   Handler都有独立的level。

可以单独设置格式

可以设置过滤器

 

Handler类继承。

Handler

Streamhandler不指定使用sys.stderr

filehandler文件

_stderrhandler 标准输出

Nullhandler 什么都不做

 

输出打印全部靠的是handler,真正干活的也是handler。

 

if handlers is None:
    filename = kwargs.pop("filename", None)
    mode = kwargs.pop("filemode", 'a')
    if filename:
        h = FileHandler(filename, mode)
    else:
        stream = kwargs.pop("stream", None)
        h = StreamHandler(stream)
    handlers = [h]

 

如果设置文件名,则根logger加一个输出到文件handler;如果没有设置文件名,则为根logger加一个streamhandler,默认输出到sys.stderr

也就是说,根logger一定会至少有一个handler。

import logging


FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.DEBUG)


logger = logging.getLogger('test')
print(logger.name,type(logger))
logging.info('line 1')

handler = logging.FileHandler('ll.log','w')
logger.addHandler(handler)

logger.info('line 2')

 

文件内的内容为line 2  控制台打印输出的内容为line1和line2,原因是因为设置的等级问题,没指定在控制台输出是因为继承的root的类,输出在控制台中。

 

 

7、日志流

Level的继承

import logging

FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.INFO)
root = logging.getLogger()

log1 = logging.getLogger('s')
log1.setLevel(logging.INFO)

log2 = logging.getLogger('s.s1')
log2.warning('log2 warning')

 

2018-06-13 16:37:50,650         Thread info:8464 MainThread log2 warning

logger实例,如果设置了level,就用它和信息的级别比较,否则,继承最近的祖先的level。

 

继承关系及信息传递:

每一个logger实例的level如同入口。让水流进来,如果门槛太高,信息就无法进入,例如log3.warning(‘log3’),如果log3定义的级别高,就不会有信息通过log3

如果level没有设置,就用父logger的,如果父logger的level没有设置,继续找父的父,最终找到root上面,如果设置了就用他的,如果root没有设置,root的默认值是WARNING,

 

消息传递流程:

1)、如果消息在某个logger对象上产生,这个logger就是当前的logger,首先消息level要和当前的logger的effective比较,如果第一当前的logger的effectivelevel,则流程结束。

2)、日志记录会交给当前logger的所有handler处理,记录还要和每一个handler的级别分别比较,低的不处理,否则按照handler输出日志记录。

3)、当前logger的所有handler处理完后,就要看自己的propagate属性,如果是True表示向父logger传达这个日志,否则到此结束流程。

4)、如果日志记录仪传递到了父logger,不需要和logger的level比较,而是直接交给父的所有handler,父logger成为当前的logger,重复2,3步骤,直到当前的父logger是None退出,也就是说当前logger最后一般是root logger(是否能到root logger更看中间的logger是否允许propagate)。

 

Logger实话初始化的propagate属性为True,即允许向父logger传递消息。

Logger.basicConfig

如果root没有handler,就默认创建一个streamhandler,如果设置了filename,就创建一个filehandler,如果设置了format参数,就会用它生成一个formatter对象,并把这个formatter加入到刚刚创建的handler上,然后把这些handler加入到root.handlers列表上,level是设置给root.logger的

如果root.handlers 列表不能为空,loggingbasicConfig的调用什么都不做。

 

 

import logging


logging.basicConfig(format='%(name)s %(asctime)s %(message)s ',level=logging.INFO)


root = logging.getLogger()
root.setLevel(logging.ERROR)
print('root',root.handlers)
h0 = logging.StreamHandler()
h0.setLevel(logging.WARNING)
root.addHandler(h0)
print('root',root.handlers)
for h in root.handlers:
    print('root handler = {},formatter={}'.format(h,h.formatter))

log1 = logging.getLogger('s')
log1.setLevel(logging.ERROR)
h1 = logging.FileHandler('h1.log')
h1.setLevel(logging.WARNING)
log1.addHandler(h1)
print('log1',log1.handlers)


log2 = logging.getLogger('s.s1')
log2.setLevel(logging.CRITICAL)
h2 = logging.FileHandler('h2.log')
h2.setLevel(logging.WARNING)
log2.addHandler(h2)
print('log2',log2.handlers)

log3 = logging.getLogger('s.s1.s2')
log3.setLevel(logging.INFO)
print(log3.getEffectiveLevel())
log3.warning(log3)
print('log3',log3.handlers)

 

 

root [<logging.StreamHandler object at 0x00000088203E9748>]

root [<logging.StreamHandler object at 0x00000088203E9748>, <logging.StreamHandler object at 0x00000088203FE5F8>]

root handler = <logging.StreamHandler object at 0x00000088203E9748>,formatter=<logging.Formatter object at 0x00000088203E9780>

root handler = <logging.StreamHandler object at 0x00000088203FE5F8>,formatter=None

log1 [<logging.FileHandler object at 0x0000008820E2DDA0>]

log2 [<logging.FileHandler object at 0x0000008820E2DF28>]

20

log3 []

s.s1.s2 2018-06-13 17:17:43,695 <logging.Logger object at 0x0000008820E2DF60>

<logging.Logger object at 0x0000008820E2DF60>

 

 

8、Formatter

Logging的formatter类,允许指定某个格式的字符串,如果提供None,name%(message)s将会作为默认值。

import logging


logging.basicConfig(format='%(name)s %(asctime)s %(message)s ',level=logging.INFO)


root = logging.getLogger()
root.setLevel(logging.ERROR)
print('root',root.handlers)
h0 = logging.StreamHandler()
h0.setLevel(logging.WARNING)
root.addHandler(h0)
print('root',root.handlers)
for h in root.handlers:
    print('root handler = {},formatter={}'.format(h,h.formatter))

log1 = logging.getLogger('s')
log1.setLevel(logging.ERROR)
h1 = logging.FileHandler('h1.log')
h1.setLevel(logging.WARNING)
log1.addHandler(h1)
print('log1',log1.handlers)


log2 = logging.getLogger('s.s1')
log2.setLevel(logging.CRITICAL)
h2 = logging.FileHandler('h2.log')
h2.setLevel(logging.WARNING)
log2.addHandler(h2)
print('log2',log2.handlers)
f2 = logging.Formatter('log2 %(name)s %(asctime)s %(message)s')
h2.setFormatter(f2)
print('log2 formatter',h2.formatter)
log2.addHandler(h2)
print('log2',log2.handlers)

log3 = logging.getLogger('s.s1.s2')
log3.setLevel(logging.INFO)
print(log3.getEffectiveLevel())
log3.warning(log3)
print('log3',log3.handlers)

 

 

 

s.s1.s2 2018-06-13 17:24:13,392 <logging.Logger object at 0x00000033721EF208>

root [<logging.StreamHandler object at 0x0000003372019780>]

<logging.Logger object at 0x00000033721EF208>

root [<logging.StreamHandler object at 0x0000003372019780>, <logging.StreamHandler object at 0x0000003372130710>]

root handler = <logging.StreamHandler object at 0x0000003372019780>,formatter=<logging.Formatter object at 0x00000033720197B8>

root handler = <logging.StreamHandler object at 0x0000003372130710>,formatter=None

log1 [<logging.FileHandler object at 0x00000033721DDEB8>]

log2 [<logging.FileHandler object at 0x00000033721EF080>]

log2 formatter <logging.Formatter object at 0x00000033721EF1D0>

log2 [<logging.FileHandler object at 0x00000033721EF080>]

20

log3 []

 

 

9、filter是过滤

可以为handler增加过滤器,所哟这种过滤器只是影响某一个handler,不会影响整个处理流程,但是,如果过滤器增加到logger上,就会影响整个流程。

 

import logging


FORMAT = '%(asctime)-15s\tThread info:%(thread)d %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.DEBUG)

log1 = logging.getLogger('s')
log1.setLevel(logging.WARNING)

h1 = logging.StreamHandler()
h1.setLevel(logging.INFO)
fmt1 = logging.Formatter('log1-h1 %(message)s')
h1.setFormatter(fmt1)
log1.addHandler(h1)

log2 = logging.getLogger('s.s1')
print(log2.getEffectiveLevel())

h2 = logging.StreamHandler()
h2.setLevel(logging.INFO)

fmt2 = logging.Formatter('log2-h2 %(message)s')
h2.setFormatter(fmt2)

f2 = logging.Filter('s')
h2.addFilter(f2)

log2.addFilter(h2)

log2.warning('log2 waring ')

 

 

30

log1-h1 log2 waring

2018-06-13 17:36:59,798         Thread info:8360 MainThread log2 waring

消息log2的,他的名字是s.s1,所以过滤器的名字设置为s或者s.s1,消息就可以通过,但是如果使其他的就不能通过,不设置过滤器的名字,所以消息通过。

 

总结:过滤器的核心就一句,在logging.filter类的filter方法中

Record.namem.find(self.name,0,self.nlen) != 0

本质上是等价于record.name.startswith(filter.name)

posted @ 2018-11-12 23:26  Python爱好者666  阅读(349)  评论(0编辑  收藏  举报