昨天看了同事的代码中用这个管理日志,作为一个小菜鸟我不得不去学习下这个模块logging,官方文档讲解的非常详细,但是无语的是没有中文版,看起来非常的吃力啊。于是我决定写下来便于理解学习。

Logging模块是用来管理日志打印,其拥有很好的线程安全性,使用非常方便,但是其不能用于多进程的模型中,网上有厉害的人改写了Logging 的代码保证其进程安全,我把地址贴出来Logging保证多进程模型中的代码安全性。同时有的时候错误的使用,会导致日志的重复打印等麻烦问题。

开始具体介绍下这个模块:

官网上讲Logging模块分为了四个部分详细讲解:

1.Loggers expose the interface that application code directly uses.

2.Handlers send the log records (created by loggers) to the appropriate destination.

3.Filters provide a finer grained facility for determining which log records to output.

4.Formatters specify the layout of log records in the final output.

其中:

1.Logger 实例化后可以用来打印日志信息。

2.Handler 用来设置日志的输出目的地,(在文件中输出时,可以设置

RotatingFileHandler来让日志文件的大小达到指定值时进行文件切分)

3.Filter 控制日志的输出等级,当达到指定等级的文件才能进行输出。

4.Formatter用来控制日志的输出格式。

实战出真理:

#coding:utf-8
import sys
import logging
if __name__=="__main__":
#通过getLogger接口创建实例化的日志打印对象
logger = logging.getLogger('rrswd')
#接下来对其进行配置
#formatter确定日至的输出格式
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(message)s')
#Handler采用了StreamHandler 输出到stdout中 将日志输出格式和等级配置到console_handler中
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter
console_handler.level = logging.DEBUG
#将console_handler添加到logger对象中,就可以按你配置的进行日志打印
logger.addHandler(console_handler)
logger.info('info information')
logger.warn('warn information')
logger.debug('debug information')
#同时可以配置多个Handler给一个对象
file_handler = logging.FileHandler('logger.log')
file_handler.formatter = formatter
file_handler.level = logging.DEBUG
#配置了文件输出handler后日志会将接下来的数据输入到文件logger.log中,因为之前console_handler的原因,还会在终端上输出一份
logger.addHandler(file_handler)
logger.warn('warn information')
其中logger的输出等级有如下几种:
CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET

对于日志的输出格式中提供了多个输出信息共选择:


Formatter.png

上面是一种调用logger写入日志的方法,还有其他一些方法。

接下来我来详细罗列下Handler的方法:

1.StreamHandler: instances send messages to streams(file-like objects).

2.FileHandler: instances send messages to disk files.

3.RotatingFileHandler: instances send messages to disk files, with support for maximum log file sizes and log file rotation

4.TimedRotatingFileHandler: instances send messages to disk files, rotating the log file at certain timed intervals.

5.SocketHandler: instances send messages to TCP/IP sockets.

6.DatagramHandler: instances send messages to UDP sockets.

7.SMTPHandler:instances send messages to a designated email address.

8.SysLogHandler:instances send messages to a Unix syslog daemon, possibly on a remote machine.

9.NTEventLogHandler:instances send messages to a Windows NT/2000/XP event log.

10.MemoryHandler: instances send messages to a buffer in memory, which is flushed whenever specific criteria are met.

11.HTTPHandler: instances send messages to an HTTP server using either GET or POST semantics.

12.WatchedFileHandler:instances watch the file they are logging to. If the file changes, it is closed and reopened using the file name. This handler is only useful on Unix-like systems; Windows does not support the underlying mechanism used.

13.NullHandler:instances do nothing with error messages. They are used by library developers who want to use logging, but want to avoid the ‘No handlers could be found for logger XXX’ message which can be displayed if the library user has not configured logging.

以上功能非常强大,其中logging可以自动做内存分割的RotatingFileHandler,网络通信进行日志处理,邮件处理,系统守护进行处理日志,通过内存加快日志的处理速度效率。上述就是logging的一种使用方法。

logging的日志格式如果都放在代码中配置就会显的非常麻烦和难看,所以其作者提供了配置项启动的方式。

#创建logger其中root是父类必须存在,其他为自己进行配置

[loggers]
keys=root,mylog
[logger_root]
level=DEBUG
handlers=hand1
[logger_mylog]
level=INFO
handlers=hand1
qualname=mylog
propagate=0
#配置handlers formatter
[handlers]
keys=hand1
[formatters]
keys=format1
[handler_hand1]
class=StreamHandler
formatter=format1
level=INFO
args=(sys.stdout,)
[formatter_format1]
format=%(asctime)s - %(filename)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S
import logging
import logging.config
logging.config.fileConfig("logger.conf")
logger = logging.getLogger("mylog")
logger.error("from logger")#通过mylog对象
logging.error("from logging")#通过root对象

其实配置方法有很多种类官网介绍还可以通过dict等。需要自己看:https://docs.python.org/2/library/logging.config.html#access-to-internal-objects

再者是logging中容易遇到的问题。

logging每次添加一个handler都会执行,如果添加多个Streamhandler在logger中就会重复打多条日志

可以通过logging.getLogger().handlers = []来删除所有的handler

logging能够保证线程安全。通过还有一个问题,logging中处理日志是单线程,如果使用socket等网络打日志的方式可能会对代码的性能有影响,所以如何打日志的同时又保证代码的性能是个问题。可以思考,等我有了解决方案,会第一时间给出。