• python日志模块 --- logging


    logging

    Python标准库中提供了方便的日志记录模块,可以根据日志的不同等级进行过滤和分别记录。根据我们的需要快速的自定义日志消息记录。其中有三个重要的对象

    • logger:程序中执行记录日志操作的对象,调用对应的方法即可产生一条日志消息
    • handler:负责管理日志消息的处理,例如写入文件还是作为标准输出
    • fromater:定义日志消息的格式

    日志的等级划分

    日志的级别分为以下几个等级,每个等级使用一个整数值对其进行量化指代,是一个常量值,其中logging模块中的默认的响应级别是

    日志级别Level 数值 对应方法  
    CRITICAL 50 critical() 严重错误级别,出现该错误已经影响到整体运行
    ERROR 40 error() 错误级别,一般用于记录程序出现错误,但不影响整体运行
    WARNING 30 默认级别 warning() 警告级别,,一般用于记录程序出现潜在错误的情形
    INFO 20 info() 事件级别,一般用于记录程序的运行过程
    DEBUG 10 debug 调试级别,一般用于记录程序运行的详细信息
    NOTSET 0    

     

     

     

     

     

     

    formatter

    一条日志消息记录可以由用户自定义消息格式,日志消息中提供了以下信息的字符串占位符。

    占位符格式 描述
    %(levelno)s 日志级别的数值
    %(levelname)s 日志级别名称
    %(name)s 该logger对象的名字
    %(module)s 当前执行程序名
    %(funcName)s 日志调用的当前函数
    %(lineno)d 日志调用的当前行行号
    %(asctime)s 日志的时间,默认为2003-07-08 16.49.45,789格式
    %(thread)d 线程ID
    %(threadName)s 线程名称
    %(process)d 进程ID
    %(processName) 进程名称
    %(message)s 日志信息

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    定义一个日志消息格式

    # 获取了一个formatter对象,该对象需要被handler使用方可生效
    formatter = logging.Formatter(fmt="%(asctime)s - %(name) - %(levelname)s - %(module)s: %(message)s")

    Handler

    logging中两种基本类型的handler,负责处理这些日志信息,但是需要根据formatter决定日志的输出结构信息。

    • FileHandler:将日志消息写入文件
    • StreamHandler:将日志消息写入标准输出
    file_handle = logging.FileHandler(filename="log.txt", mode="a+", encoding="utf-8")
    stream_handler = logging.StreamHandler()

    fmt = logging.Formatter(fmt="%(asctime)s - %(name) - %(levelname)s - %(module)s: %(message)s")   # formatter 
    file_handle.setFormatter(fmt) # 绑定formatter

    Logger

    每一个logger实例就是一个日志记录器,他们有自己属性,例如:名字,日志级别,父logger等

    class Logger(Filterer):
        def __init__(self, name, level=NOTSET):
            Filterer.__init__(self)
            self.name = name                # logger名称
            self.level = _checkLevel(level) # logger级别,定义了0-50整十数极其常量,    logging.WARNING = 30,也使用"WARNING"字符串,_chackLevel(level)已做处理
            self.parent = None              # 继承的父类,命名时使用.作为继承的标志。例如m.m1表示m1继承于m,m必须存在。
            self.propagate = True           # 通过下层logger的消息默认向父类传播,给父类handler判断处理
            self.handlers = []              # 处理消息handler们,每一个分别处理
            self.disabled = False           # 标记为不可用

    通常我们会通过logger  =  logging.getLogger(name, level)去获取一个logger,而不是示例化,该方法是logger提供的工厂方法,再创建前会根据name实现同名单例,也就不会产生同名的两个logger。

    logger产生一条日志消息

    使用对应的方法将会产生一条日志消息,同时还需要绑定handler和formater才能将这个消息输出记录。同时消息的等级必须同时高于logger以及handler的等级,日志消息才会被输出。

    # 用于产生对应消息方法
    debug(self, msg, *args, **kwargs)
    info(msg, *args, **kwargs)
    warning(msg, *args, **kwargs)
    critical(msg, *args, **kwargs)
    error(msg, *args, **kwargs)

    setLevel(level)         # 设置level级别,高于该级别才会交给handler处理
    getEffectiveLevel()     # 有效level,子logger向父logger继承的特性
    addFilter(filter)       # 增加一个过滤对象
    addHandler(hdlr)        # 增加一个handler对象
    removeHandler(hdlr)     # 移除handler

    常见的使用

    有了三个对象,可以结合使用

    file_handle = logging.FileHandler(filename="log.txt", mode="a+", encoding="utf-8")        # 创建handler,将日志写入log.txt文件
    fmt = logging.Formatter(fmt="%(asctime)s - %(name) - %(levelname)s - %(module)s: %(message)s")  # 日志格式
    file_handle.setFormatter(fmt)                                                            # 添加格式
    logger = logging.Logger("cmdb", level=level)    # 获取handler,设置等级
    logger.addHandler(file_handle) # 添加到logger中


    # 使用
    logger.info("一条日志消息")

    # 记录栈信息
    try:
      process()
    except Exception as e:
      logger.error("错误信息", exc_info=True) # exc_info=True将会同时记录这个错误的traceback信息记录日志,方便查询错误信息

    root-logger

    当我们加载logger模块时,会自动创建一个root(一个logger),默认level为warning(30),只有消息等级高于warning的消息才能通过,使用logging.basicConfig()函数可以对root进行方便的初始化配置,它的参数有

     1 logging.basicConfig(
     2     filename=             # 如果消息写入文件,提供文件路径
     3     filemode=             # 设置读写模式,默认为"a"
     4     format=               # 格式化字符串例如:format = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
     5 
     6     datefmt=              # 时间格式字符:"%Y-%M-%D %H:%m:%S"
     7     style=             
     8     level=                # root的level
     9     stream=               # 如果是流,指定一个流对象,例如 stream=os.stderr
    10     handlers=             # 指定一个handdle
    11 )

    format参数中不但可以写入自带占位符,还可以写入自定义占位符,例如:format="%(key1)s",打印消息时候,指定该key的消息value即可。

     

    日志轮转

    在logging.handers模块中,提供了多种handler,这里常用的两种轮转日志handler类

    RotatingFileHandler

    logging提供了将日志写入文件中,但是服务在长期运行时会产生大量的信息,写入一个文件并不方便管理,同时也是不安全的。日志信息从始至终操作一个文件,如果在运行时出现故障造成日志文件丢失,将会造成所有日志信息的丢失,同时,随着时间的积累,我们可能需要对时间线过长的日志信息进行清理,这时候使用日志回滚(RotatingFile)

    日志轮转:使用多个文件分层次的去记录日志信息。随着时间的推移,新的日志文件会将旧文件进行更迭,新日志消息的会将最早的信息清除。同时这些日志内容按照顺序被分片的放在不同文件中,这些文件个数和大小可以自定义,这样我们不再担心一个巨大的日志文件出现了。在logging模块中使用了RotatingHandler实现该功能,将处理日志文件时使用RotatingHandler来处理消息即可。

     1 import logging
     2 from logging import RotatingHandler
     3 
     4 
     5 logger = logging.getLogger(__name__)
     6 logger.setLevel(logging.INFO)
     7 
     8 formatter = logging.Formatter("'%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%D %H:%M:%S")
     9 
    10 # 设置一个log.txt和两个回滚文件,每个文件最多储存1024字节大小的数据,当log.txt字节大于1024,会将数据写入log.txt.1文件,log.txt文件重置。
    11 # log.txt.1文件再次被写入时会向log.txt.2文件写入内容,在接受从log.txt写入的新内容。
    12 # log.txt.2文件写满后,继续写入将丢失最早的信息。最新的消息始终在log.txt中,之前的日志内容在log.txt.1和log.txt.2两个文件中轮转
    13 file_hendler = logging.handlers.RotatingFileHandler(filename="log.txt", maxBytes=1024, backupCount=2)
    14     # maxBytes 单个轮转文件最大字节数
    15     # backupCount 轮转文件的个数;backupCount = 0时,log.txt可以不受maxBytes影响,一直写入数据,和普通日志文件相同
    16 file_headler.setFormatter(formatter)
    17 file_handler.setLevel(logging.INFO)
    18 logger.addHandler(file)
    19 
    20 for i in range(100):
    21     logger.warning("warning %d" % i)

    TimedRotatingFileHandler

    该handler和上面的轮转方式一样,使用多个文件来分别记录,但是分割方式是按照每天进行分割,每个日志文件记录当天的日志消息,可以设置最长的记录日期,这里设置了一个月

    1 logger = logging.getLogger("abc")
    2 logger.setLevel(logging.INFO)
    3 formatter = logging.Formatter("'%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%D %H:%M:%S")
    4 day_handler = TimedRotatingFileHandler("log.txt", when='D', interval=1, backupCount=30, encoding="utf-8")
    5 
    6 day_handler.setFormatter(formatter)
    7 day_handler.setLevel(logging.INFO)

    使用这种时间轮状的方式可以将日志按照每天进行分类,方便我们快速的对日志文件内容进行分析处理,也更加方便的管理。

  • 相关阅读:
    java生成json字符串的方法
    JSON的三种解析方式
    Android Studio你不知道的调试技巧
    Android 打开URL
    build.gradle中引入jar
    Spark RDD/Core 编程 API入门系列之map、filter、textFile、cache、对Job输出结果进行升和降序、union、groupByKey、join、reduce、lookup(一)
    NovaMind *的安装、和谐破解到永久使用
    小Q书桌的下载、安装和使用
    作业提交过程分析(源码)
    SparkContext的初始化过程分析(源码)
  • 原文地址:https://www.cnblogs.com/k5210202/p/13067831.html
Copyright © 2020-2023  润新知