Django提供了日志模块可以在settings.py中定义LOGGING直接使用
示例 :
LOGGING = { 'version': 1, 'disable_existing_loggers': False, # 是否禁用已经存在的日志模块 'handlers': { 'file': { # 定义日志文件记录 'level': 'ERROR', # 只记录报错 # 'class': 'logging.FileHandler', # 普通的日志记录类,不实用 # 'class': 'logging.handlers.TimedRotatingFileHandler', # 原本的按时间分割的日志记录类 'class': 'utils.tools.MyTimedRotating', # 使用django日志记录全局报错. 重写父类方法,自定义文件命名和删除 'filename': os.path.join(BASE_DIR, 'logs', 'err.log'), # 定义日志文件目录,logs文件夹没有就创建,err.log自动生成 'formatter': 'verbose', 'when': 'D', # 每天切割一次日志 'interval': 1, # 时间间隔: 一天 'backupCount': 10, # 保留?份日志 'encoding': 'utf-8' }, 'console': { # 定义终端打印记录 'level': 'INFO', # 打印所有信息 'class': 'logging.StreamHandler', 'formatter': 'verbose', }, }, 'formatters': { 'verbose': { # 定义详细的日志信息 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', 'style': '{', }, 'simple': { # 定义简单的日志信息 'format': '{levelname} {message}', 'style': '{', }, }, 'loggers': { 'django': { # 使用django日志,指定使用上述定义的各个配置 'handlers': ['file', 'console'], # 同时记录到日志文件和在终端打印 'level': 'INFO', 'propagate': True, # 是否向上传播 'formatter': 'verbose' }, }, }
由于Django提供的这个按时间分割的 TimedRotatingFileHandler 日志类命名很奇怪, 所以我把它的文件命名和删除文件方法重写了, 在自己的 utils/tools.py文件中定义
其中原本的类通过 from logging.handlers import TimedRotatingFileHandler 导入
class MyTimedRotating(TimedRotatingFileHandler): """ 重写父类的日志命名及过量日志删除 """ def doRollover(self): """ 自定义日志命名 """ if self.stream: self.stream.close() self.stream = None # get the time that this sequence started at and make it a TimeTuple currentTime = int(time.time()) dstNow = time.localtime(currentTime)[-1] t = self.rolloverAt - self.interval if self.utc: timeTuple = time.gmtime(t) else: timeTuple = time.localtime(t) dstThen = timeTuple[-1] if dstNow != dstThen: if dstNow: addend = 3600 else: addend = -3600 timeTuple = time.localtime(t + addend) # 重写父类方法, 重写命名日志文件 # dfn = self.rotation_filename(self.baseFilename + "." + # time.strftime(self.suffix, timeTuple)) dfn = self.rotation_filename(self.baseFilename.rstrip(".log") + "_" + time.strftime(self.suffix, timeTuple) + ".log") if os.path.exists(dfn): os.remove(dfn) self.rotate(self.baseFilename, dfn) if self.backupCount > 0: for s in self.getFilesToDelete(): os.remove(s) if not self.delay: self.stream = self._open() newRolloverAt = self.computeRollover(currentTime) while newRolloverAt <= currentTime: newRolloverAt = newRolloverAt + self.interval # If DST changes and midnight or weekly rollover, adjust for this. if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour addend = -3600 else: # DST bows out before next rollover, so we need to add an hour addend = 3600 newRolloverAt += addend self.rolloverAt = newRolloverAt def getFilesToDelete(self): """ 超出规定数量日志的删除 """ dirName, baseName = os.path.split(self.baseFilename) fileNames = os.listdir(dirName) result = [] # prefix = baseName + "." # err. prefix = baseName.rstrip(".log") + "_" # err_ tail = ".log" plen_head = len(prefix) plen_tail = len(tail) for fileName in fileNames: if fileName[:plen_head] == prefix and fileName[-plen_tail:] == tail: suffix = fileName[plen_head: -plen_tail] if self.extMatch.match(suffix): result.append(os.path.join(dirName, fileName)) if len(result) < self.backupCount: result = [] else: result.sort() result = result[:len(result) - self.backupCount] return result
如果懒的话直接使用原本的 logging.handlers.TimedRotatingFileHandler 类, 就不需要重写父类方法了. 写完之后可以使用raise一个错误看看是否能记录到日志.
如果本地启动项目报错 PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。:
将django的启动参数改为: python manage.py runserver --noreload 就正常了.
这样就能自动按时间分割日志文件, 记录全局报错日志了, 大家觉得好用可以帮忙点个赞