Python基础篇:日志logging

Posted 风流 少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python基础篇:日志logging相关的知识,希望对你有一定的参考价值。

一:日志级别

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

二:日志格式化

https://docs.python.org/3/library/logging.html#logrecord-attributes

Attribute nameFormatDescription
argsYou shouldn’t need to format this yourself.The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge (when there is only one argument, and it is a dictionary).
asctime%(asctime)sHuman-readable time when the LogRecord was created. By default this is of the form 2003-07-08 16:49:45,896’ (the numbers after the comma are millisecond portion of the time).
created%(created)fTime when the LogRecord was created (as returned by time.time()).
exc_infoYou shouldn’t need to format this yourself.Exception tuple (à la sys.exc_info) or, if no exception has occurred, None.
filename%(filename)sFilename portion of pathname.
funcName%(funcName)sName of function containing the logging call.
levelname%(levelname)sText logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
levelno%(levelno)sNumeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
lineno%(lineno)dSource line number where the logging call was issued (if available).
message%(message)sThe logged message, computed as msg % args. This is set when Formatter.format() is invoked.
module%(module)sModule (name portion of filename).
msecs%(msecs)dMillisecond portion of the time when the LogRecord was created.
msgYou shouldn’t need to format this yourself.The format string passed in the original logging call. Merged with args to produce message, or an arbitrary object (see Using arbitrary objects as messages).
name%(name)sName of the logger used to log the call.
pathname%(pathname)sFull pathname of the source file where the logging call was issued (if available).
process%(process)dProcess ID (if available).
processName%(processName)sProcess name (if available).
relativeCreated%(relativeCreated)dTime in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
stack_infoYou shouldn’t need to format this yourself. Stack frame information (where available) from the bottom of the stack in the current thread, up to and including the stack frame of the logging call which resulted in the creation of this record.
thread%(thread)dThread ID (if available).
threadName%(threadName)sThread name (if available).

三:使用

3.1 编码方式(个人推荐使用这种)

封装一个日志类。

import os
import sys
import logging
from logging.handlers import RotatingFileHandler
import datetime

current_path = os.path.dirname(__file__)
log_path = os.path.join(current_path, f'../logs/app-datetime.date.today().log')


class LogUtils:
    def __init__(self):
        self.log_path = log_path
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.DEBUG)

        formatter = logging.Formatter(
            fmt='%(asctime)s %(levelname)s %(thread)d --- [%(threadName)s] %(filename)s %(funcName)s:%(lineno)d:%(message)s')

        console_handler = logging.StreamHandler()
        console_handler.setFormatter(formatter)

		# RotatingFileHandler 根据日志文件大小自动生成日志文件
        # 单个文件最大3k,最多保存3份文件(除了当前写入的文件外),实际情况这个值要设的很大sys.maxsize,防止覆盖 超过则循环式覆盖
        rotating_file_handler = RotatingFileHandler(log_path, maxBytes=1024 * 3, backupCount=3, encoding='utf-8')

		# TimedRotatingFileHandler 往文件里写入: 根据时间间隔自动生成日志 文件
        # interval是时间间隔,
        # backupCount是备份文件的个数,如果超过这个个数,就会自动删除,
        # when是间隔的时间单位,单位有以下几种:S 秒, M 分, H 小时, D 天, W 每星期(interval==0时代表星期一, midnight 每天凌晨
        timed_rotating_file_handler = handlers.TimedRotatingFileHandler(filename=filename, when='D', backupCount=3, encoding='utf-8')

  
        rotating_file_handler.setFormatter(formatter)

        file_handler = logging.FileHandler(log_path, encoding='utf-8')
        file_handler.setFormatter(formatter)
        self.logger.addHandler(console_handler)
        # self.logger.addHandler(file_handler)
        self.logger.addHandler(rotating_file_handler)

    def get_logger(self):
        return self.logger


logger = LogUtils().get_logger()

日志测试

from common.log_utils import logger

if __name__ == '__main__':
    for i in range(40):
        logger.info(f" i info测试info测试info测试info测试info测试info测试info测试info测试info测试info测试info测试info测试info测试info测试.")

注意:这里和我的认知不太一样,这里先从最后一个日志文件开始写,即先从2号开始写,然后是1号,最后是没有标号的文件。


3.2 配置文件方式 fileConfig

logging.conf

[loggers]
# 配置logger信息。必须包含一个名字叫做root的logger,当使用无参函数logging.getLogger()时,默认返回root这个logger,
# 其他自定义logger可以通过 logging.getLogger("fileAndConsole") 方式进行调用
keys=root,fileAndConsole

[handlers]
# 定义声明handlers信息。
keys=fileHandler,consoleHandler

[formatters]
# 设置日志格式
keys=simpleFormatter

[logger_root]
# 对loggers中声明的logger进行逐个配置,且要一一对应,在所有的logger中,必须制定level和handlers这两个选项,
# 对于非roothandler,还需要添加一些额外的option,其中qualname表示它在logger层级中的名字,在应用代码中通过这个名字制定所使用的handler,
# 即 logging.getLogger("fileAndConsole"),handlers可以指定多个,中间用逗号隔开,比如handlers=fileHandler,consoleHandler,同时制定使用控制台和文件输出日志
level=DEBUG
handlers=consoleHandler,fileHandler

[logger_fileAndConsole]
level=DEBUG
handlers=fileHandler,consoleHandler
qualname=fileAndConsole
propagate=0

[handler_consoleHandler]
# 在handler中,必须指定class和args这两个option,常用的class包括
# StreamHandler(仅将日志输出到控制台)、FileHandler(将日志信息输出保存到文件)、
# RotaRotatingFileHandler(将日志输出保存到文件中,并设置单个日志wenj文件的大小和日志文件个数),
# args表示传递给class所指定的handler类初始化方法参数,它必须是一个元组(tuple)的形式,即便只有一个参数值也需要是一个元组的形式;
# 里面指定输出路径,比如输出的文件名称等。level与logger中的level一样,而formatter指定的是该处理器所使用的格式器,
# 这里指定的格式器名称必须出现在formatters这个section中,且在配置文件中必须要有这个formatter的section定义;
# 如果不指定formatter则该handler将会以消息本身作为日志消息进行记录,而不添加额外的时间、日志器名称等信息;
class=StreamHandler
args=(sys.stdout,)
level=DEBUG
formatter=simpleFormatter

[handler_fileHandler]
class=FileHandler
args=('test.log', 'a')
level=DEBUG
formatter=simpleFormatter

[formatter_simpleFormatter]
format=%(asctime)s %(levelname)s %(thread)d --- [%(threadName)s] %(filename)s %(funcName)s:%(lineno)d:%(message)s
datefmt=%Y-%m-%d %H:%M:%S
import logging.config

logging.config.fileConfig('./config/logging.conf')
logger = logging.getLogger()

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

3.3 配置字典方式 dictConfig

LOGGING_CONFIG = 
    "version": 1,
    "formatters": 
        "default": 
            'format': '%(asctime)s %(levelname)s %(thread)d --- [%(threadName)s] %(filename)s %(funcName)s:%(lineno)d:%(message)s',
        
    ,
    "handlers": 
        "console": 
            "class": "logging.StreamHandler",
            "level": logging.DEBUG,
            "formatter": "default"
        ,
        "file": 
            "class": "logging.FileHandler",
            "level": logging.DEBUG,
            "filename": "./log.txt",
            "formatter": "default",
        
    ,
    "root": 
        "handlers": ["console", "file"],
        "level": "DEBUG"
    ,


logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger()

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

以上是关于Python基础篇:日志logging的主要内容,如果未能解决你的问题,请参考以下文章

Python 日志记录与程序流追踪(基础篇)

Python学习笔记——基础篇第六周——logging模块

python自学日志--基础篇

Python接口自动化之logging日志

Nginx详解六:Nginx基础篇之Nginx日志

接口测试基础——第4篇logging模块