Django 使用logging生成日志

如果对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下有相应的日志文件产生,并且根据处理器的设置进行生成
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值