如果对logging模块不了解可以先看下上一篇博客
一、示例代码
一个示例,有些配置可能用不到,但为了介绍全面一些就多写了,需要根据自己项目进行实际的设置
settings文件中配置:
#进行日志logging的配置
#设置日志文件路径
uqa_logpath = os.path.join(BASE_DIR,"logs/uqa/uqa.log").replace('\\', '/')
echarts_logpath = os.path.join(BASE_DIR,"logs/echarts/echarts.log").replace('\\', '/')
echarts_rotatinglogpath=os.path.join(BASE_DIR,"logs/echarts/echartsrotating.log").replace('\\', '/')
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
#过滤器设置
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
}, # 针对 DEBUG = True 的情况, 此过滤器仅在settings.DEBUG为True时传递记录
},
#格式器设置
'formatters': {
'standard': {
'format': '%(levelname)s %(asctime)s %(pathname)s %(filename)s %(module)s %(funcName)s %(lineno)d: %(message)s'
}, # 对日志信息进行格式化,每个字段对应了日志格式中的一个字段,更多字段参考官网文档,我认为这些字段比较合适,输出类似于下面的内容
# INFO 2016-09-03 16:25:20,067 /home/ubuntu/mysite/views.py views.py views get 29: some info...
},
#处理器设置
'handlers': {
#用于发送电子邮件
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'formatter':'standard'
},
# 用于文件输出
'file_handler': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': "debug.txt",
'formatter':'standard'
},
#能够将日志信息输出到sys.stdout, sys.stderr 或者类文件对象(更确切点,就是能够支持write()和flush()方法的对象)
#logging.StreamHandler(stream=None),日志信息会输出到指定的stream中,如果stream为空则默认输出到sys.stderr
'console':{
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'standard'
},
#定义一个写入文件的处理器,不进行切割,在我的项目中使用
'uqa_hanlder':{
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': uqa_logpath,
'formatter': 'standard'
},
#定义一个按日期进行切割日志文件的处理器,在我的项目中使用
'echarts_hanlder': {
'level': 'INFO',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': echarts_logpath,
'formatter': 'standard',
#按分钟数切割一次日志
'when':'M',
#设置时间间隔,这里设为1分钟
'interval':1,
# 保留5份日志,如果有超过五份日志的话会删除最早的,如果设为0则不会删除
'backupCount':5,
'encoding':'utf-8',
},
#定义一个按日志文件大小进行切割的处理器
'rotatingFileHandler':{
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': echarts_rotatinglogpath,
'formatter': 'standard',
'maxBytes': 1024*1024*500, # 日志大小 50M(最好不要超过1G)
# 保留5份日志,如果有超过五份日志的话会删除最早的,如果设为0则不会删除
'backupCount': 5,
'encoding': 'utf-8',
}
},
#日志器设置
'loggers': {
#名称为django的这个日志器是django默认使用的日志器,每次加载会有很多DEBUG级别的日志产生,如果不需要使用可以不设置,或者设为INFO级别
'django': {
'handlers' :['console'], # handlers 来自于上面的 handlers 定义的内容
'level':'WARNING',
'propagate': True # 是否继承父类的log信息
},
#上面那个django日志器的子日志器
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
},
#例如我的名为uqa项目里使用的日志器,可以为每个子项目创建一个日志器
'uqalogger':{
'handlers':["uqa_hanlder"],
'level':'INFO',
'propagate':False,
},
# 例如我名为echarts项目里使用的日志器
'echartslogger': {
'handlers': ["echarts_hanlder"],
'level': 'INFO',
'propagate': False,
},
}
}
二、代码解释
1、设置日志文件路径
在项目下创建一个logs目录,再根据app名称创建子目录,我这里先创建了,如果没有先创建的话可以添加一下判断,不存在目录的话就创建。
uqa_logpath = os.path.join(BASE_DIR,"logs/uqa/uqa.log").replace('\\', '/')
echarts_logpath = os.path.join(BASE_DIR,"logs/echarts/echarts.log").replace('\\', '/')
echarts_rotatinglogpath=os.path.join(BASE_DIR,"logs/echarts/echartsrotating.log").replace('\\', '/')
2、设置过滤器,可以根据自己的需要进行设置,我没怎么用过滤器就不说了
#过滤器设置
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
}, # 针对 DEBUG = True 的情况, 此过滤器仅在settings.DEBUG为True时传递记录
}
3、设置格式器,这里我设置了一个名为standard的格式器
#格式器设置
'formatters': {
'standard': {
'format': '%(levelname)s %(asctime)s %(pathname)s %(filename)s %(module)s %(funcName)s %(lineno)d: %(message)s'
}, # 对日志信息进行格式化,每个字段对应了日志格式中的一个字段,更多字段参考官网文档,我认为这些字段比较合适,输出类似于下面的内容
# INFO 2016-09-03 16:25:20,067 /home/ubuntu/mysite/views.py views.py views get 29: some info...
}
4、设置处理器
#处理器设置
'handlers': {
#用于发送电子邮件
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'formatter':'standard'
},
# 用于文件输出,按日期切割
'file_handler': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': "debug.txt",
'formatter':'standard'
},
#能够将日志信息输出到sys.stdout, sys.stderr 或者类文件对象(更确切点,就是能够支持write()和flush()方法的对象)
#logging.StreamHandler(stream=None),日志信息会输出到指定的stream中,如果stream为空则默认输出到sys.stderr
'console':{
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'standard'
},
#定义一个写入文件的处理器,不进行切割,在我的项目中使用
'uqa_hanlder':{
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': uqa_logpath,
'formatter': 'standard'
},
#定义一个按日期进行切割日志文件的处理器,在我的项目中使用
'echarts_hanlder': {
'level': 'INFO',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': echarts_logpath,
'formatter': 'standard',
#按分钟数切割一次日志
'when':'M',
#设置时间间隔,这里设为1分钟
'interval':1,
# 保留5份日志,如果有超过五份日志的话会删除最早的,如果设为0则不会删除
'backupCount':5,
'encoding':'utf-8',
},
#定义一个按日志文件大小进行切割的处理器
'rotatingFileHandler':{
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': echarts_rotatinglogpath,
'formatter': 'standard',
'maxBytes': 1024*1024*500, # 日志大小 50M(最好不要超过1G)
# 保留5份日志,如果有超过五份日志的话会删除最早的,如果设为0则不会删除
'backupCount': 5,
'encoding': 'utf-8',
}
}
这里设置了几个handler处理器,可以设置输出日志的级别、处理器类型、日志文件名、日志格式(使用上面创建的格式器)、过滤器(使用上面创建的过滤器)等等配置。
前面三个处理器是参考其他人的配置,例子中没用到
- mail_admins这个处理器使用
django.utils.log.AdminEmailHandler
用来发送电子邮件,没用过,有需要再查下 - file_handler这个处理器使用
logging.handlers.TimedRotatingFileHandler
用于写入文件中,并根据日期分割,这里用的默认配置 - console这个处理器使用
logging.StreamHandler
,能够将日志信息输出到sys.stdout, sys.stderr 或者类文件对象(更确切点,就是能够支持write()和flush()方法的对象),logging.StreamHandler(stream=None),日志信息会输出到指定的stream中,如果stream为空则默认输出到sys.stderr,我这里没设置stream参数所以这个处理器会默认输出到控制台
后面三个处理器我测试使用测试了
- uqa_hanlder这个处理器使用
logging.FileHandler
写入文件的处理器,不进行切割 - echarts_hanlder这个处理器使用
logging.handlers.TimedRotatingFileHandler
,按日期进行切割日志文件,这里为了测试设为按分钟切割,会根据时间生成日志文件的名称。 - rotatingFileHandler这个处理器使用
logging.handlers.RotatingFileHandler
按日志文件大小进行切割
django中TimedRotatingFileHandler和RotatingFileHandler多进程报错的问题
参考:django–日志按日期分割
logging多进程报错:PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问
Django多进程滚动日志问题解决方案
(1)根据时间进行切割的处理器logging.handlers.TimedRotatingFileHandler
和根据日志大小进行切割的处理器logging.handlers.RotatingFileHandler
,在django中使用的时候会产生logging多进程报错:PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问
这样的报错。
因为Django默认启用两个进程,一个进程用来检测文件变化,另一个进程是正经的服务器进程。settting.py这个文件被加载了两次,也就是日志文件打开了两次,如果是服务器进程先启动,则看不出毛病来;如果是监控进程首先打开了从settings.py加载了日志,那么正经服务器进程就无法再次加载日志了。
(2)如果你的Django项目是单进程的,那么在启动Django项目的时候使用–noreload就可以解决,noreload表示不启动Django的监控进程,也就是说项目代码的改变不再会影响已经载入内存中的代码,这样,Django就只会起一个进程。
python manage.py runserver 0.0.0.0:80 --noreload
pycharm使用时,在下面添加启动时参数
(3)但是,如果你的项目是多进程的,或者在某些单独的模块,比如celery中为了使用Django的ORM而使用了django.setup()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
import django
django.setup()
如果是根据时间进行切割的TimedRotatingFileHandler
处理器的话,没查到什么好使的方法,还得改代码啥的,这里先放着,后面有查到再补充吧
如果是根据日志大小进行切割的RotatingFileHandler,那么就需要用另一个日志模块解决
- 在window下使用concurrent_log_handler.ConcurrentRotatingFileHandler
pip install concurrent-log-handler
在LOGGING中,用concurrent_log_handler.ConcurrentRotatingFileHandler代替logging.RotatingFileHandler
# settings.py
LOGGING = {
...
'handlers': {
...
'file': {
'level': 'INFO',
'class': 'concurrent_log_handler.ConcurrentRotatingFileHandler',
'filename': os.path.join(LOGS_DIR, 'app.log'),
'formatter': 'verbose',
'maxBytes': 1024,
'backupCount': 5
},
...
}
...
}
- 在linux下使用ConcurrentLogHandler
如果是linux系统下的多进程Django,可以用ConcurrentLogHandler模块。windows上使用该handler会出错,程序卡死在写日志的地方。调试跟踪到该Handler内部,是某个锁的问题。
pip install ConcurrentLogHandler
# settings.py
LOGGING = {
...
'handlers': {
...
'file': {
'level': 'INFO',
'class': 'cloghandler.ConcurrentRotatingFileHandler',
'filename': os.path.join(LOGS_DIR, 'app.log'),
'formatter': 'verbose',
'maxBytes': 1024,
'backupCount': 5
},
...
}
...
}
5、设置日志器
#日志器设置
'loggers': {
#名称为django的这个日志器是django默认使用的日志器,每次加载会有很多DEBUG级别的日志产生,如果不需要使用可以不设置,或者设为INFO级别及以上
'django': {
'handlers' :['console'], # handlers 来自于上面的 handlers 定义的内容
'level':'WARNING',
'propagate': True # 是否继承父类的log信息
},
#上面那个django日志器的子日志器
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
},
#例如我的名为uqa项目里使用的日志器,可以为每个子项目创建一个日志器
'uqalogger':{
'handlers':["uqa_hanlder"],
'level':'INFO',
'propagate':False,
},
# 例如我名为echarts项目里使用的日志器
'echartslogger': {
'handlers': ["echarts_hanlder"],
'level': 'INFO',
'propagate': False,
},
}
(1)django默认使用的名称为django的日志器
名称为django的这个日志器是django默认使用的日志器,django默认去搜寻配置文件中的名为django的日志器,如果没有,就用自带的格式输出到控制台,如果有就按照配置的格式输出。
每次加载会有很多DEBUG级别的日志产生,如果不需要使用可以不设置,或者设为INFO级别及以上。我一般不设置这个,这里为了说明设置一下。
(2)名称为django.request的日志是上面名称为django的的子日志器
(3)uqalogger这个是我一个子项目中使用的日志器,使用上面的创建的uqa_hanlder这个处理器
(4)echartslogger也是子项目中使用的日志器,使用上面创建的echarts_hanlder这个处理器,这里是根据日期进行切割,如果要根据大小切割方式类似,就不多设置日志器了。
三、测试
uqa这个app中设置一个视图函数进行测试
def uqalogtest(request):
uqalogger = logging.getLogger('uqalogger')
uqalogger.info("uqalogtest")
return HttpResponse("测试uqa日志功能")
echarts这个app中也设置一个视图函数进行测试
import logging
def echartslogtest(request):
echartslogger = logging.getLogger('echartslogger')
echartslogger.info("echartslogtest")
return HttpResponse("测试echarts日志功能")
然后启动项目,并访问测试接口
可看到logs下有相应的日志文件产生,并且根据处理器的设置进行生成