【日常小结】python模块--logging

 

上星期挺忙的,参加了一下学校的数学建模比赛,预测湖南湖北的疫情走势以及疫情对长沙经济的影响。 看了别人数学系的论文之后,发现我们太业余了,哈哈,我们基本就是在网上找了几片论文看了一下,然后选择了一个模型,对疫情数据做了一下拟合。他们我就不说了。。

今天总结一下python模块,logging、argparse、tqdm,好早就想小结一下,一直没有做.(写的有点多,argparse、tqdm独立出来,下两篇) 还有《神经网络与深度学习》中的第七章的网络优化与正则化、第八章的注意力机制,看了好久了,也想总结一下,这几天都总结一下吧。

logging模块

logging是python自带的日志模块官方文档,这里主要总结一下Logger、Handler、Formatter对象以及常用的方法。

Logger对象-class logging.Logger

获取日志对象Logger

Logger类不能被直接实例化,需要用logging.getLogger(name)来获取日志对象。

常用方法

  1. 设置日志对象输出信息的最低级别setLevel(level),相应的日志级别
  2. 添加处理日志的处理器对象addHandler(hdlr)
  3. 输出对应级别的信息:debug(msg, *args, **kwargs)info(msg, *args, **kwargs)warning(msg, *args, **kwargs)error(msg, *args, **kwargs)critical(msg, *args, **kwargs)log(level, msg, *args, **kwargs)exception(msg, *args, **kwargs),相应的日志级别

日志级别

日志级别如下表,根日志对象默认的级别是NOTSET,而后代日志对象默认是WARNING,后代日志对象可以由getChild(suffix)方法来获取。

级别 对应的数值
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0

Handler对象-logging.Handler

Handler对象是可以直接实例化的,而且它还有很多子类,如下:

  • StreamHandler
    • StreamHandler(stream=None)
    • 输出日志到sys.stdoutsys.stderr或者是其他file-like文件对象,常用于输出到控制台
  • FileHandler
    • FileHandler(filename, mode='a', encoding=None, delay=False)
    • 输出日志到文件,继承了StreamHandler
  • NullHandler:不做任何处理
  • WatchedFileHandler:监测文件打开与关闭操作,输出日志
  • BaseRotatingHandler:滚动处理RotatingFileHandlerTimedRotatingFileHandler的基类
  • RotatingFileHandler
    • RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
    • 这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小maxBytes之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出。比如日志文件是app.log。当app.log达到指定的大小之后,RotatingFileHandler自动把文件改名为app.log.1,如果app.log.1已经存在,会先把app.log.1重命名为app.log.2,一直到最后重新创建chat.log,继续输出日志信息,如果backupCount=5那么,最多创建备份到app.log.5。
  • TimedRotatingFileHandler
    • TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None)
    • 这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。interval是时间间隔.when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值: | 值 | 类型 | | :–| :– |
      | S | 秒 |
      | M | 分 | | H | 小时 | | D | 天 | | W0-W6 | 每星期(0表示星期一)| | midnight | 每天凌晨 |
  • SocketHandler:远程输出日志到TCP/IP sockets
  • DatagramHandler:远程输出日志到UDP sockets
  • SysLogHandler:日志输出到系统日志syslog
  • NTEventLogHandler:远程输出日志到Windows NT/2000/XP的事件日志
  • SMTPHandler:远程输出日志到邮件地址
  • MemoryHandler:日志输出到内存中的制定buffer
  • HTTPHandler:通过”GET”或”POST”远程输出到HTTP服务器
  • QueueHandler:输出日志到队列中
  • QueueListener:从队列中接受日志信息

以上这些logging.Handler子类,比较常用的是StreamHandlerFileHandlerRotatingFileHandlerTimedRotatingFileHandler

常用方法

  1. 设置处理器处理信息最低等级setLevel(level)
  2. 设置输出日志信息格式setFormatter(fmt),fmt为Formatter对象

Formatter对象-logging.Formatter

Formatter对象用于规定输出日志的格式,这些格式其实是来源于LogRecord对象的属性,不过可以通过字符串的方式直接创建,如实例代码中logging.Formatter。

格式 描述
%(asctime)s 调用日志输出函数的的时间,默认格式像这样2003-07-08 16:49:45,896
%(created)f %(asctime)s类似,也是调用日志输出函数的时间,但是输出格式不同,输出time.time(),时间戳格式,像这样1592202653.744816的数字
%(filename)s 调用日志输出函数是在哪个文件创建的文件名
%(funcName)s 调用日志输出函数是在哪个方法中的方法名
%(levelname)s 调用日志输出函数对应的级别名称
%(levelno)s 调用日志输出函数对应的级别数字
%(lineno)d 调用日志输出函数对应是在代码文件中的哪一行 (有可能不存在)
%(message)s 日志消息,由我们调用日志输出函数中指定
%(module)s 调用日志输出函数是在哪个模块中创建的模块名
%(msecs)d %(asctime)s类似,也是调用日志输出函数的时间,但是输出格式不同,输出的是毫秒
%(name)s Logger对象的名字
%(pathname)s 调用日志输出函数的模块的完整路径名(可能不存在)
%(process)d 调用日志输出函数属于哪个进程的id(可能不存在)
%(processName)s 调用日志输出函数属于哪个进程的名称(可能不存在)
%(relativeCreated)d 调用日志输出函数的相对时间,自Logger对象创建以来的毫秒数
%(thread)d 调用日志输出函数属于哪个线程的id(可能不存在)
%(threadName)s 调用日志输出函数属于哪个线程的名称(可能不存在)

格式就大概讲到这里,具体可以看实例代码

实例代码

import logging
import os

class Logger():

    def __init__(self, logger_path):
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.DEBUG)
        # 输出到文件
        self.logfile = logging.FileHandler(logger_path)
        self.logfile.setLevel(logging.DEBUG)
        # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        formatter = logging.Formatter('%(asctime)s -%(filename)s:%(lineno)s - %(levelname)s - %(message)s')
        self.logfile.setFormatter(formatter)
        # 输出到控制台
        self.logdisplay = logging.StreamHandler()
        # self.logdisplay.setLevel(logging.DEBUG)
        self.logdisplay.setLevel(logging.INFO)
        self.logdisplay.setFormatter(formatter)
        self.logger.addHandler(self.logfile)
        self.logger.addHandler(self.logdisplay)

    def get_logger(self):
        return self.logger
from logger import Logger

logger = Logger('./test.log')
my_logger = logger.get_logger()

my_logger.info('hello, world')
my_logger.debug('hello, world')
## `debug(msg, *args, **kwargs)`
## `info(msg, *args, **kwargs)`
## `warning(msg, *args, **kwargs)`
## `error(msg, *args, **kwargs)`
## `critical(msg, *args, **kwargs)`
## `log(level, msg, *args, **kwargs)`
## `exception(msg, *args, **kwargs)`

小结

上面写了这么多,总结一起,主要就是上面的实例代码这部分代码,全文内容应该差不多可以满足我们大多数日常开放的使用,就总结到这了,用过滤器对象过滤输出等等其他内容就等待探索了,文档在此

本来想logging、argparse、tqdm三个模块放一起的,发现写的有点多(啰里八嗦的),argparse、tqdm模块还是独立写出来吧。