Logging模块

Logging模块

什么是日志?

日志是一种可以追踪某些软件运行时所发生事件的方法。通过log的分析,可以方便用户了解系统或软件、应用的运行情况。

日志的级别

logging模块日志级别有DEBUG < INFO < WARNING < ERROR < CRITICAL 五种。

  • DEBUG - 调试模式,应用场景是问题诊断;
  • INFO - 通常只记录程序中一般事件的信息,用于确认工作一切正常;
  • WARNING - 打印警告信息,系统还在正常运行;
  • ERROR - 错误导致某些功能不能正常运行时记录的信息;
  • CRITICAL - 当发生严重错误,导致应用程序不能继续运行时记录的信息。

组成部分

  • logger:提供记录日志的方法。
  • handler:选择日志的输出地方(一个logger添加多个handler)。
  • filter:给用户提供更加细粒度的控制日志的输出内容。
  • format:用户格式化输出日志的信息。

配置方法

  1. 基础配置
logging.basicConfig(filename="config.log", 
                    filemode="w", 
                    format="%(asctime)s-%(name)s-%(levelname)s-%(message)s", 
                    level=logging.INFO)
  1. 使用配置文件的方式
fileConfig(filename,defaults=None,disable_existing_loggers=Ture )
  1. 使用一个字典方式来写配置信息
使用dictConfig(dict,defaults=None, disable_existing_loggers=Ture )函数

日志输出

  • StreamHandler
logging.StreamHandler:日志输出到流,可以是sys.stderr,sys.stdout或者文件
  • FileHandler
logging.FileHandler:日志输出到文件
  • BaseRotatingHandler
logging.handlers.BaseRotatingHandler:基本的日志回滚方式
  • RotatingHandler
logging.handlers.RotatingHandler:日志回滚方式,支持日志文件最大数量和日志文件回滚

部分名词解释

Logging.Formatter:这个类配置了日志的格式,在里面自定义设置日期和时间,输出时会按照设置的格式显示。
Logging.Logger:Logger是Logging模块的主体,进行以下三项工作:
    1. 为程序提供记录日志的接口
    2. 判断日志所处级别,并判断是否要过滤
    3. 根据其日志级别将该条日志分发给不同handler

日志的封装

​ 实际开发情况中,我们会将logging单独写成一个模块封装成类,然后在其他的功能模块比如通讯协议模块,数据库模块,业务层,API调用模块等等,中进行调用。

​ 在实际情况中,在前文提到的 logging.getLogger(" ") 传入无名称适用于只需要小范围系统使用,一旦涉及到多个模块,需要系统划分的情况,建议把class设置一个传入参数,并且将这个参数传递给 logging.getLogger(" ") ,以规范日志的划分。

import logging
import logging.handlers
import os
import time


class logs(object):
    def __init__(self):
        # 获取模块名称,测试的时候直接控模块即可,但是在实际使用的情况下需要针对不同需要进行日志撰写的模块进行命名
        # 列如:通讯协议模块,测试模块,数据库模块,业务层模块,API调用模块
        # 可以考虑 __init__(self,model_name) 这样传入,然后再用一个list规定一下模块名称
        self.logger = logging.getLogger("")
        # 设置输出的等级
        LEVELS = {'NOSET': logging.NOTSET,
                  'DEBUG': logging.DEBUG,
                  'INFO': logging.INFO,
                  'WARNING': logging.WARNING,
                  'ERROR': logging.ERROR,
                  'CRITICAL': logging.CRITICAL}
        # 创建文件目录
        logs_dir = "logs"
        if os.path.exists(logs_dir) and os.path.isdir(logs_dir):
            pass
        else:
            os.mkdir(logs_dir)
        # 修改log保存位置
        timestamp = time.strftime("%Y-%m-%d", time.localtime())
        logfilename = '%s.txt' % timestamp
        logfilepath = os.path.join(logs_dir, logfilename)
        rotatingFileHandler = logging.handlers.RotatingFileHandler(filename=logfilepath,
                                                                   maxBytes=1024 * 1024 * 50,
                                                                   backupCount=5)
        # 设置输出格式
        formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
        rotatingFileHandler.setFormatter(formatter)
        # 控制台句柄
        console = logging.StreamHandler()
        console.setLevel(logging.NOTSET)
        console.setFormatter(formatter)
        # 添加内容到日志句柄中
        self.logger.addHandler(rotatingFileHandler)
        self.logger.addHandler(console)
        self.logger.setLevel(logging.NOTSET)

    def info(self, message):
        self.logger.info(message)

    def debug(self, message):
        self.logger.debug(message)

    def warning(self, message):
        self.logger.warning(message)

    def error(self, message):
        self.logger.error(message)

Demo

  1. 日志输出-控制台

    import logging  # 引入logging模块
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')  # logging.basicConfig函数对日志的输出格式及方式做相关配置
    
    # 由于日志基本配置中级别设置为DEBUG,所以一下打印信息将会全部显示在控制台上
    logging.info('this is a loggging info message')
    logging.debug('this is a loggging debug message')
    logging.warning('this is loggging a warning message')
    logging.error('this is an loggging error message')
    logging.critical('this is a loggging critical message')
    
  2. 日志输出-文件

import logging
import os.path
import time


# 第一步,创建一个logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # 设置Log等级

# 第二步,创建一个handler,用于写入日志文件
rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
log_path = os.path.dirname(os.getcwd()) + '/Logs/'
log_name = log_path + rq + '.log'
logfile = log_name

fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG)  # 输出到file的log等级的开关

# 第三步,定义handler的输出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)

# 第四步,将logger添加到handler里面
logger.addHandler(fh)

# 日志
logger.debug('this is a logger debug message')
logger.info('this is a logger info message')
logger.warning('this is a logger warning message')
logger.error('this is a logger error message')
logger.critical('this is a logger critical message')
  1. 日志输出-控制台和文件
ch = logging.StreamHandler()	# 只要在输入到日志中的第二步和第三步插入一个handler输出到控制台
ch.setLevel(logging.WARNING)  # 输出到console的log等级的开关
# 在第四步和第五步分别加入以下代码即可
ch.setFormatter(formatter)
logger.addHandler(ch)
6format常用格式说明
    %(levelno)s: 打印日志级别的数值
    %(levelname)s: 打印日志级别名称
    %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
    %(filename)s: 打印当前执行程序名
    %(funcName)s: 打印日志的当前函数
    %(lineno)d: 打印日志的当前行号
    %(asctime)s: 打印日志的时间
    %(thread)d: 打印线程ID
    %(threadName)s: 打印线程名称
    %(process)d: 打印进程ID
    %(message)s: 打印日志信息

    
import os.path
import time
import logging
# 创建一个logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # Log等级总开关

# 创建一个handler,用于写入日志文件
rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
log_path = os.path.dirname(os.getcwd()) + '/Logs/'
log_name = log_path + rq + '.log'
logfile = log_name
fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG)  # 输出到file的log等级的开关

# 定义handler的输出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)
logger.addHandler(fh)
# 使用logger.XX来记录错误,这里的"error"可以根据所需要的级别进行修改
try:
    open('/path/to/does/not/exist', 'rb')
except (SystemExit, KeyboardInterrupt):
    raise
except Exception, e:
    logger.error('Failed to open file', exc_info=True)
  1. 日志滚动和过期删除(按时间)
# 字段解释
filename:日志文件名的prefix;

when:是一个字符串,用于描述滚动周期的基本单位,字符串的值及意义如下: 
“S”: Seconds 
“M”: Minutes 
“H”: Hours 
“D”: Days 
“W”: Week day (0=Monday) 
“midnight”: Roll over at midnight

interval: 滚动周期,单位有when指定,比如:when=’D’,interval=1,表示每天产生一个日志文件
backupCount: 表示日志文件的保留个数
# coding:utf-8
import logging
import time
import re
from logging.handlers import TimedRotatingFileHandler
from logging.handlers import RotatingFileHandler


def backroll():
    #日志打印格式
    log_fmt = '%(asctime)s\tFile \"%(filename)s\",line %(lineno)s\t%(levelname)s: %(message)s'
    formatter = logging.Formatter(log_fmt)
    #创建TimedRotatingFileHandler对象
    log_file_handler = TimedRotatingFileHandler(filename="ds_update", when="M", interval=2, backupCount=2)
    #log_file_handler.suffix = "%Y-%m-%d_%H-%M.log"
    #log_file_handler.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}.log$")
    log_file_handler.setFormatter(formatter)
    logging.basicConfig(level=logging.INFO)
    log = logging.getLogger()
    log.addHandler(log_file_handler)
    #循环打印日志
    log_content = "test log"
    count = 0
    while count < 30:
        log.error(log_content)
        time.sleep(20)
        count = count + 1
    log.removeHandler(log_file_handler)


if __name__ == "__main__":
    backroll()
    

你可能感兴趣的:(Python的标准库,python)