为什么要使用日志而不是print
- 打印到控制台的内容会因为运行主机意外中断而消失,这对项目大、运行时间长时,会导致重跑等。列:下班前跑ai代码运行在服务器上,服务器异常中断连接,导致控制台被关闭、输出被情况,排查问题复杂
- 对多个代码的实验更容易追溯。列:做ai实验时,我们会跑多次代码、替换数据或特征等,这些实验结果应该被详细记录下来,而不是手动对结果进行标注
python日志设计思路
- 最简化封装。工程中日志模块可能被多次引用,我看网上教程很多都是在以代码中加入大量日志基础模块做配置,这在工程中会显得项目臃肿
- 可被复用。保证在python项目中能正常通用性调用
- 当作模块调用,每次启动项目,尽管调用多次也只创建一个日志文件。(用单例模式)
代码
项目下创建py文件如logger.py,里面代码如下:
import datetime
import logging
from os.path import join
# 使用单列模式来保证多个模块调用时, 只有一个代码
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances.keys():
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Log:
__metaclass__ = Singleton
_loggers = {}
def __init__(self, file_name, logger_name=None):
self.file_name = file_name
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(logging.INFO)
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)
dt = datetime.datetime.now().strftime(format('%Y-%m-%d-%H-%M-%S'))
# 最好有统一输出目录,而非项目目录下
log_path = '.'
logger = Log(join(log_path, dt + '_TSC.log'))
使用方式可以在多个该项目的不同py文件调用此代码,如下为调用方法:
from logger import logger
logger.info('呵呵,在洗澡')
在项目目录下可以获得以时间+tsc.log结尾的文件,如下打开后显示为
也可以直接调用该模块,来达到相应的自定义效果,如以下引用:
from logger import Log
from os.path import join
# 要顺利运行需要在本地创建output目录
logger_custom = Log(join(r'./output', 'error_plot_des.log'), '')
logger_custom.info(f'调用测试')