【转】https://www.cnblogs.com/yelin/p/6600325.html

基本用法

下面的代码展示了logging最基本的用法。

 1 # -*- coding: utf-8 -*-
2
3 import logging
4 import sys
5
6 # 获取logger实例,如果参数为空则返回root logger
7 logger = logging.getLogger("AppName")
8
9 # 指定logger输出格式
10 formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')
11
12 # 文件日志
13 file_handler = logging.FileHandler("test.log")
14 file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式
15
16 # 控制台日志
17 console_handler = logging.StreamHandler(sys.stdout)
18 console_handler.formatter = formatter # 也可以直接给formatter赋值
19
20 # 为logger添加的日志处理器
21 logger.addHandler(file_handler)
22 logger.addHandler(console_handler)
23
24 # 指定日志的最低输出级别,默认为WARN级别
25 logger.setLevel(logging.INFO)
26
27 # 输出不同级别的log
28 logger.debug('this is debug info')
29 logger.info('this is information')
30 logger.warn('this is warning message')
31 logger.error('this is error message')
32 logger.fatal('this is fatal message, it is same as logger.critical')
33 logger.critical('this is critical message')
34
35 # 2016-10-08 21:59:19,493 INFO : this is information
36 # 2016-10-08 21:59:19,493 WARNING : this is warning message
37 # 2016-10-08 21:59:19,493 ERROR : this is error message
38 # 2016-10-08 21:59:19,493 CRITICAL: this is fatal message, it is same as logger.critical
39 # 2016-10-08 21:59:19,493 CRITICAL: this is critical message
40
41 # 移除一些日志处理器
42 logger.removeHandler(file_handler)

格式化输出日志

1 # 格式化输出
2
3 service_name = "Booking"
4 logger.error('%s service is down!' % service_name) # 使用python自带的字符串格式化,不推荐
5 logger.error('%s service is down!', service_name) # 使用logger的格式化,推荐
6 logger.error('%s service is %s!', service_name, 'down') # 多参数格式化
7 logger.error('{} service is {}'.format(service_name, 'down')) # 使用format函数,推荐
8
9 # 2016-10-08 21:59:19,493 ERROR : Booking service is down!

记录异常信息

当你使用logging模块记录异常信息时,不需要传入该异常对象,只要你直接调用logger.error() 或者 logger.exception()就可以将当前异常记录下来。

 1 # 记录异常信息
2
3 try:
4 1 / 0
5 except:
6 # 等同于error级别,但是会额外记录当前抛出的异常堆栈信息
7 logger.exception('this is an exception message')
8
9 # 2016-10-08 21:59:19,493 ERROR : this is an exception message
10 # Traceback (most recent call last):
11 # File "D:/Git/py_labs/demo/use_logging.py", line 45, in
12 # 1 / 0
13 # ZeroDivisionError: integer division or modulo by zero

logging配置要点

GetLogger()方法

这是最基本的入口,该方法参数可以为空,默认的logger名称是root,如果在同一个程序中一直都使用同名的logger,其实会拿到同一个实例,使用这个技巧就可以跨模块调用同样的logger来记录日志。

另外你也可以通过日志名称来区分同一程序的不同模块,比如这个例子。

1 logger = logging.getLogger("App.UI")
2 logger = logging.getLogger("App.Service")

Formatter日志格式

Formatter对象定义了log信息的结构和内容,构造时需要带两个参数:

  • 一个是格式化的模板fmt,默认会包含最基本的level和 message信息
  • 一个是格式化的时间样式datefmt,默认为 2003-07-08 16:49:45,896 (%Y-%m-%d %H:%M:%S)

fmt中允许使用的变量可以参考下表。

  • %(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 用户输出的消息

SetLevel 日志级别

Logging有如下级别: DEBUG,INFO,WARNING,ERROR,CRITICAL
默认级别是WARNING,logging模块只会输出指定level以上的log。这样的好处, 就是在项目开发时debug用的log,在产品release阶段不用一一注释,只需要调整logger的级别就可以了,很方便。

Handler 日志处理器

最常用的是StreamHandler和FileHandler, Handler用于向不同的输出端打log。
Logging包含很多handler, 可能用到的有下面几种

  • StreamHandler instances send error messages to streams (file-like objects).
  • FileHandler instances send error messages to disk files.
  • RotatingFileHandler instances send error messages to disk files, with support for maximum log file sizes and log file rotation.
  • TimedRotatingFileHandler instances send error messages to disk files, rotating the log file at certain timed intervals.
  • SocketHandler instances send error messages to TCP/IP sockets.
  • DatagramHandler instances send error messages to UDP sockets.
  • SMTPHandler instances send error messages to a designated email address.

Configuration 配置方法

logging的配置大致有下面几种方式。

  1. 通过代码进行完整配置,参考开头的例子,主要是通过getLogger方法实现。
  2. 通过代码进行简单配置,下面有例子,主要是通过basicConfig方法实现。
  3. 通过配置文件,下面有例子,主要是通过 logging.config.fileConfig(filepath)
logging.basicConfig

basicConfig()提供了非常便捷的方式让你配置logging模块并马上开始使用,可以参考下面的例子。具体可以配置的项目请查阅官方文档

 1 import logging
2
3 logging.basicConfig(filename='example.log',level=logging.DEBUG)
4 logging.debug('This message should go to the log file')
5
6 logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
7 logging.debug('This message should appear on the console')
8
9 logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
10 logging.warning('is when this event was logged.')

备注: 其实你甚至可以什么都不配置直接使用默认值在控制台中打log,用这样的方式替换print语句对日后项目维护会有很大帮助。

通过文件配置logging

如果你希望通过配置文件来管理logging,可以参考这个官方文档。在log4net或者log4j中这是很常见的方式。

 1 # logging.conf
2 [loggers]
3 keys=root
4
5 [logger_root]
6 level=DEBUG
7 handlers=consoleHandler
8 #,timedRotateFileHandler,errorTimedRotateFileHandler
9
10 #################################################
11 [handlers]
12 keys=consoleHandler,timedRotateFileHandler,errorTimedRotateFileHandler
13
14 [handler_consoleHandler]
15 class=StreamHandler
16 level=DEBUG
17 formatter=simpleFormatter
18 args=(sys.stdout,)
19
20 [handler_timedRotateFileHandler]
21 class=handlers.TimedRotatingFileHandler
22 level=DEBUG
23 formatter=simpleFormatter
24 args=('debug.log', 'H')
25
26 [handler_errorTimedRotateFileHandler]
27 class=handlers.TimedRotatingFileHandler
28 level=WARN
29 formatter=simpleFormatter
30 args=('error.log', 'H')
31
32 #################################################
33 [formatters]
34 keys=simpleFormatter, multiLineFormatter
35
36 [formatter_simpleFormatter]
37 format= %(levelname)s %(threadName)s %(asctime)s: %(message)s
38 datefmt=%H:%M:%S
39
40 [formatter_multiLineFormatter]
41 format= ------------------------- %(levelname)s -------------------------
42 Time: %(asctime)s
43 Thread: %(threadName)s
44 File: %(filename)s(line %(lineno)d)
45 Message:
46 %(message)s
47
48 datefmt=%Y-%m-%d %H:%M:%S

假设以上的配置文件放在和模块相同的目录,代码中的调用如下。

1 import os
2 filepath = os.path.join(os.path.dirname(__file__), 'logging.conf')
3 logging.config.fileConfig(filepath)
4 return logging.getLogger()

日志重复输出的坑

你有可能会看到你打的日志会重复显示多次,可能的原因有很多,但总结下来无非就一个,日志中使用了重复的handler。

第一坑

 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
import logging
 
logging.basicConfig(level=logging.DEBUG)
 
fmt = '%(levelname)s:%(message)s'
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter(fmt))
logging.getLogger().addHandler(console_handler)
 
logging.info('hello!')
 
# INFO:root:hello!
# INFO:hello!

上面这个例子出现了重复日志,因为在第3行调用basicConfig()方法时系统会默认创建一个handler,如果你再添加一个控制台handler时就会出现重复日志。

第二坑

 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import logging
 
def get_logger():
    fmt = '%(levelname)s:%(message)s'
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(fmt))
    logger = logging.getLogger('App')
    logger.setLevel(logging.INFO)
    logger.addHandler(console_handler)
    return logger
 
def call_me():
    logger = get_logger()
    logger.info('hi')
 
call_me()
call_me()
 
# INFO:hi
# INFO:hi
# INFO:hi

在这个例子里hi居然打印了三次,如果再调用一次call_me()呢?我告诉你会打印6次。why? 因为你每次调用get_logger()方法时都会给它加一个新的handler,你是自作自受。正常的做法应该是全局只配置logger一次。

第三坑

 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import logging
 
def get_logger():
    fmt = '%(levelname)s: %(message)s'
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(fmt))
    logger = logging.getLogger('App')
    logger.setLevel(logging.INFO)
    logger.addHandler(console_handler)
    return logger
 
def foo():
    logging.basicConfig(format='[%(name)s]: %(message)s')
    logging.warn('some module use root logger')
 
def main():
    logger = get_logger()
    logger.info('App start.')
    foo()
    logger.info('App shutdown.')
 
main()
 
# INFO: App start.
# [root]: some module use root logger
# INFO: App shutdown.
# [App]: App shutdown.

为嘛最后的App shutdown打印了两次?所以在Stackoverflow上很多人都问,我应该怎么样把root logger关掉,root logger太坑爹坑妈了。只要你在程序中使用过root logger,那么默认你打印的所有日志都算它一份。上面的例子没有什么很好的办法,我建议你招到那个没有经过大脑就使用root logger的人,乱棍打死他或者开除他。

如果你真的想禁用root logger,有两个不是办法的办法:

 
 
1
2
logging.getLogger().handlers = []  # 删除所有的handler
logging.getLogger().setLevel(logging.CRITICAL)  # 将它的级别设置到最高

Python中的logging模块【转】https://www.cnblogs.com/yelin/p/6600325.html的更多相关文章

  1. Python中的logging模块就这么用

    Python中的logging模块就这么用 1.日志日志一共分成5个等级,从低到高分别是:DEBUG INFO WARNING ERROR CRITICALDEBUG:详细的信息,通常只出现在诊断问题 ...

  2. python中日志logging模块的性能及多进程详解

    python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...

  3. Python中的logging模块

    http://python.jobbole.com/86887/ 最近修改了项目里的logging相关功能,用到了python标准库里的logging模块,在此做一些记录.主要是从官方文档和stack ...

  4. Python入门之Python中的logging模块

    基本用法 下面的代码展示了logging最基本的用法. import logging import sys # 获取logger实例,如果参数为空则返回root logger logger = log ...

  5. Python 中 对logging 模块进行封装,记录bug日志、日志等级

    是程序产生的日志 程序员自定义设置的 收集器和渠道级别那个高就以那个级别输出 日志和报告的作用: 报告的重点在于执行结果(执行成功失败,多少用例覆盖),返回结果 日志的重点在执行过程当中,异常点,哪里 ...

  6. python中的logging模块学习

    Python的logging模块 Logging的基本信息: l  默认的情况下python的logging模块打印到控制台,只显示大于等于warning级别的日志 l  日志级别:critical ...

  7. 【python,logging】python中的logging模块

    本文章转自kenby的博客,比较全面易懂,转来留作以后使用. http://kenby.iteye.com/blog/1162698 一.从一个使用场景开始 import logging # 创建一个 ...

  8. Python中日志logging模块

    # coding:utf-8 import logging import os import time class Logger(object): def __init__(self): # 创建一个 ...

  9. [ Python入门教程 ] Python中日志记录模块logging使用实例

    python中的logging模块用于记录日志.用户可以根据程序实现需要自定义日志输出位置.日志级别以及日志格式. 将日志内容输出到屏幕 一个最简单的logging模块使用样例,直接打印显示日志内容到 ...

随机推荐

  1. Java六大必须理解的问题

    Java六大必须理解的问题 对于这个系列里的问题,每个学Java的人都应该搞懂.当然,如果只是学Java玩玩就无所谓了.如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列.内容 ...

  2. C++中多维数组传递参数

    在c++自定义函数时我们有时需要传递参数,有时以多维数组作为参数,这里就遇到了多维数组该怎么传值的问题了,首先我们看看一维数组是怎么做的. void print_num(int num[], int ...

  3. [ACM International Collegiate Programming Contest, Amman Collegiate Programming Contest (2018)]

    https://codeforces.com/gym/101810 A. Careful Thief time limit per test 2.5 s memory limit per test 2 ...

  4. FlexRay笔记

    1.FlexRay具有高速.可靠及安全的特点.FlexRay在物理上通过两条分开的总线通信,每一条的数据速率是10MBit/s.CAN网络最高性能极限为1Mbps,而FlexRay总数据速率可达到20 ...

  5. Java_初入IO流_字符流_Write-Read_小笔记

    package IO; import java.io.FileWriter; import java.io.IOException; class File_Writer { public static ...

  6. qsort函数排序各种类型的数据。

    qsort函数是库函数中的一员,我们先来看看官方文档是怎么写的: 其中qsort的参数void* base是传入一个数组,size_t num 为数组整体大小,size_t size 为单个元素的大小 ...

  7. Spring/Spring MVC

    90.为什么要使用 spring? 答:spring是一个开源框架,是个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架 方便结构简化开发 AOP编码的支持 声明式事物的支持 方便程序的测试 ...

  8. bootstrapValidator关于js,jquery动态赋值不触发验证(不能捕获“程序赋值事件”)解决办法

    //触发oninput事件 //propertychange 兼容ie678 $('#captainName').on('input propertychange', function() { }); ...

  9. 涨姿势:Java 分业务、分级别实现自定义日志打印

    自定义日志级别 通常的日志框架都有以下几个级别,从低到高TRACE,DEBUG,INFO,WARN,ERROR,FATAL. 默认情况,假如我们定义日志打印级别INFO,它会把大于等于INFO级别的日 ...

  10. 知识点:SQL中char、varchar、text区别

    Char为定长,varchar,text为变长. 1.CHAR.CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去1 ...