python的logging模块提供了通用的日志系统,可以方便第三方模块或应用使用。

简单使用

  1. import logging
  2.  
  3. # logging.config.fileConfig("./logging.conf")
  4. logging.basicConfig(filename='logger.log', level=logging.INFO)
  5.  
  6. # create logger
  7. logger_name1 = "example01"
  8. logger = logging.getLogger(logger_name1)
  9.  
  10. logger.debug('debug message')
  11. logger.info('info message')
  12. logger.warn('warn message')
  13. logger.error('error message')
  14. logger.critical('critical message')

控制台无打印信息,发现当前工作目录下生成了logger.log,内容为:

  1. INFO:example01:info message
  2. WARNING:example01:warn message
  3. ERROR:example01:error message
  4. CRITICAL:example01:critical message

该模块可以配置哪些信息:

详解:

Logging模块提供Logger,handler,filter,formatter。

  1. Logger:记录器

    • 应用程序代码能直接调用日志接口。
    • Logger最常用的操作有两类:配置和发送日志消息。
    • 初始化 logger = logging.getLogger("endlesscode"),获取logger对象,getLogger()方法后面最好加上所要日志记录的模块名字,配置文件和打印日志格式中的%(name)s 对应的是这里的模块名字,如果不指定name则返回root对象。
    • logger.setLevel(logging.DEBUG),Logging中有NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL这几种级别,日志会记录设置级别以上的日志
    • 级别 何时使用
      DEBUG 详细信息,典型地调试问题时会感兴趣。
      INFO 证明事情按预期工作。
      WARNING 表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
      ERROR 由于更严重的问题,软件已不能执行一些功能了。
      CRITICAL 严重错误,表明软件已不能继续运行了。
    • 多次使用相同的name调用getLogger方法返回同一个looger对象;
  2. handler:处理器
    • 将(记录器产生的)日志记录(log record)发送至合适的目的地(destination),比如文件,socket等。
    • Handler常用的是StreamHandler和FileHandler,可以简单理解为一个是console和文件日志,一个打印在调试窗口上,一个记录在一个文件上
    • 一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。
  3. filter:
    • 过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记录。。
  4. formatter:
    • 格式化器,指明了最终输出中日志记录的布局。
    • 指定日志记录输出的具体格式。
    • formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。
    • 喜欢用这样的格式 '[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S'

Logger 记录器

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

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

Handler 处理器

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

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

  1. 创建方法: 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='')

配置文件格式说明

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

实例代码:

  1. 1、在调试窗口上只打出error以上级别的日志,但是在日志中打出debug以上的信息
  1. import logging
  2.  
  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. import logging
  4.  
  5. class Logger:
  6. def __init__(self, path, clevel=logging.DEBUG, Flevel=logging.DEBUG):
  7. self.logger = logging.getLogger(path)
  8. self.logger.setLevel(logging.DEBUG)
  9. fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
  10.  
  11. # 设置CMD日志
  12. sh = logging.StreamHandler()
  13. sh.setFormatter(fmt)
  14. sh.setLevel(clevel)
  15.  
  16. # 设置文件日志
  17. fh = logging.FileHandler(path)
  18. fh.setFormatter(fmt)
  19. fh.setLevel(Flevel)
  20. self.logger.addHandler(sh)
  21. self.logger.addHandler(fh)
  22.  
  23. def debug(self, message):
  24. self.logger.debug(message)
  25.  
  26. def info(self, message):
  27. self.logger.info(message)
  28.  
  29. def war(self, message):
  30. self.logger.warn(message)
  31.  
  32. def error(self, message):
  33. self.logger.error(message)
  34.  
  35. def cri(self, message):
  36. self.logger.critical(message)
  37.  
  38. if __name__ == '__main__':
  39. logyyx = Logger('yyx.log', logging.ERROR, logging.DEBUG)
  40. logyyx.debug('一个debug信息')
  41. logyyx.info('一个info信息')
  42. logyyx.war('一个warning信息')
  43. logyyx.error('一个error信息')
  44. logyyx.cri('一个致命critical信息')

调试运行结果:

  1. /usr/bin/python3.5 /home/rxf/python3_1000/1000/python3_server/logging封装/封装为一个类.py
  2. [2017-11-07 10:25:50] [ERROR] 一个error信息
  3. [2017-11-07 10:25:50] [CRITICAL] 一个致命critical信息

日志文件内的内容:

  1. [2017-11-07 10:25:50] [DEBUG] 一个debug信息
  2. [2017-11-07 10:25:50] [INFO] 一个info信息
  3. [2017-11-07 10:25:50] [WARNING] 一个warning信息
  4. [2017-11-07 10:25:50] [ERROR] 一个error信息
  5. [2017-11-07 10:25:50] [CRITICAL] 一个致命critical信息

多模块使用logging

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

logging.conf:

  1. [loggers]
  2. keys=root,main
  3.  
  4. [handlers]
  5. keys=consoleHandler,fileHandler
  6.  
  7. [formatters]
  8. keys=fmt
  9.  
  10. [logger_root]
  11. level=DEBUG
  12. handlers=consoleHandler
  13.  
  14. [logger_main]
  15. level=DEBUG
  16. qualname=main
  17. handlers=fileHandler
  18.  
  19. [handler_consoleHandler]
  20. class=StreamHandler
  21. level=DEBUG
  22. formatter=fmt
  23. args=(sys.stdout,)
  24.  
  25. [handler_fileHandler]
  26. class=logging.handlers.RotatingFileHandler
  27. level=DEBUG
  28. formatter=fmt
  29. args=('tst.log','a',20000,5,)
  30.  
  31. [formatter_fmt]
  32. format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
  33. datefmt=

主模块main.py

  1. import logging
  2. import logging.config
  3. import mod
  4.  
  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. logger.debug('let\'s test mod.testLogger()')
  14. mod.testLogger()
  15.  
  16. root_logger.info('finish test...')

子模块mod.py

  1. import logging
  2. import submod
  3.  
  4. logger = logging.getLogger('main.mod')
  5. logger.info('logger of mod say something...')
  6.  
  7. def testLogger():
  8. logger.debug('this is mod.testLogger...')
  9. submod.tst()

子子模块submod.py:

  1. import logging
  2.  
  3. logger = logging.getLogger('main.mod.submod')
  4. logger.info('logger of submod say something...')
  5.  
  6. def tst():
  7. logger.info('this is submod.tst()...')

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

  1. /usr/bin/python3.5 /home/rxf/python3_1000/1000/python3_server/logging封装/main.py
  2. 2017-11-07 10:53:49,228 - root - DEBUG - test root logger...
  3. 2017-11-07 10:53:49,228 - main - INFO - test main logger
  4. 2017-11-07 10:53:49,228 - main - INFO - start import module 'mod'...
  5. 2017-11-07 10:53:49,229 - main - DEBUG - let's test mod.testLogger()
  6. 2017-11-07 10:53:49,229 - main.mod - DEBUG - this is mod.testLogger...
  7. 2017-11-07 10:53:49,229 - main.mod.submod - INFO - this is submod.tst()...
  8. 2017-11-07 10:53:49,229 - root - INFO - finish test...

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

  1. 2017-11-07 10:56:54,189 - main - INFO - test main logger
  2. 2017-11-07 10:56:54,189 - main - INFO - start import module 'mod'...
  3. 2017-11-07 10:56:54,189 - main - DEBUG - let's test mod.testLogger()
  4. 2017-11-07 10:56:54,189 - main.mod - DEBUG - this is mod.testLogger...
  5. 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模块使用过程

  1. 第一次导入logging模块或使用reload函数重新导入logging模块,logging模块中的代码将被执行,这个过程中将产生logging日志系统的默认配置。
  2. 自定义配置(可选)。logging标准模块支持三种配置方式: dictConfig,fileConfig,listen。其中,dictConfig是通过一个字典进行配置Logger,Handler,Filter,Formatter;fileConfig则是通过一个文件进行配置;而listen则监听一个网络端口,通过接收网络数据来进行配置。当然,除了以上集体化配置外,也可以直接调用Logger,Handler等对象中的方法在代码中来显式配置。
  3. 使用logging模块的全局作用域中的getLogger函数来得到一个Logger对象实例(其参数即是一个字符串,表示Logger对象实例的名字,即通过该名字来得到相应的Logger对象实例)。
  4. 使用Logger对象中的debug,info,error,warn,critical等方法记录日志信息。

logging模块处理流程

logging_flow.png
  1. 判断日志的等级是否大于Logger对象的等级,如果大于,则往下执行,否则,流程结束。
  2. 产生日志。第一步,判断是否有异常,如果有,则添加异常信息。第二步,处理日志记录方法(如debug,info等)中的占位符,即一般的字符串格式化处理。
  3. 使用注册到Logger对象中的Filters进行过滤。如果有多个过滤器,则依次过滤;只要有一个过滤器返回假,则过滤结束,且该日志信息将丢弃,不再处理,而处理流程也至此结束。否则,处理流程往下执行。
  4. 在当前Logger对象中查找Handlers,如果找不到任何Handler,则往上到该Logger对象的父Logger中查找;如果找到一个或多个Handler,则依次用Handler来处理日志信息。但在每个Handler处理日志信息过程中,会首先判断日志信息的等级是否大于该Handler的等级,如果大于,则往下执行(由Logger对象进入Handler对象中),否则,处理流程结束。
  5. 执行Handler对象中的filter方法,该方法会依次执行注册到该Handler对象中的Filter。如果有一个Filter判断该日志信息为假,则此后的所有Filter都不再执行,而直接将该日志信息丢弃,处理流程结束。
  6. 使用Formatter类格式化最终的输出结果。 注:Formatter同上述第2步的字符串格式化不同,它会添加额外的信息,比如日志产生的时间,产生日志的源代码所在的源文件的路径等等。
  7. 真正地输出日志信息(到网络,文件,终端,邮件等)。至于输出到哪个目的地,由Handler的种类来决定。
  1.  
  1. 参考文章:
    http://www.jb51.net/article/88449.htm
    http://www.jianshu.com/p/feb86c06c4f4

python3_Logging模块详解的更多相关文章

  1. Python中操作mysql的pymysql模块详解

    Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ...

  2. python之OS模块详解

    python之OS模块详解 ^_^,步入第二个模块世界----->OS 常见函数列表 os.sep:取代操作系统特定的路径分隔符 os.name:指示你正在使用的工作平台.比如对于Windows ...

  3. python之sys模块详解

    python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...

  4. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  5. python time 模块详解

    Python中time模块详解 发表于2011年5月5日 12:58 a.m.    位于分类我爱Python 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括: ...

  6. python time模块详解

    python time模块详解 转自:http://blog.csdn.net/kiki113/article/details/4033017 python 的内嵌time模板翻译及说明  一.简介 ...

  7. 小白的Python之路 day5 time,datatime模块详解

    一.模块的分类 可以分成三大类: 1.标准库 2.开源模块 3.自定义模块 二.标准库模块详解 1.time与datetime 在Python中,通常有这几种方式来表示时间:1)时间戳 2)格式化的时 ...

  8. 小白的Python之路 day5 random模块和string模块详解

    random模块详解 一.概述 首先我们看到这个单词是随机的意思,他在python中的主要用于一些随机数,或者需要写一些随机数的代码,下面我们就来整理他的一些用法 二.常用方法 1. random.r ...

  9. Python中time模块详解

    Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...

随机推荐

  1. 华为 进入和退出Fastboot、eRecovery和Recovery升级模式

    手机关机状态下,可以进入Fastboot/eRecovery / Recovery/升级这几种模式: 需要连接电脑:Fastboot模式:长按音量下键+电源键.eRecovery 模式:长按音量上键+ ...

  2. js让程序暂停运行的方法

    //自己写的暂停毫秒数的函数 function pauseTime(millTime) { var start=Date.now(); while(true){ var nowTime=Date.no ...

  3. JAVA NIO使用非阻塞模式实现高并发服务器

    参考:http://blog.csdn.net/zmx729618/article/details/51860699  https://zhuanlan.zhihu.com/p/23488863 ht ...

  4. js 匿名函数-立即调用的函数表达式

    先提个问题, 单独写匿名函数为什么报错?return 匿名函数 为什么不报错? 如图: 第二种情况在 f 还没有执行的时候,就报错了,,,当然这得归因于函数声明语句声明提前(发生在代码执行之前)的原因 ...

  5. QQ空间的文艺打开方法

    QQ空间被限制?打不开? 看看这里 第一种:http://user.qzone.qq.com/627911903 第二种:http://627911903.qzone.qq.com 第三种:http: ...

  6. QBC检索和本地SQL检索

    细说QBC:QBC(Query By Criteria) 查询:这种方式比较面向对象方式,因为是面向对象,所以查询时参数名就是所查询的类的属性名并不是数据库的表的列名重点是有三个描述条件的对象:Res ...

  7. HQL的第一个程序

    使用HQL查询数据库: 分为以下几个步骤 1获取query对象 //1获取query对象 String hql="FROM Employee e where e.salary>?&qu ...

  8. Struts2的默认拦截器执行顺序

    我们在写Struts2的时候package属性默认都是差不多这样吧 <package name="packageName" namespace="/" e ...

  9. SaltStack远程执行-模块

    上一篇:SaltStack数据系统-Pillar 执行模块 salt 'linux-node2.example.com' service.status sshd 其中service是模块名称statu ...

  10. 在虚拟机中的搭建Web服务器(CentOS)

    1.制作本地yum源 相关可查看:http://www.cnblogs.com/xiaomingzaixian/p/8424290.html 2.安装JDK 上传上传jdk-7u45-linux-x6 ...