python中,logging由logger、handler、filter、formater四个部分组成:
logger(记录器):提供我们记录日志的方法;
handler(处理器):选择日志的输出地方,如:控制台,文件,邮件发送等,一个logger可以添加多个handler;
filter(过滤器):是给用户提供更加细致的控制日志的输出内容;
formater(格式化器):用户格式化输出日志的信息。
python中配置logging有三种方式:
1、基础配置(logging.basicConfig)
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='mymmmmmmmm.txt',
filemode='a')
在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
-
filename: 用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
-
filemode: 文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
-
format: 指定handler使用的日志显示格式:
- format参数中可能用到的格式化串:
- %(name)s Logger的名字
- %(levelno)s 数字形式的日志级别
- %(levelname)s 文本形式的日志级别
- %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
- %(filename)s 调用日志输出函数的模块的文件名
- %(module)s 调用日志输出函数的模块名
- %(funcName)s 调用日志输出函数的函数名
- %(lineno)d 调用日志输出函数的语句所在的代码行
- %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
- %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
- %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
- %(thread)d 线程ID。可能没有
- %(threadName)s 线程名。可能没有
- %(process)d 进程ID。可能没有
- %(message)s 用户输出的消息
- format参数中可能用到的格式化串:
-
datefmt: 指定日期时间格式。
-
level: 设置rootlogger(后边会讲解具体概念)的日志级别
-
stream: 用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
propagete参数 :propagete=0,表示输出日志,但消息不传递;propagate=1是输出日志,同时消息往更高级别的地方传递。root为最高级别。
2、使用配置文件的方式配置logging(fileConfig)
使用fileConfig(filename,defaults=None,disable_existing_loggers=Ture )函数来读取配置文件。
3、使用字典方式来写配置信息(dictConfig)
使用dictConfig(dict,defaults=None, disable_existing_loggers=Ture )函数来完成logging的配置.
my_logger.py
import datetime
from your_project.settings import MEDIA_ROOT # 这里为你项目中的根目录,在settings中配置
import os
import logging
import logging.config
#LOGGING_DIR 日志文件存放目录
LOGGING_DIR = MEDIA_ROOT + "/logs/" # 日志存放路径
if not os.path.exists(LOGGING_DIR):
os.mkdir(LOGGING_DIR)
def genLogDict():
# 日志配置
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
# 格式化器
'formatters': {
'standard': {
'format': '[%(levelname)s] [%(asctime)s] [%(filename)s] [%(funcName)s] [%(lineno)d] > %(message)s'
},
'simple': {
'format': '[%(levelname)s] > %(message)s'
},
},
# 过滤器
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
# 处理器
'handlers': {
'console': {
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file_handler': {
'level': 'INFO',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': '%s/mylog.log %s' % (LOGGING_DIR, datetime.datetime.today().date()), #具体日志文件的名字
'formatter':'standard'
}, # 用于文件输出
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'formatter':'standard'
},
},
# 日志记录器
'loggers': { #日志分配到哪个handlers中
'your_app_name': { # 后面导入时logging.getLogger使用的app_name
'handlers': ['console','file_handler'],
'level':'DEBUG',
'propagate': True,
},
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
}, ####如果要将get,post请求同样写入到日志文件中,则这个触发器的名字必须叫django,然后写到handler中
}
}
return LOGGING
def initLogConf():
"""
配置日志
"""
logDict = genLogDict()
logging.config.dictConfig(logDict)
配置完成后,在需要使用到日志的地方导入使用:
test.py
import logging
from my_logger import initLogConf
# 配置日志
initLogConf()
mylog = logging.getLogger('your_app_name') # 该app_name为日志配置my_logger中日志记录器中的app_name,两者保持一致
def test1():
try:
print(1/0)
except Exception as e:
mylog.error(str(e)) # 将异常写入日志
test1()
这样日志中就记录了异常:
mylog.log
[ERROR] [2021-08-23 10:48:05,933] [CheckConsistency_views.py] [get] [315] > division by zero
至于选择那种方式配置日志,可以根据项目需求来灵活选择!