logging模块

  python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志。

logging的日志分为debug()、info()、warning()、error()、critical()五个级别
debug() 调试模式(详细)
info() 记录(无错误)
warning() 无错误但可能有潜在的危险
error() 出现错误
critical() 严重问题
基本用法
import logging

# 基本使用:日志打印
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
"""
WARNING:root:user [alex] attempted wrong password more than 3 times
CRITICAL:root:server is down
"""
日志写入文件
import logging

logging.basicConfig(filename='log_test.log', level=logging.INFO)
logging.debug("This message should go to the log file")
logging.info("so should this")
logging.warning("And this,too")
"""
log_test.log中仅写入了warning和info信息
"""

  在basicConfig中,filename指定了文件路径,level=logging.INFO是把日志记录设置为INFO,只输入INFO或者比INFO级别更高的日志(日志级别过滤)。

自定义日志格式
import logging

logging.basicConfig(filename='log_test.log',
                    level=logging.DEBUG,
                    format='%(asctime)s-%(name)s-%(filename)s-%(funcName)s-%(lineno)d-%(message)s',  # 参数固定格式
                    datefmt='%m/%d/%Y %I:%M:%S %p')

def sayhi():
    logging.error("from sayhi....")
sayhi()
logging.debug("This message should go to the log file")
logging.info("so should this")
logging.warning("And this,too")

  执行会生成log_test.log文件,文件内容如下:

04/18/2018 03:19:00 PM-root-logging_module.py-sayhi-40-from sayhi....
04/18/2018 03:19:00 PM-root-logging_module.py-<module>-42-This message should go to the log file
04/18/2018 03:19:00 PM-root-logging_module.py-<module>-43-so should this
04/18/2018 03:19:00 PM-root-logging_module.py-<module>-44-And this,too

  除了可以在日志格式上加上时间之外,还可以自定义很多格式:

参数格式介绍:
%(levelno)s     # 打印数字形式的日志级别(10对应debug,20对应info,30对应warning)
%(levelname)s   # 打印文本形式的日志级别 %(pathname)s    # 调用日志输出函数的模块的完整路径名
%(filename)s    # 调用日志输出函数的模块的文件名

%(module)s      # 调用日志输出函数的模块名
%(funcName)s    # 调用日志输出函数的函数名
%(lineNo)d      # 调用日志输出函数的语句所在的代码行(44)
%(created)f     # 当前时间,用UNIX标准的表示是时间(一般时间用datafmt即可)
%(relaticeCreated)d    # 输出日志信息时,自Logger创建以来的毫秒数

%(asctime)s     # 字符串形式的当前时间,默认格式"2003-08-08 16:32:21,878",逗号后为毫秒数

%(thread)d      # 线程ID  
%(threadName)s  # 线程名
%(process)d     # 进程ID

%(message)s     # 用户输出的消息

 

日志同时输出到屏幕和文件

Python使用logging模块记录日志涉及四个主要类:
  1、logger提供了应用程序可以直接使用的接口;
  2、handler将(logger创建的)日志记录发送到合适的目的输出;
  3、filter对记录的日志过滤决定哪条日志输出;
  4、formatter决定日志记录的最终输出格式。

这四个类之间的关系:

  首先在输出信息之前获取一个logger对象,用getLogger()方法指定文件名;其次利用StreamHandler()输送到屏幕,利用FileHandler('文件名')输送到文件;再利用addHandler()方法将handler对象加进Logger对象中。接着可以生成Formatter对象,设置文件输出格式,利用setFormatter()方法将输出格式绑定到hander对象上。

  最后由Filters对象对日志进行过滤,一般与Logger进行关联,如果屏幕和文件的日志过滤机制不同,可以与handler进行关联。

Logger组件

  每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块、核心模块可以这样获得它的Logger:

LOG = logging.getLogger("chat.gui")  # 图形界面模块
LOG2 = logging.getLogger("chat.kernal") # 核心模块

  指定日志级别、绑定或删除handler和filters:

# 指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
logging.Logger.setLevel() # 低于指定级别将被忽略

# 添加或删除指定的filter
logging.Logger.addFilter()
logging.Logger.removeFilter()

# 添加或删除指定的handler
logging.Logger.addHandler()
logging.Logger.removeHandler()

  Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别

handler模块

  handler对象负责发送相关信息到指定的目的地(控制台、文件、网络):

logging.Handler.setLevel()  # 指定被处理信息级别
logging.Handler.setFormatter()  # 给这个handler选择一个格式
logging.Handler.addFilter() # 新增一个filter对象
logging.Handler.removeFilter() # 删除一个filter对象

  每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:

  1. logging.StreamHandler 使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。
  2. logging.FileHandler 和StreamHandler 类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件
  3. logging.handlers.RotatingFileHandler  同FileHandler类似,但可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出。

    # 比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的函数是:
    
    RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
    
    """
    其中filename和mode两个参数和FileHandler一样。
        maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
        backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
    """
  4. logging.handlers.TimedRotatingFileHandler

    这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。
    # 函数如下:
    TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
    
    """
    其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
    
    interval是时间间隔。
    
    when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
        S 秒
        M 分
        H 小时
        D 天
        W 每星期(interval==0时代表星期一)
        midnight 每天凌晨
    """

     

formatter组件

  日志的formatter是个独立的组件,可以跟handler组合。

fh = logging.FileHandler("access.log")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter) #把formmater绑定到fh上

 

filter组件

  对日志过滤,可自定义一个filter,通用格式如下:(注意filter函数会返加True or False,logger根据此值决定是否输出此日志

class IgnoreBackupLogFilter(logging.Filter):
    """忽略带db backup 的日志"""
    def filter(self, record): #固定写法
        return   "db backup" not in record.getMessage()

  然后将这个filter添加到logger中:

logger.addFilter(IgnoreBackupLogFilter())

  下面的日志就会将符合filter条件的过滤掉

logger.debug("test ....")
logger.info("test info ....")
logger.warning("start to run db backup job ....")
logger.error("test error ...."
同时输出屏幕、文件、带filter的例子

 

import logging


class IgnoreBackupLogFilter(logging.Filter):
    """忽略带db backup 的日志"""

    def filter(self, record):  # 固定写法
        return "db backup" not in record.getMessage()  # 字段不在日志消息内


# 生成logger对象
logger = logging.getLogger("web")
logger.setLevel(logging.DEBUG)  # 不设置日志级别,默认日志级别是warning
# 把filter对象添加到logger中 logger.addFilter(IgnoreBackupLogFilter()) # 生成handler对象 ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # 屏幕debug级别 fh = logging.FileHandler("web.log") fh.setLevel(logging.WARNING) # 文件设置WARNING级别 # 把handler对象绑定到logger对象 logger.addHandler(ch) logger.addHandler(fh) # 生成formatter对象 file_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s') # 把formatter对象绑定hander对象 ch.setFormatter(console_formater) fh.setFormatter(file_formater) logger.debug("test_log") logger.warning("test_log_2") logger.debug("test log db backup 3") # filter测试,不记录这条日志 """ 在全局日志级别:info (不设置默认级别是warning,一般可以把全局设低把其他级别设高) 屏幕日志级别:debug 文件日志级别:warning 这种情况下,屏幕日志级别不生效,依然按照全局日志级别仅输出一条: 2018-03-03 16:27:28,508 - web - WARNING - 23 - test_log_2 全局设置为DEBUG后,console_handler设置为INFO,若输出的日志级别为DEBUG,则不会再屏幕显示 """

  可以看到上述程序设置屏幕日志级别为debug, 文件日志级别为warning,同时过滤信息为“db backup”。屏幕输出和web.log文件日志如下所示:

# 控制台日志
2018-04-18 16:34:21,376 - web - DEBUG - 32 - test_log
2018-04-18 16:34:21,376 - web - WARNING - 33 - test_log_2

# web.log日志
2018-04-18 16:34:21,376 - web - WARNING - test_log_2

 

根据文件大小截断日志

  函数示例:logging.RotatingFileHandler(filename[, mode[, maxBytes[, backupCount]]]),当文件达到一定大小后,会自动将当前日志文件改名,然后创建一个新的同名的日志文件继续输出。

import logging
from logging import handlers


class IgnoreBackupLogFilter(logging.Filter):
    """忽略带db backup 的日志"""

    def filter(self, record):  # 固定写法
        return "db backup" not in record.getMessage()  # 字段不在日志消息内


# 生成logger对象
logger = logging.getLogger("web")
logger.setLevel(logging.DEBUG)  # 不设置日志级别,默认日志级别是warning

# 把filter对象添加到logger中
logger.addFilter(IgnoreBackupLogFilter())

# 生成handler对象
ch = logging.StreamHandler()
# ch.setLevel(logging.DEBUG)  # 屏幕debug级别

# 生成RotatingFileHandler对象
# fh = logging.FileHandler("web.log")
fh = handlers.RotatingFileHandler("web_jd.log", maxBytes=10, backupCount=3)   # 限制文件大小,日志截断
# fh.setLevel(logging.WARNING)  # 文件设置WARNING级别

# 把handler对象绑定到logger对象
logger.addHandler(ch)
logger.addHandler(fh)

# 生成formatter对象
file_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s')

# 把formatter对象绑定hander对象
ch.setFormatter(console_formater)
fh.setFormatter(file_formater)

logger.debug("test_log")
logger.warning("test_log_2")
logger.debug("test log db backup 3")
"""
输出web_jd.log.1  web_jd.log.2这三个文件
web_jd.log:
2018-03-03 16:54:32,307 - web - WARNING - test_log_2
web_jd.log.1:
2018-03-03 16:54:32,307 - web - DEBUG - test_log
web_jd.log.2:
2018-03-03 16:53:38,900 - web - DEBUG - test_log
2018-03-03 16:53:38,901 - web - WARNING - test_log_2
"""

 

根据时间截断日志

 handlers.TimedRotatingFileHandler()方法

import logging
from logging import handlers


class IgnoreBackupLogFilter(logging.Filter):
    """忽略带db backup 的日志"""

    def filter(self, record):  # 固定写法
        return "db backup" not in record.getMessage()  # 字段不在日志消息内


# 生成logger对象
logger = logging.getLogger("web")
logger.setLevel(logging.DEBUG)  # 不设置日志级别,默认日志级别是warning

# 把filter对象添加到logger中
logger.addFilter(IgnoreBackupLogFilter())

# 生成handler对象
ch = logging.StreamHandler()
# ch.setLevel(logging.DEBUG)  # 屏幕debug级别
# fh = logging.FileHandler("web.log")
fh = handlers.TimedRotatingFileHandler("web_jd.log", when="S", interval=5, backupCount=3)
# fh.setLevel(logging.WARNING)  # 文件设置WARNING级别
# 把handler对象绑定到logger对象
logger.addHandler(ch)
logger.addHandler(fh)

# 生成formatter对象
file_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s')
# 把formatter对象绑定hander对象
ch.setFormatter(console_formater)
fh.setFormatter(file_formater)

logger.debug("test_log")
logger.warning("test_log_2")
logger.debug("test log db backup 3")
"""两次执行生成两个文件
文件web_jd.log.2018-04-18_19-29-22
2018-04-18 19:29:22,013 - web - WARNING - test_log_2
文件web_jd.log.2018-04-18_22-49-38
2018-04-18 22:49:38,467 - web - DEBUG - test_log
2018-04-18 22:49:38,469 - web - WARNING - test_log_2
"""

 

posted @ 2018-04-18 19:31  休耕  阅读(269)  评论(0编辑  收藏  举报