logging模块是Python内置的标准模块,主要用于输出运行日志。

简单应用

import logging
logging.debug('+++debug+++')
logging.info('+++info+++')
logging.warning('+++warning+++')
logging.error('+++error+++')
logging.critical('+++critical+++')
结果:

WARNING:root:+++warning+++
ERROR:root:+++error+++
CRITICAL:root:+++critical+++

可见,默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为     日志级别:Logger名称:用户输出消息

灵活配置日志级别,日志格式,输出位置

import logging
logging.basicConfig(level=logging.DEBUG, #级别为DEBUG,所以五条都打出来了
format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', #依次为时间、文件名、行号、日志级别、内容
datefmt='%a, %d %b %Y %H:%M:%S', #日期时间的格式
filename='test.log', #日志存储的指定文件
filemode='w') #默认是a追加,w是写入 logging.debug('+++debug+++')
logging.info('+++info+++')
logging.warning('+++warning+++')
logging.error('+++error+++')
logging.critical('+++critical+++')
test.log内容:

Tue, 15 Jan 2019 20:20:06 logging_lesson.py [line:9] DEBUG +++debug+++
Tue, 15 Jan 2019 20:20:06 logging_lesson.py [line:10] INFO +++info+++
Tue, 15 Jan 2019 20:20:06 logging_lesson.py [line:11] WARNING +++warning+++
Tue, 15 Jan 2019 20:20:06 logging_lesson.py [line:12] ERROR +++error+++
Tue, 15 Jan 2019 20:20:06 logging_lesson.py [line:13] CRITICAL +++critical+++

可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”追加,还可指定为“w”写入。
format:指定handler使用的日志显示格式。 
datefmt:指定日期时间格式。 
level:设置rootlogger(后边会讲解具体概念)的日志级别 
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

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

logger对象

import logging
logger = logging.getLogger() #返回一个logger对象 fh = logging.FileHandler('test2_log') #创建一个handler,用于写入日志文件
ch = logging.StreamHandler() #再创建一个handler,用于输出到控制台 fm = logging.Formatter('%(asctime)s %(message)s') #创建一个格式,将用于上面的两个handler fh .setFormatter(fm) #两个handler设定格式
ch.setFormatter(fm) logger.addHandler(fh) #两个handler都添加进logger对象
logger.addHandler(ch) logger.setLevel('DEBUG') #设置logger的日志级别 logger.debug('+++debug+++') #正式调用logger对象打印日志
logger.info('+++info+++')
logger.warning('+++warning+++')
logger.error('+++error+++')
logger.critical('+++critical+++')

结果:控制台输出和test2_log文件中的内容都是:
2019-01-15 23:29:18,465 +++debug+++
2019-01-15 23:29:18,465 +++info+++
2019-01-15 23:29:18,465 +++warning+++
2019-01-15 23:29:18,465 +++error+++
2019-01-15 23:29:18,465 +++critical+++

如上图,fh和ch作为两个handler对象(一个负责写入文件,一个负责控制台输出),都"吃"掉了fm这个格式对象,又都被最后负责打印日志的logger对象"吃"掉。

使用logger对象是我们常用的方式,Logger是一个树形层级结构, logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。
当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。

但是有两个注意点:

1.只要logging.getLogger(name)中名称参数name相同则返回的Logger实例就是同一个,且仅有一个

import logging
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO) fh = logging.FileHandler('test1_log')
ch = logging.StreamHandler() logger1.addHandler(fh)
logger1.addHandler(ch)
logger2.addHandler(fh)
logger2.addHandler(ch) logger1.debug('logger1+++debug+++')
logger1.info('logger1+++info+++')
logger1.warning('logger1+++warning+++')
logger1.error('logger1+++error+++')
logger1.critical('logger1+++critical+++')
logger2.debug('logger2+++debug+++')
logger2.info('logger2+++info+++')
logger2.warning('logger2+++warning+++')
logger2.error('logger2+++error+++')
logger2.critical('logger2+++critical+++')
结果:控制台输出和test1_log文件中的内容都是:

logger1+++info+++                               #logger1虽然设置了日志级别为DEBUG,但遵从logger2设置的日志级别INFO,因为两者对应的是同一个Logger实例
logger1+++warning+++
logger1+++error+++
logger1+++critical+++
logger2+++info+++
logger2+++warning+++
logger2+++error+++
logger2+++critical+++

logger1.setLevel(logging.DEBUG)将logger1的日志级别设置为了DEBUG,为何显示的时候没有显示出DEBUG级别的日志信息,而是从INFO级别的日志开始显示呢?

原来logger1和logger2对应的是同一个Logger实例,只要logging.getLogger(name)中名称参数name相同则返回的Logger实例就是同一个,且仅有一个,就是说name与Logger实例一一对应。在logger2实例中通过logger2.setLevel(logging.INFO)设置mylogger的日志级别为logging.INFO,所以最后logger1的输出遵从了后来设置的日志级别。

所以,创建Logger时,如果是需要两个实例对象,就要在logging.getLogger(name)中把name参数区分开。

2."子实例"的handler进行处理时,也会传递给所有的"父实例"Logger处理,所以子实例的处理会被执行多次。

import logging
logger = logging.getLogger() logger2 = logging.getLogger('mylogger2')
logger2.setLevel(logging.INFO) ch = logging.StreamHandler() logger.addHandler(ch)
logger2.addHandler(ch) logger.debug('logger+++debug+++')
logger.info('logger+++info+++')
logger.warning('logger+++warning+++')
logger.error('logger+++error+++')
logger.critical('logger+++critical+++')
logger2.debug('logger2+++debug+++')
logger2.info('logger2+++info+++')
logger2.warning('logger2+++warning+++')
logger2.error('logger2+++error+++')
logger2.critical('logger2+++critical+++')
结果:

logger+++warning+++
logger+++error+++
logger+++critical+++
logger2+++info+++                               #logger2执行了两次
logger2+++info+++
logger2+++warning+++
logger2+++warning+++
logger2+++error+++
logger2+++error+++
logger2+++critical+++
logger2+++critical+++

通过logger = logging.getLogger()创建了root Logger,而logger2 = logging.getLogger('mylogger2')创建了root Logger的“子实例”logger2。而孩子,孙子,重孙……的handler进行处理时,也会传递给所有祖先的Logger处理,所以logger2被执行了两边。

也就是说,子实例工作的时候会依次去找他的父辈(树结构,可能有好几层父辈)有没有在工作,如果有一个父辈在工作,子实例就多工作一次。

上述例子中,如果把logger.addHandler(ch)注释掉,logger2就只执行一遍。

(十七)logging模块的更多相关文章

  1. Python之路(第十七篇)logging模块

    一.logging模块 (一).日志相关概念 日志是一种可以追踪某些软件运行时所发生事件的方法.软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情.一个事件可以用一个可包含可选变 ...

  2. Python日志(logging)模块,shelve,sys模块

    菜鸟学python第十七天 1.logging 模块 logging模块即日志记录模块 用途:用来记录日志 为什么要记录日志: 为了日后复查,提取有用信息 如何记录文件 直接打开文件,往里写东西 直接 ...

  3. Python Logging模块的简单使用

    前言 日志是非常重要的,最近有接触到这个,所以系统的看一下Python这个模块的用法.本文即为Logging模块的用法简介,主要参考文章为Python官方文档,链接见参考列表. 另外,Python的H ...

  4. logging 模块误用导致的内存泄露

    首先介绍下怎么发现的吧, 线上的项目日志是通过 logging 模块打到 syslog 里, 跑了一段时间后发现 syslog 的 UDP 连接超过了 8W, 没错是 8 W. 主要是 logging ...

  5. python logging模块详解[转]

    一.简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.war ...

  6. python logging模块

    1.logging模块提供了四个组件logger:日志类,有两个功能1)配置日志的等级,处理器handler,过滤器filterlogger.setLevel(logging.INFO)logger. ...

  7. python logging模块可能会令人困惑的地方

    python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...

  8. Python之logging模块

    一.引言 之前在写一些小程序的时候想把日志内容打到文件中,所以就自己写了一个logger.py的程序,如下: #!/usr/bin/python # -*- coding=utf-8 -*- impo ...

  9. logging模块转载博客

     转载自:http://blog.csdn.net/zyz511919766/article/details/25136485 简单将日志打印到屏幕: [python] view plain copy ...

随机推荐

  1. 20201203-6 设置excel样式【】

    1-1 1 import os 2 from openpyxl import load_workbook 3 from openpyxl.styles import PatternFill, Alig ...

  2. SpringBoot集成基于tobato的fastdfs-client实现文件上传下载和删除

    1. 简介   基于tobato的fastdfs-client是一个功能完善的FastDFS客户端工具,它是在FastDFS作者YuQing发布的客户端基础上进行了大量的重构,提供了上传.下载.删除. ...

  3. AOP基本概念

    连接点joinpoint(类中所有方法) 切入点pointcut(缺少共性代码的方法) 通知advice(被抽取的共性功能的代码逻辑,通知有位置区分,也就是从切入点方法中被抽取代码的前面还是后面抽象出 ...

  4. ES6、ES7、ES8、ES9、ES10新特性

    ES6新特性(2015) ES6的特性比较多,在 ES5 发布近 6 年(2009-11 至 2015-6)之后才将其标准化.两个发布版本之间时间跨度很大,所以ES6中的特性比较多. 在这里列举几个常 ...

  5. Bootstrap留言板界面练习

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. Spring Boot 2.4版本前后的分组配置变化及对多环境配置结构的影响

    前几天在<Spring Boot 2.4 对多环境配置的支持更改>一文中,给大家讲解了Spring Boot 2.4版本对多环境配置的配置变化.除此之外,还有一些其他配置变化,所以今天我们 ...

  7. Unity 2017 Scene界面与Game界面显示不同/过于灰暗的解决办法

    场景界面的显示过于灰暗,严重影响工作心情. 切换到游戏界面时的颜色. 只要将场景中全部摄像机的[Allow HDR]取消勾选即可.

  8. sqlserver 汉字转全拼函数

    create function fn_Getquanpin (@str varchar(100)) returns varchar(8000) as begin declare @re varchar ...

  9. JAVA_JNI字段描述符“([Ljava/lang/String;)V”(Android)

    JNI字段描述符"([Ljava/lang/String;)V "([Ljava/lang/String;)V" 它是一种对函数返回值和参数的编码.这种编码叫做JNI字段 ...

  10. github与svn的区别

      github与svn都属于版本控件系统,但是两者不同于,github是分布式的,svn不是分布的是属于集中式的.   1) 最核心的区别Git是分布式的,而Svn不是分布的.能理解这点,上手会很容 ...