python 日志类

简介

在所有项目中必不可少的一定是日志记录系统,python为我们提供了一个比较方便的日志模块logging,通常,我们都会基于此模块编写一个日志记录类,方便将项目中的日志记录到文件中。

logging

日志主要分为如下几个等级。

日志等级 描述
DEBUG 详细信息,通常仅在诊断问题时才有意义。
INFO 无异常时输出的日志,主要是确认程序是否正常按照预期进行的
WARNING 当出现一些异常信息(例如磁盘空间不足)时,但是不会影响程序的正常执行
ERROR 当出现问题时导致程序无法正常运行时
CRITICAL 当出现严重问题时导致程序无法继续运行时
import logging


logging.info("info")
logging.warning("warning")
logging.debug("debug")
logging.error("error")
logging.critical("critical")
WARNING:root:warning
ERROR:root:error      
CRITICAL:root:critical

由此可见,info,debug信息未输出,是因为默认的level等级是warning。

logging模块中的四个基本类和对应功能

名称 功能
Loggers 公开应用程序代码直接使用的接口。
Handlers 将日志记录(由记录器创建)发送到适当的目的地(标准输出、文件等)。
Filters 提供了更细粒度的工具来确定要输出哪些日志记录。
Formatters 指定最终输出中日志记录的布局。

日志输出到文件

使用basicConfig进行配置

logging.basicConfig(filename="test.log", level=logging.INFO)
logging.info("info")
logging.warning("warning")
logging.debug("debug")
logging.error("error")
logging.critical("critical")
INFO:root:info
WARNING:root:warning
ERROR:root:error
CRITICAL:root:critical

由上述日志可得出:日志的组成

日志等级:日志记录器名称:日志内容

那么如何修改记录器名称?

通过如下方式可以实现记录器名称的修改

logger = logging.getLogger("test")
logging.basicConfig(filename="test.log", level=logging.INFO)
logger.info("info")
logger.warning("warning")
logger.debug("debug")
logger.error("error")
logger.critical("critical")
INFO:test:info
WARNING:test:warning
ERROR:test:error
CRITICAL:test:critical

由上述可见,虽然修改了记录器的名称,但格式还是不那么容易读懂的,因此需要修改一下日志的格式

如何修改日志输出的格式呢?

通过basicConfig中的format来修改
asctime:当前时间,levelname:等级名称,message:日志信息

logger = logging.getLogger("test")
logging.basicConfig(
    filename="test.log",
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)
logger.info("info")
logger.warning("warning")
logger.debug("debug")
logger.error("error")
logger.critical("critical")

Handler

处理器对象:将适当的日志消息(基于日志消息的严重性)分派到处理程序的指定目的地。 Logger 对象可以使用 addHandler() 方法向自己添加零个或多个处理程序对象。作为示例场景,应用程序可能希望将所有日志消息发送到日志文件,将所有错误或更高级别的日志消息发送到标准输出,并将所有关键消息发送到电子邮件地址。此方案需要三个单独的处理程序,其中每个处理程序负责将特定严重性的消息发送到特定位置。
handler主要有以下几种,此处列举出常用的几种。

名称 作用
StreamHandler 用于将日志记录直接在终端中输出
FileHandler 用于将日志记录输出到磁盘中
NullHandler 用于对日志记录不做任何输出
RotatingFileHandler 用于达到一定大小时,自动生成新的日志文件, 只适用于Linux
TimedRotatingFileHandler 用于对每天的日志文件进行输出, 只适用于Linux

Formatters

格式化对象:将日志转换成text并按照指定格式格式化输出日志字符串的格式。
常用的参数:fmt=None, datefmt=None
fmt:日志的展示格式,例如:

# 代表时间 日志等级 日志信息
%(asctime)s %(levelname)s %(message)s

主要有以下显示格式

%(name)s 记录器的名称(记录通道)
%(levelno)s 消息的数字日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)
%(levelname)s 消息的文本记录级别 ("DEBUG", "INFO", WARNING、ERROR、CRITICAL)
%(pathname)s 记录日志的源文件的完整路径名已发出呼叫(如果可用)
%(filename)s 路径名的文件名部分
%(module)s 模块(文件名的名称部分)
%(lineno)d 发出记录调用的源行号(如果可供使用的话)
%(funcName)s 函数名
%(created)f 创建日志记录的时间 (time.time()返回值)
%(asctime)s 创建 LogRecord 的文本时间
%(msecs)d 创建时间的毫秒部分
%(relativeCreated)d 创建 LogRecord 的时间(以毫秒为单位),相对于加载日志模块的时间(通常在应用程序启动时)
%(thread)d 线程 ID(如果可用)
%(threadName)s 线程名称(如果可用)
%(process)d 进程 ID(如果可用)
%(message)s record.getMessage() 的结果,计算方式为 记录发出

datefmt:日志信息的时间格式,例如:

%Y-%m-%d %H:%M:%S

简单的日志记录类

import logging


def log():
    # 创建一个日志对象
    log = logging.getLogger("test")
    # 设置记录器发给处理器handler的最低等级
    log.setLevel(logging.DEBUG)

    # 创建一个处理器用于设置日志对象
    handler = logging.StreamHandler()
    # 设置handler发送给目标的最低等级
    handler.setLevel(logging.DEBUG)

    # 创建格式器,设置输出日志格式
    format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    handler.setFormatter(format)

    log.addHandler(handler)

    return log


test_log: logging.Logger = log()
test_log.info("info")
test_log.debug("debug")
test_log.error("error")
test_log.critical("critical")
2022-07-12 17:19:23,396 - test - INFO - info
2022-07-12 17:19:23,396 - test - DEBUG - debug      
2022-07-12 17:19:23,396 - test - ERROR - error      
2022-07-12 17:19:23,396 - test - CRITICAL - critical

从配置文件中读取配置进行输出日志

import logging
import logging.config

logging.config.fileConfig('logging.conf')

logger = logging.getLogger('simpleExample')

logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')

logging.conf

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
2022-07-12 17:22:55,953 - simpleExample - DEBUG - debug message
2022-07-12 17:22:55,953 - simpleExample - INFO - info message        
2022-07-12 17:22:55,953 - simpleExample - WARNING - warn message     
2022-07-12 17:22:55,953 - simpleExample - ERROR - error message      
2022-07-12 17:22:55,953 - simpleExample - CRITICAL - critical message

通过配置文件方式进行日志格式的处理与上述类似。

日志记录类

下面的日志记录类,可以方便在项目中进行直接使用或者简单修改一下使用。

类方式实现

import logging
import pathlib


class Log:
    def __init__(self, file_name, logger_name=None):
        self.file_name = file_name
        self.logger = logging.getLogger(logger_name)
        self.logger.setLevel(logging.DEBUG)
        self.get_log()

    def get_log(self):
        # FileHandler: 将格式化的日志记录写入磁盘文件的处理程序类
        # 将格式化的日志记录写入磁盘文件的处理程序
        handler = logging.FileHandler(self.file_name)
        handler.setLevel(logging.DEBUG)
        formater = logging.Formatter(
            "%(asctime)s:%(filename)s:%(lineno)d:%(name)s:%(levelname)s:%(message)s"
        )
        handler.setFormatter(formater)
        self.logger.addHandler(handler)

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

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

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

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

    def critical(self, msg):
        self.logger.critical(msg)


log_path = pathlib.Path(__file__).parent.joinpath("test.log")

log = Log(log_path)
log.info("info")
2022-07-12 17:51:14,069:logger.py:24:root:INFO:info

目前发现日志的对应行数是类中的行数,使用函数方式则不会出现此问题

函数方式

def Log2(file_name, logger_name=None):
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.DEBUG)
    handler = logging.FileHandler(file_name)
    handler.setLevel(logging.DEBUG)
    formater = logging.Formatter(
        "%(asctime)s:%(filename)s:%(lineno)d:%(name)s:%(levelname)s:%(message)s"
    )
    handler.setFormatter(formater)
    logger.addHandler(handler)
    return logger


log = Log2(log_path)
log.info("info")
2022-07-12 17:53:40,661:logger.py:59:root:INFO:info

参考

logging官方文档

posted @ 2022-07-10 16:33  形同陌路love  阅读(366)  评论(0编辑  收藏  举报