一:日志级别
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 name | Format | Description |
args | You shouldn’t need to format this yourself. | The tuple of arguments merged into |
asctime |
| Human-readable time when the |
created |
| Time when the |
exc_info | You shouldn’t need to format this yourself. | Exception tuple (à la |
filename |
| Filename portion of |
funcName |
| Name of function containing the logging call. |
levelname |
| Text logging level for the message ( |
levelno |
| Numeric logging level for the message ( |
lineno |
| Source line number where the logging call was issued (if available). |
message |
| The logged message, computed as |
module |
| Module (name portion of |
msecs |
| Millisecond portion of the time when the |
msg | You shouldn’t need to format this yourself. | The format string passed in the original logging call. Merged with |
name |
| Name of the logger used to log the call. |
pathname |
| Full pathname of the source file where the logging call was issued (if available). |
process |
| Process ID (if available). |
processName |
| Process name (if available). |
relativeCreated |
| Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded. |
stack_info | You 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 ID (if available). |
threadName |
| Thread 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')