先看日志模块的代码逻辑图:
配上代码,助我加深理解:
# coding=utf-8
import logging
import time
from Common.function import project_path
# 单词:formatter格式器、handler处理程序、FileHandler文件内容处理程序
class FrameLog:
"""
这里定义了日志输出的基本格式
"""
def __init__(self, name=None):
# 调用Framelog,user默认root、日志级别默认debug
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.DEBUG)
# handler定义了将日志发送到哪里,如:pycharm控制器、日志文件、邮件、短信等,
# 创建一个handler,定义了将日志发送到文件,并设置了日志内容的格式、级别、
self.log_name = f"{project_path()}/logs/" + time.strftime("%Y_%m_%d") + "_log.log"
file = logging.FileHandler(self.log_name, "a", "utf-8")
formatter = logging.Formatter('[%(asctime)s] %(filename)s-> %(funcName)s line:%(lineno)d [%(levelname)s]%(''message)s')
file.setFormatter(formatter)
file.setLevel(logging.DEBUG)
# 再次创建一个handler,将日志发送到控制器(我用的是上面的格式器,你可以再这个handler里再自定义一个。)
console = logging.StreamHandler(stream=None)
console.setFormatter(formatter)
console.setLevel(logging.INFO)
# 将2个处理器加入到logger中,不但向控制器输出、还想文件输出。
self.logger.addHandler(file)
self.logger.addHandler(console)
def log(self):
return self.logger
if __name__ == '__main__':
# cgis模块,打印cgis-server模块的日志
log = FrameLog('cgis-server').log()
try:
print(2/0)
except ZeroDivisionError:
print('这里打印在控制台')
# 下面的message输入到日志
log.error('这是一个框架性的错误11111111')
log.debug('这是业务代码里的错误1111111111')
log.info('这是业务代码里info级别的错误11111111111')
log.critical('这是系统性的错误1111111')
# fgis模块,打印fgis - server模块的日志
log = FrameLog('fgis-server').log()
try:
print(2/0)
except ZeroDivisionError:
print('这里打印在控制台')
# 下面的message输入到日志
log.error('这是一个框架性的错误22222')
log.debug('这是业务代码里的错误22')
log.info('这是业务代码里info级别的错误2222')
log.critical('这是系统性的错误222')
实际项目中,日志的定义都是通过配置文件实现的。请参考大佬总结:
[loggers] #固定写法
keys=root,error,info #创建三个app名,root是父类,必需存在的
[logger_root] #创建完的app名我们要定义一些规则,严格要求格式为"logger_appname"
level=DEBUG #设置日志级别
qualname=root #这里在"root"appname下可以不填,所有没获取get的情况下默认app名都是root
handlers=debugs #设置指定过滤器,多个以逗号分隔,这个名字待会儿 我们会以固定格式"handler_(value)"创建
[logger_error]
level=ERROR
qualname=error #除了root appname以外,定义的app名必须要设置这个属性,用于定义打印输出时候的app名
handlers=errors
[logger_info]
level=INFO
qualname=INFO
handlers=infos
[handlers] #固定格式
keys=infos,errors,debugs #定义过滤器名称,下面定义以handler_keysname格式定义,上面引用名称必须和keys一致
[handler_infos]
class=FileHandler #指定过滤器组件,详情请看官网,这个是以文件方式创建
level=INFO #设置级别
formatter=form01 #定义日志打印格式,下面会创建formatters,格式也是严格要求formatter_keysname 创建
args=('info.log','a') #创建文件名字,以什么方式打开
[handler_errors]
class=FileHandler
level=DEBUG
formatter=form02
args=('info1.log','a')
[handler_debugs]
class=FileHandler
level=DEBUG
formatter=form02
args=('info1.log','a')
[formatters] #固定格式
keys=form01,form02 #定义名称,下面会引用格式同上
[formatter_form01]
format=%(asctime)s %(filename)s %(levelname)s %(message)s #年-月-日 时-分-秒,毫秒,文件名,级别名,消息信息
datefmt=%Y-%m-%d %H:%M:%S #日期输出格式
[formatter_form02]
format=%(asctime)s %(filename)s %(levelname)s %(message)s
datefmt=%Y-%m-%d %H:%M:%S
日志模块中是这么调用的:
# coding=utf-8
import logging
import logging.config
logging.config.fileConfig('log.conf')
logs = logging.getLogger('error')
logs.error('errorsssss')