python之logging模块

python之logging模块,第1张

概述网上已经有很多logging模块的资料,在这里只是把看到的几片博客总结一下,也是为了符合自己阅读习惯。参考的博客地址:http://www.cnblogs.com/dahu-daqing/p/7040764.htmlhttps://www.cnblogs.com/louis-w/p/8567434.htmlhttps://www.cnblogs.com

网上已经有很多logging模块的资料,在这里只是把看到的几片博客总结一下,也是为了符合自己阅读习惯。

参考的博客地址:

      http://www.cnblogs.com/dahu-daqing/p/7040764.html

      https://www.cnblogs.com/louis-w/p/8567434.html

      https://www.cnblogs.com/testdjt/p/7834856.html

具体logging模块的具体作用,在上面两片博客里面都很清楚。

logging模块的框架:

  Loggers: 可供程序直接调用的接口,app通过调用提供的API来记录日志       Handlers: 决定将日志记录分配至正确的目的地       Filters:对日志信息进行过滤, 提供更细粒度的日志是否输出的判断       Formatters: 自定义最终记录打印的格式布局loggers:

loggers 就是程序可以直接调用的一个日志接口,可以直接向logger写入日志信息。logger并不是直接实例化使用的,而是通过logging.getLogger(name)来获取对象,事实上logger对象是单例模式,logging是多线程安全的,也就是无论程序中哪里需要打日志获取到的logger对象都是同一个。但是不幸的是logger并不支持多进程,这个在后面的章节再解释,并给出一些解决方案。

【注意】loggers对象是有父子关系的,当没有父logger对象时它的父对象是root,当拥有父对象时父子关系会被修正。举个例子,logging.getLogger("abc.xyz") 会创建两个logger对象,一个是abc父对象,一个是xyz子对象,同时abc没有父对象,所以它的父对象是root。但是实际上abc是一个占位对象(虚的日志对象),可以没有handler来处理日志。但是root不是占位对象,如果某一个日志对象打日志时,它的父对象会同时收到日志,所以有些使用者发现创建了一个logger对象时会打两遍日志,就是因为他创建的logger打了一遍日志,同时root对象也打了一遍日志。

handlers:

Handlers 将logger发过来的信息进行准确地分配,送往正确的地方。举个栗子,送往控制台或者文件或者both或者其他地方(进程管道之类的)。它决定了每个日志的行为,是之后需要配置的重点区域。

每个Handler同样有一个日志级别,一个logger可以拥有多个handler也就是说logger可以根据不同的日志级别将日志传递给不同的handler。当然也可以相同的级别传递给多个handlers这就根据需求来灵活的设置了。

logging中包含的handler主要有以下几种:

handler名称:位置;作用StreamHandler:logging.StreamHandler;日志输出到流,可以是sys.stderr,sys.stdout或者文件fileHandler:logging.fileHandler;日志输出到文件BaseRotatingHandler:logging.handlers.BaseRotatingHandler;基本的日志回滚方式RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件SocketHandler:logging.handlers.socketHandler;远程输出日志到TCP/IP socketsDatagramHandler:logging.handlers.DatagramHandler;远程输出日志到UDP socketsSMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址SysLogHandler:logging.handlers.SysLogHandler;日志输出到syslogNTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到windows NT/2000/XP的事件日志MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定bufferhttpHandler:logging.handlers.httpHandler;通过"GET"或者"POST"远程输出到http服务器

 

Filters:

Filters 提供了更细粒度的判断,来决定日志是否需要打印。原则上handler获得一个日志就必定会根据级别被统一处理,但是如果handler拥有一个Filter可以对日志进行额外的处理和判断。例如Filter能够对来自特定源的日志进行拦截or修改甚至修改其日志级别(修改后再进行级别判断)。

logger和handler都可以安装filter甚至可以安装多个filter串联起来。

formatters:

Formatters 指定了最终某条记录打印的格式布局。Formatter会将传递来的信息拼接成一条具体的字符串,默认情况下Format只会将信息%(message)s直接打印出来。Format中有一些自带的LogRecord属性可以使用,如下表格:

asctime             %(asctime)s         日志事件发生的时间--人类可读时间,如:2003-07-08 16:49:45,896
created             %(created)f         日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值
relativeCreated     %(relativeCreated)d 日志事件发生的时间相对于logging模块加载时间的相对毫秒数(目前还不知道干嘛用的)
msecs               %(msecs)d           日志事件发生事件的毫秒部分
levelname           %(levelname)s       该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
levelno             %(levelno)s         该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
name                %(name)s            所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
message             %(message)s         日志记录的文本内容,通过 msg % args计算得到的
pathname            %(pathname)s        调用日志记录函数的源码文件的全路径
filename            %(filename)s        pathname的文件名部分,包含文件后缀
module              %(module)s          filename的名称部分,不包含后缀
lineno              %(lineno)d          调用日志记录函数的源代码所在的行号
funcname            %(funcname)s        调用日志记录函数的函数名
process             %(process)d         进程ID
processname         %(processname)s     进程名称,Python 3.1新增
thread              %(thread)d          线程ID
threadname          %(thread)s          线程名称

一个Handler只能拥有一个Formatter 因此如果要实现多种格式的输出只能用多个Handler来实现。

在formatters中levelname中可以设置日志的级别,日志的级别有以下几种,如下:

日志等级:使用范围FATAL:致命错误CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用ERROR:发生错误时,如IO *** 作失败或者连接问题WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误INFO:处理请求或者状态变化等日常事务DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态

低于设置日志级别的信息,将会被忽略不会被记录!

logging中的两个方法:logging.basicConfig(**kwargs)  为日志模块配置基本信息。kwargs 支持如下几个关键字参数:
filename :日志文件的保存路径。如果配置了些参数,将自动创建一个fileHandler作为Handler;
filemode :日志文件的打开模式。 默认值为’a’,表示日志消息以追加的形式添加到日志文件中。如果设为’w’, 那么每次程序启动的时候都会创建一个新的日志文件;
format :设置日志输出格式;
datefmt :定义日期格式;
level :设置日志的级别.对低于该级别的日志消息将被忽略;
stream :设置特定的流用于初始化StreamHandler;logging.getLogger([name])创建Logger对象。日志记录的工作主要由Logger对象来完成。在调用getLogger时要提供Logger的名称(注:多次使用相同名称来调用getLogger,返回的是同一个对象的引用。),Logger实例之间有层次关系,这些关系通过Logger名称来体现,如:

p = logging.getLogger(“root”)

c1 = logging.getLogger(“root.c1”)

c2 = logging.getLogger(“root.c2”)

例子中,p是父logger, c1,c2分别是p的子logger。c1, c2将继承p的设置。如果省略了name参数, getLogger将返回日志对象层次关系中的根Logger。

 

基本使用简单的直接在控制台输出:
In [6]: logging.info("this is  info message!")      In [7]: logging.warning("This is  warnings messages")WARNING:root:This is  warnings messages

logging中默认的日志级别是warning,因此info信息不会打印,只有在warning级别以上的信息才会打印。

上述的日志信息为默认的格式信息,下面使用basicconfig对日志信息进行设置。

In [1]: import loggingIn [2]: logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(name)s - %(process)d - %(message)s")In [3]: logging.deBUG("this is deBUG meg")2018-08-04 14:19:50,113 - DEBUG - root - 25188 - this is deBUG megIn [4]: logging.info("this is info meg")2018-08-04 14:20:03,873 - INFO - root - 25188 - this is info megIn [5]: logging.warning("this is warning  meg")2018-08-04 14:20:25,041 - WARNING - root - 25188 - this is warning  meg

上述的日志信息,按照自定义的日志格式输出。

日志输出到文本:
#!/usr/bin/env python#*-* Coding:utf-8 *-*import loggingLOG_FORMAT = "%(asctime)s - %(name)s - %(process)d - %(message)s"DATE_FORMAT = "%Y-%m-%d %H:%M:%s %P"logging.basicConfig(filename="log.txt", level=logging.ERROR, format=LOG_FORMAT, datefmt=DATE_FORMAT)logging.deBUG("This is a deBUG log.")logging.error("this is a error")logging.critical("This is a critical log.")=====执行结果=====[root@os1 workgit]# python log.py    #控制台并不会输出任何结果[root@os1 workgit]# cat log.txt      #文本输出2018-08-04 15:20:29 pm - root - 30511 - this is a error2018-08-04 15:20:29 pm - root - 30511 - This is a critical log.[root@os1 workgit]#

 

日志输出到控制台和文本
= logging.getLogger(== logging.Formatter(= logging.fileHandler(= logging.StreamHandler() console.setLevel(logging.INFO)    console.setFormatter(formatter)   )#整个过程就是先初始化一个logger,然后初始化handler,最后把handler添加进logger!

执行结果:

[root@os1 workgit]2018-08-04 15:08:12,266 -  - INFO - Start 2018-08-04 15:08:12,267 -  - WARNING -2018-08-04 15:08:12,267 -  - INFO -[root@os1 workgit]2018-08-04 15:08:12,266 -  - INFO - Start 2018-08-04 15:08:12,267 -  - WARNING -2018-08-04 15:08:12,267 -  - INFO - Finish【疑问】 在filehandler中设置了日志的默认级别为deBUG,但是文件中的调试信息并没有打出,handler的setlevel设置与logger的setlevel设置究竟是怎么样生效的?未解决!!!!!!!!!!!!

上面的设置已经实现了在控制台和日志中打印输出日志的功能!

几点说明logging.basicConfig()函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何 *** 作的,多次调用的设置并不是累加 *** 作。日志器(Logger)是有层级关系的,上面调用的logging模块级别的函数所使用的日志器是RootLogger类的实例,其名称为'root',它是处于日志器层级关系最顶层的日志器,且该实例是以单例模式存在的。如果要记录的日志中包含变量数据,可使用一个格式字符串作为这个事件的描述消息(logging.deBUG、logging.info等函数的第一个参数),然后将变量数据作为第二个参数*args的值进行传递,如:logging.warning('%s is %d years old.', 'Tom', 10),输出内容为WARNING:root:Tom is 10 years old.logging.deBUG(), logging.info()等方法的定义中,除了msg和args参数外,还有一个**kwargs参数。它们支持3个关键字参数: exc_info, stack_info, extra,下面对这几个关键字参数作个说明。关于exc_info, stack_info, extra关键词参数的说明:exc_info: 其值为布尔值,如果该参数的值设置为True,则会将异常异常信息添加到日志消息中。如果没有异常信息则添加None到日志信息中。stack_info: 其值也为布尔值,默认值为False。如果该参数的值设置为True,栈信息将会被添加到日志信息中。extra: 这是一个字典(dict)参数,它可以用来自定义消息格式中所包含的字段,但是它的key不能与logging模块定义的字段冲突。

 

这些字段介绍,参考上面的第三个博文。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

在博文开始的时候,说明了logging模块的四个核心组件,这个四个核心组件彼此之间是怎么工作的以及各自又是怎么工作的?

四个组件的描述:

日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;不同的处理器(handler)可以将日志输出到不同的位置;日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。

简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理 *** 作。

具体模块的功能介绍,推荐上面博文的第三篇:https://www.cnblogs.com/testdjt/p/7834856.html

捕捉异常

在python中使用traceback追踪一些错误的信息,这里使用logging.error!

#!/usr/bin/env python#*-* Coding:utf-8 *-*import logginglogger = logging.getLogger(__name__)logger.setLevel(level = logging.INFO)handler = logging.fileHandler("log.txt")handler.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')handler.setFormatter(formatter)console = logging.StreamHandler()console.setLevel(logging.INFO)logger.addHandler(handler)logger.addHandler(console)logger.info("Start print log")logger.deBUG("Do something")logger.warning("Something maybe fail.")try:    open("sklearn.txt","rb")except (SystemExit,KeyboardInterrupt):    raiseexcept Exception:    logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)    #logger.error("Faild to open sklearn.txt from logger.error")logger.info("Finish")#通过注释可以查看exc_info = True参数输出的信息

输出的结果如下:

-----------注释前----------------[root@os1 workgit]# python log.pyStart print logSomething maybe fail.Faild to open sklearn.txt from logger.errorTraceback (most recent call last):  file "log.py", line 21, in     open("sklearn.txt","rb")IOError: [Errno 2] No such file or directory: 'sklearn.txt'Finish-----------注释后-----------------[root@os1 workgit]# python log.pyStart print logSomething maybe fail.Faild to open sklearn.txt from logger.errorFinish----------注释前日志文件中的结果---[root@os1 workgit]# cat log.txt 2018-08-04 15:47:55,656 - __main__ - INFO - Start print log2018-08-04 15:47:55,656 - __main__ - WARNING - Something maybe fail.2018-08-04 15:47:55,656 - __main__ - ERROR - Faild to open sklearn.txt from logger.errorTraceback (most recent call last):  file "log.py", line 21, in     open("sklearn.txt","rb")IOError: [Errno 2] No such file or directory: 'sklearn.txt'2018-08-04 15:47:55,656 - __main__ - INFO - Finish

 

总结

以上是内存溢出为你收集整理的python之logging模块全部内容,希望文章能够帮你解决python之logging模块所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1187172.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存