import logging.config
from logging import LogRecord
# 通常用于Linux系统下,使控制台输出的日志带颜色
class ColorFormatter(logging.Formatter):
log_colors = {
'CRITICAL': '\033[0;31m',
'ERROR': '\033[0;33m',
'WARNING': '\033[0;35m',
'INFO': '\033[0;32m',
'DEBUG': '\033[0;00m',
}
def format(self, record: LogRecord) -> str:
s = super().format(record)
level_name = record.levelname
if level_name in self.log_colors:
return self.log_colors[level_name] + s + '\033[0m'
return s
class MyFilter400(logging.Filter):
def filter(self, record: LogRecord):
if record.msg.startswith("4"):
return True
return False
class MyFilter300(logging.Filter):
def filter(self, record: LogRecord):
if record.msg.startswith("3"):
return True
return False
LOG_LEVEL = logging.INFO
LOGGER = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'color': {
'class': '__main__.ColorFormatter', # 如果你的模块不是写在启动程序中,请将__main__更换成你模块的路径,下同
'format': '%(asctime)s [%(name)s] %(levelname)s: %(message)s'
},
'default': {
'class': 'logging.Formatter',
'format': '%(message)s'
}
},
'filters': {
'filter_400': {
'()': '__main__.MyFilter400'
},
'filter_300': {
'()': '__main__.MyFilter300'
}
},
'handlers': {
'console': {
'level': LOG_LEVEL,
'class': 'logging.StreamHandler',
'formatter': 'color',
},
'file1': {
'level': LOG_LEVEL,
'class': 'logging.FileHandler',
'mode': 'w',
'formatter': 'default',
'filename': '400_log.txt',
'encoding': 'utf-8',
'filters': ['filter_400']
},
'file2': {
'level': LOG_LEVEL,
'class': 'logging.FileHandler',
'mode': 'w',
'formatter': 'default',
'filename': '300_log.txt',
'encoding': 'utf-8',
'filters': ['filter_300']
},
},
'loggers': {
'__main__': {
'handlers': ['file1', 'file2', 'console'],
'level': LOG_LEVEL,
},
}
}
logging.config.dictConfig(LOGGER)
logger = logging.getLogger(__name__)
logger.debug('200,this is a logger debug message')
logger.info('302,this is a logger info message')
logger.warning('301,this is a logger warning message')
logger.error('404,this is a logger error message')
logger.critical('500,this is a logger critical message')
print("%s" % __name__)
运行效果图:
控制台:
文件:
3开头的写入到300_log.txt
4开头的写入到400_log.txt
特别注意,使用过滤器的一个问题
class MyFilter400And500(logging.Filter):
def filter(self, record: LogRecord):
if record.msg.startswith("4") or record.msg.startswith("5"):
return True
return False
# record.msg = "404, %s, %s"
logger.info(f"{status_code}, %s, %s", website, link)
# record.msg = "%s, %s, %s",这就导致过滤器返回False
logger.info("%s, %s, %s", status_code, website, link)
因此,如果发现消息没有写入文件,可能是消息格式的问题。
目前,官方推荐字符串格式化的方式就是第一种方式,%s
和.format()
的方式都不如这个好。但是如果你的项目中使用了sentry,在打印错误信息的时候就推荐用%s的方式了,因为sentry会将上面第二种方式的消息统归为一类,如果用第一种方式,每个不同的status_code就是一类错误消息了。