python3 log_python3_Logging模块详解

Logger 记录器

Logger是一个树形层级结构,在使用接口debug,info,warn,error,critical之前必须创建Logger实例

创建方法: logger = logging.getLogger(logger_name)

Handler 处理器

Handler处理器类型有很多种,比较常用的有三个,StreamHandler,FileHandler,NullHandler,详情可以访问Python logging.handlers

创建StreamHandler之后,可以通过使用以下方法设置日志级别,设置格式化器Formatter,增加或删除过滤器Filter。

创建方法: sh = logging.StreamHandler(stream=None)

FileHandler

创建方法: fh = logging.FileHandler(filename, mode='a', encoding=None, delay=False)

Formatter 格式化器

使用Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S。

创建方法: formatter = logging.Formatter(fmt=None, datefmt=None)

其中,fmt是消息的格式化字符串,datefmt是日期字符串。如果不指明fmt,将使用'%(message)s'。如果不指明datefmt,将使用ISO8601日期格式。

有用的format格式

格式描述

%(levelno)s

打印日志级别的数值

%(levelname)s

打印日志级别名称

%(pathname)s

打印当前执行程序的路径

%(filename)s

打印当前执行程序名称

%(funcName)s

打印日志的当前函数

%(lineno)d

打印日志的当前行号

%(asctime)s

打印日志的时间

%(thread)d

打印线程id

%(threadName)s

打印线程名称

%(process)d

打印进程ID

%(message)s

打印日志信息

Filter 过滤器

Handlers和Loggers可以使用Filters来完成比级别更复杂的过滤。Filter基类只允许特定Logger层次以下的事件。例如用‘A.B’初始化的Filter允许Logger ‘A.B’, ‘A.B.C’, ‘A.B.C.D’, ‘A.B.D’等记录的事件,logger‘A.BB’, ‘B.A.B’ 等就不行。 如果用空字符串来初始化,所有的事件都接受。

创建方法: filter = logging.Filter(name='')

配置文件格式说明

%(name)s Logger的名字%(levelname)s 文本形式的日志级别%(message)s 用户输出的消息%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒%(levelno)s 数字形式的日志级别%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有%(filename)s 调用日志输出函数的模块的文件名%(module)s 调用日志输出函数的模块名%(funcName)s 调用日志输出函数的函数名%(lineno)d 调用日志输出函数的语句所在的代码行%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示%(relativeCreated)d 输出日志信息时来自Logger创建的毫秒数%(thread)d 线程ID。可能没有%(threadName)s 线程名。可能没有%(process)d 进程ID。可能没有

实例代码:

1、在调试窗口上只打出error以上级别的日志,但是在日志中打出debug以上的信息

1 importlogging2

3 logger = logging.getLogger("simple_example")4 logger.setLevel(logging.DEBUG)5

6 #建立一个filehandler来把日志记录在文件里,级别为debug以上

7 fh = logging.FileHandler("spam.log")8 fh.setLevel(logging.DEBUG)9

10 #建立一个streamhandler来把日志打在CMD窗口上,级别为error以上

11 ch =logging.StreamHandler()12 ch.setLevel(logging.ERROR)13

14 #设置日志格式

15 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")16 ch.setFormatter(formatter)17 fh.setFormatter(formatter)18

19 #将相应的handler添加在logger对象中

20 logger.addHandler(ch)21 logger.addHandler(fh)22

23 #开始打日志

24 logger.debug("debug message")25 logger.info("info message")26 logger.warn("warn message")27 logger.error("error message")28 logger.critical("critical message")

将Logging封装成一个类

这样每次使用的时候,只要实例化一个对象就可以了

1 #! /usr/bin/python3

2

3 importlogging4

5

6 classLogger:7 def __init__(self, path, clevel=logging.DEBUG, Flevel=logging.DEBUG):8 self.logger =logging.getLogger(path)9 self.logger.setLevel(logging.DEBUG)10 fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')11

12 #设置CMD日志

13 sh =logging.StreamHandler()14 sh.setFormatter(fmt)15 sh.setLevel(clevel)16

17 #设置文件日志

18 fh =logging.FileHandler(path)19 fh.setFormatter(fmt)20 fh.setLevel(Flevel)21 self.logger.addHandler(sh)22 self.logger.addHandler(fh)23

24 defdebug(self, message):25 self.logger.debug(message)26

27 definfo(self, message):28 self.logger.info(message)29

30 defwar(self, message):31 self.logger.warn(message)32

33 deferror(self, message):34 self.logger.error(message)35

36 defcri(self, message):37 self.logger.critical(message)38

39

40 if __name__ == '__main__':41 logyyx = Logger('yyx.log', logging.ERROR, logging.DEBUG)42 logyyx.debug('一个debug信息')43 logyyx.info('一个info信息')44 logyyx.war('一个warning信息')45 logyyx.error('一个error信息')46 logyyx.cri('一个致命critical信息')

调试运行结果:

/usr/bin/python3.5 /home/rxf/python3_1000/1000/python3_server/logging封装/封装为一个类.py

[2017-11-07 10:25:50] [ERROR] 一个error信息

[2017-11-07 10:25:50] [CRITICAL] 一个致命critical信息

日志文件内的内容:

[2017-11-07 10:25:50] [DEBUG] 一个debug信息

[2017-11-07 10:25:50] [INFO] 一个info信息

[2017-11-07 10:25:50] [WARNING] 一个warning信息

[2017-11-07 10:25:50] [ERROR] 一个error信息

[2017-11-07 10:25:50] [CRITICAL] 一个致命critical信息

多模块使用logging

logging模块保证在同一个python解释器内,多次调用logging.getLogger('log_name')都会返回同一个logger实例,即使是在多个模块的情况下。所以典型的多模块场景下使用logging的方式是在main模块中配置logging,这个配置会作用于多个的子模块,然后在其他模块中直接通过getLogger获取Logger对象即可。

logging.conf:

[loggers]

keys=root,main

[handlers]

keys=consoleHandler,fileHandler

[formatters]

keys=fmt

[logger_root]

level=DEBUG

handlers=consoleHandler

[logger_main]

level=DEBUG

qualname=main

handlers=fileHandler

[handler_consoleHandler]class=StreamHandler

level=DEBUG

formatter=fmt

args=(sys.stdout,)

[handler_fileHandler]class=logging.handlers.RotatingFileHandler

level=DEBUG

formatter=fmt

args=('tst.log','a',20000,5,)

[formatter_fmt]

format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

datefmt=

主模块main.py

1 importlogging2 importlogging.config3 importmod4

5 logging.config.fileConfig('logging.conf')6 root_logger = logging.getLogger('root')7 root_logger.debug('test root logger...')8

9 logger = logging.getLogger('main')10 logger.info('test main logger')11 logger.info('start import module \'mod\'...')12

13

14 logger.debug('let\'s test mod.testLogger()')15 mod.testLogger()16

17 root_logger.info('finish test...')

子模块mod.py

importloggingimportsubmod

logger= logging.getLogger('main.mod')

logger.info('logger of mod say something...')deftestLogger():

logger.debug('this is mod.testLogger...')

submod.tst()

子子模块submod.py:

importlogging

logger= logging.getLogger('main.mod.submod')

logger.info('logger of submod say something...')deftst():

logger.info('this is submod.tst()...')

然后运行python main.py,控制台输出:

/usr/bin/python3.5 /home/rxf/python3_1000/1000/python3_server/logging封装/main.py2017-11-07 10:53:49,228 - root - DEBUG -test root logger...2017-11-07 10:53:49,228 - main - INFO -test main logger2017-11-07 10:53:49,228 - main - INFO - start import module 'mod'...2017-11-07 10:53:49,229 - main - DEBUG - let's test mod.testLogger()

2017-11-07 10:53:49,229 - main.mod - DEBUG - this ismod.testLogger...2017-11-07 10:53:49,229 - main.mod.submod - INFO - this issubmod.tst()...2017-11-07 10:53:49,229 - root - INFO - finish test...

再看一下tst.log,logger配置中的输出的目的地:

2017-11-07 10:56:54,189 - main - INFO -test main logger2017-11-07 10:56:54,189 - main - INFO - start import module 'mod'...2017-11-07 10:56:54,189 - main - DEBUG - let's test mod.testLogger()

2017-11-07 10:56:54,189 - main.mod - DEBUG - this ismod.testLogger...2017-11-07 10:56:54,190 - main.mod.submod - INFO - this is submod.tst()...

tst.log中没有root logger输出的信息,因为logging.conf中配置了只有main logger及其子logger使用RotatingFileHandler,而root logger是输出到标准输出。

学习思考思路参考:

Logging工作流程

logging模块使用过程

第一次导入logging模块或使用reload函数重新导入logging模块,logging模块中的代码将被执行,这个过程中将产生logging日志系统的默认配置。

自定义配置(可选)。logging标准模块支持三种配置方式: dictConfig,fileConfig,listen。其中,dictConfig是通过一个字典进行配置Logger,Handler,Filter,Formatter;fileConfig则是通过一个文件进行配置;而listen则监听一个网络端口,通过接收网络数据来进行配置。当然,除了以上集体化配置外,也可以直接调用Logger,Handler等对象中的方法在代码中来显式配置。

使用logging模块的全局作用域中的getLogger函数来得到一个Logger对象实例(其参数即是一个字符串,表示Logger对象实例的名字,即通过该名字来得到相应的Logger对象实例)。

使用Logger对象中的debug,info,error,warn,critical等方法记录日志信息。

logging模块处理流程

logging_flow.png

判断日志的等级是否大于Logger对象的等级,如果大于,则往下执行,否则,流程结束。

产生日志。第一步,判断是否有异常,如果有,则添加异常信息。第二步,处理日志记录方法(如debug,info等)中的占位符,即一般的字符串格式化处理。

使用注册到Logger对象中的Filters进行过滤。如果有多个过滤器,则依次过滤;只要有一个过滤器返回假,则过滤结束,且该日志信息将丢弃,不再处理,而处理流程也至此结束。否则,处理流程往下执行。

在当前Logger对象中查找Handlers,如果找不到任何Handler,则往上到该Logger对象的父Logger中查找;如果找到一个或多个Handler,则依次用Handler来处理日志信息。但在每个Handler处理日志信息过程中,会首先判断日志信息的等级是否大于该Handler的等级,如果大于,则往下执行(由Logger对象进入Handler对象中),否则,处理流程结束。

执行Handler对象中的filter方法,该方法会依次执行注册到该Handler对象中的Filter。如果有一个Filter判断该日志信息为假,则此后的所有Filter都不再执行,而直接将该日志信息丢弃,处理流程结束。

使用Formatter类格式化最终的输出结果。 注:Formatter同上述第2步的字符串格式化不同,它会添加额外的信息,比如日志产生的时间,产生日志的源代码所在的源文件的路径等等。

真正地输出日志信息(到网络,文件,终端,邮件等)。至于输出到哪个目的地,由Handler的种类来决定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值