<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      32 項目結(jié)構(gòu) & 事務(wù) & Logging日志

      1 項目結(jié)構(gòu)

      以下主要是以drf編寫api時的結(jié)構(gòu)為示例。

      1.1 APP結(jié)構(gòu)

      1.1.1 單APP

      例如:訂單系統(tǒng)

      image


      1.1.2 Base + 業(yè)務(wù)APP

      例如:供應(yīng)鏈系統(tǒng)

      image


      1.1.3 獨立的APP

      app中的功能各自獨立的,每個app中編寫自己的 models / views 等。

      image


      1.2 視圖結(jié)構(gòu)

      1.2.1 view.py

      image


      1.2.2 views + 文件

      根據(jù)業(yè)務(wù)拆分成多個視圖文件,每個視圖文件中實現(xiàn)指定的一些業(yè)務(wù)。

      image


      1.2.3 views + 文件夾

      image


      這里的router路由需要注意:

      image


      1.3 返回值

      1.3.1 自定義mixins

      將視圖中的 mixins相關(guān)的視圖重寫,業(yè)務(wù)視圖繼承自己視圖,對于各種情況的返回值進行定制:

      1.內(nèi)置返回

      對于認證、權(quán)限等組件進行自定義,實現(xiàn)返回自定義的格式數(shù)據(jù)。

      image


      2.視圖返回

      對于用戶請求的返回值進行定制。

      image


      1.3.2 自定義異常處理機制

      在之前學習源碼時,我們知道:請求到來都會執(zhí)行dispatch方法,在 try...except代碼塊中:

      • 觸發(fā):認證、權(quán)限、限流等
      • 執(zhí)行視圖
      • 上述過程如果出現(xiàn)異常,則由 self.handle_exception(exc)對異常處理并封裝返回值,然后返回。

      image


      1.handle_exception源碼

      image

      image

      image

      image


      2.自定義exception_handler

      詳細案例見:dbhot11.zip

      utils/handlers.py
      from django.http import Http404
      
      from rest_framework import exceptions
      from rest_framework.response import Response
      from rest_framework.exceptions import ValidationError
      from rest_framework.exceptions import Throttled
      from rest_framework.exceptions import PermissionDenied
      from rest_framework.exceptions import NotAuthenticated
      from rest_framework.exceptions import AuthenticationFailed
      from rest_framework.views import set_rollback
      
      
      def exception_handler(exc, context):
          if isinstance(exc, Http404):
              exc = exceptions.NotFound()
              exc.ret_code = 1001
          elif isinstance(exc, PermissionDenied):
              exc = exceptions.PermissionDenied()
              exc.ret_code = 1002
          elif isinstance(exc, (AuthenticationFailed, NotAuthenticated)):
              exc.ret_code = 1003
          elif isinstance(exc, Throttled):
              exc.ret_code = 1004
          elif isinstance(exc, ValidationError):
              exc.ret_code = 1005
      
          # 只處理drf相關(guān)的異常
          if isinstance(exc, exceptions.APIException):
              headers = {}
              if getattr(exc, 'auth_header', None):
                  headers['WWW-Authenticate'] = exc.auth_header
              if getattr(exc, 'wait', None):
                  headers['Retry-After'] = '%d' % exc.wait
      
              if isinstance(exc.detail, (list, dict)):
                  data = exc.detail
              else:
                  code = getattr(exc, 'ret_code', None) or -1
                  data = {'code': code, 'detail': exc.detail}
      
              set_rollback()
              return Response(data, status=exc.status_code, headers=headers)
          return None
      
      utils/exceptions.py
      from rest_framework import exceptions
      
      
      class ExtraException(exceptions.APIException):
      
          def __init__(self, detail=None, ret_code=None, code=None):
              super().__init__(detail, code)
              self.ret_code = ret_code
      
      views.py
      from rest_framework import exceptions
      from rest_framework import serializers
      from rest_framework.viewsets import GenericViewSet
      from rest_framework.mixins import ListModelMixin
      from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin
      from rest_framework.authentication import BaseAuthentication
      from rest_framework.permissions import BasePermission
      from rest_framework.throttling import BaseThrottle
      
      from api import models
      from utils.exceptions import ExtraException
      
      
      class ExtraAuthentication(BaseAuthentication):
          def authenticate(self, request):
              raise exceptions.AuthenticationFailed("認證失敗")
      
          def authenticate_header(self, request):
              return "api"
      
      
      class ExtraPermission(BasePermission):
          def has_permission(self, request, view):
              return False
      
          def has_object_permission(self, request, view, obj):
              return False
      
      
      class ExtraThrottle(BaseThrottle):
          def allow_request(self, request, view):
              return False
      
      
      class DemoSerializer(serializers.ModelSerializer):
          class Meta:
              model = models.UserInfo
              fields = "__all__"
      
      
      class DemoView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin,
                     GenericViewSet):
          # authentication_classes = [ExtraAuthentication]
          # throttle_classes = [ExtraThrottle]
          # permission_classes = [ExtraPermission]
          queryset = models.UserInfo.objects.all()
          serializer_class = DemoSerializer
      
          def perform_create(self, serializer):
              self.dispatch
              if True:
                  # 自定義錯誤
                  # raise ExtraException("數(shù)據(jù)異常")
                  raise ExtraException("更新失敗", ret_code=9000)
              serializer.save()
      
          def finalize_response(self, request, response, *args, **kwargs):
              response = super().finalize_response(request, response, *args, **kwargs)
              if response.exception:
                  return response
      
              response.data = {'code': 0, 'data': response.data}
              return response
      

      3.正常返回

      image

      image

      def finalize_response(self, request, response, *args, **kwargs):
          response = super().finalize_response(request, response, *args, **kwargs)
          if response.exception:
              return response
      
          response.data = {'code': 0, 'data': response.data}
          return response
      

      可以通過自定義 DrfGenericViewSet

      from rest_framework.viewsets import GenericViewSet as DrfGenericViewSet
      
      
      class GenericViewSet(DrfGenericViewSet):
          def finalize_response(self, request, response, *args, **kwargs):
              response = super().finalize_response(request, response, *args, **kwargs)
              if response.exception:
                  return response
              response.data = {'code': 0, 'data': response.data}
              return response
      

      可以定義到中間件中使用:

      from django.utils.deprecation import MiddlewareMixin
      
      
      class ReturnCodeMiddleware(MiddlewareMixin):
          def process_response(self, request, response):
              if not hasattr(response, 'exception'):
                  return response
      
              if response.exception:
                  return response
      
              response.data = {'code': 0, 'data': response.data}
              response._is_rendered = False
              response.content = response.render().content
              return response
      

      2 事務(wù)

      2.1 局部事務(wù)(*)

      基于上下文管理,如果出現(xiàn)異常則自動回滾;無異常則自動提交。

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.db import transaction
      from api import models
      
      
      class Demo1View(APIView):
          def get(self, request, *args, **kwargs):
              try:
                  with transaction.atomic():
                      models.UserInfo.objects.create(name='v1', age=1)
                      models.Order.objects.create(name='v1', age=1)
              except Exception as e:
                  print("異常,自動回滾")
      
              return Response("...")
      

      事務(wù)提交的回調(diào)函數(shù)(本質(zhì)上就是事務(wù)完成后,自動執(zhí)行一個函數(shù)):

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.db import transaction
      from api import models
      from functools import partial
      
      
      def db_success_callback(*args, **kwargs):
          print(args, **kwargs)
      
      class Demo1View(APIView):
          def get(self, request, *args, **kwargs):
              try:
                  with transaction.atomic():
                      # 回調(diào)函數(shù),事務(wù)正常提交自動執(zhí)行
                      transaction.on_commit(db_success_callback)
                      transaction.on_commit( partial(db_success_callback, 11, 22, 33) )
      
                      models.UserInfo.objects.create(name='v1', age=1)
                      models.Order.objects.create(title='v1', count=1)
              except Exception as e:
                  print("異常,自動回滾") # on_commit回調(diào)函數(shù)內(nèi)部異常時不會回滾
      
              return Response("...")
      

      回滾到 指定事務(wù)點:

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.db import transaction
      from api import models
      
      
      class Demo1View(APIView):
          def get(self, request, *args, **kwargs):
              try:
                  with transaction.atomic():
                      # 回調(diào)函數(shù),事務(wù)正常提交自動執(zhí)行
                      n1 = transaction.savepoint()
                      models.UserInfo.objects.create(name='v1', age=1)
                      n2 = transaction.savepoint()
                      models.UserInfo.objects.create(name='v2', age=1)
      
                      # 必須在事務(wù)里面,回顧到指定 事務(wù)點,后續(xù)東西不提交
                      transaction.savepoint_rollback(n2)
              except Exception as e:
                  print("異常,自動回滾", e)  # on_commit回調(diào)函數(shù)內(nèi)部異常時不會回滾
      
              return Response("...")
      

      2.2 視圖事務(wù)

      針對整個視圖進行開啟事務(wù):

      • 視圖內(nèi),有數(shù)據(jù)庫操作異常,自動回滾
      • 視圖內(nèi),有其他異常,不會回滾。
      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.db import transaction, IntegrityError
      from api import models
      
      
      class Demo1View(APIView):
      
          @transaction.atomic
          def get(self, request, *args, **kwargs):
              try:
                  models.UserInfo.objects.create(name='v100', age=1)
                  models.UserInfo.objects.create(name="v200", age="xxx")  # 有異常,回滾,即:v100不會保存
                  int("asdf")   # 有異常,不會滾,即:兩條數(shù)據(jù)正常保存到數(shù)據(jù)庫
              except Exception as e:
                  pass
              return Response("...")
      

      定義事務(wù)點,自定義回滾位置:

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.db import transaction, IntegrityError
      from api import models
      
      
      class Demo1View(APIView):
      
          @transaction.atomic
          def get(self, request, *args, **kwargs):
              try:
                  models.UserInfo.objects.create(name='v10', age=1)
                  n1 = transaction.savepoint()
                  models.UserInfo.objects.create(name="v11", age=1)
                  n2 = transaction.savepoint()
                  models.UserInfo.objects.create(name='v12', age=1)
                  n3 = transaction.savepoint()
                  models.UserInfo.objects.create(name='v13', age=1)
      
                  # 后續(xù)讀取到某些值后,發(fā)現(xiàn) v12不應(yīng)該創(chuàng)建,那么就可以主動回滾(只生成n2之前的)
                  transaction.savepoint_rollback(n2)
              except Exception as e:
                  print("有異常", e)
              return Response("...")
      

      2.3 全局事務(wù)

      效率低:項目中一般不會使用。

      如果想要開啟全局事務(wù),需要在連接數(shù)據(jù)庫時多設(shè)置一個參數(shù):

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              'NAME': 'dbhot4',
              'USER': 'root',
              'PASSWORD': 'root123',
              'HOST': '127.0.0.1',
              'PORT': '3306',
              'ATOMIC_REQUESTS': True
          }
      }
      
      • 只要視圖函數(shù)執(zhí)行異常,無論是什么原因觸發(fā),均自動回滾。

        class Demo1View(APIView):
            def get(self, request, *args, **kwargs):
                models.UserInfo.objects.create(name='v1', age=1)
                models.UserInfo.objects.create(xxxxxxx='v2', age=1) # 錯誤
                return Response("...")
        
        class Demo1View(APIView):
            def get(self, request, *args, **kwargs):
                models.UserInfo.objects.create(name='v1', age=1)
                models.UserInfo.objects.create(name='v2', age=1)
                int("asdf")  # 錯誤
                return Response("...")
        
      • 如果視圖函數(shù)執(zhí)行不報錯(try處理異常,也叫不報錯),則不會回滾

        class Demo1View(APIView):
            def get(self, request, *args, **kwargs):
                try:
                    models.UserInfo.objects.create(name='v1', age=1)
                    models.UserInfo.objects.create(xxxxxxx='v2', age=1)
                    int("xxx")
                except Exception as e:
                    pass
                return Response("...")
        
        # 視圖函數(shù)執(zhí)行沒有報錯,不會滾回。
        

      如果開啟了全局事務(wù),想要免除某個指定的函數(shù)不需要開啟事務(wù),則可以使用:

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from django.db import transaction, IntegrityError
      from api import models
      from django.utils.decorators import method_decorator
      
      
      @method_decorator(transaction.non_atomic_requests, name='dispatch')
      class Demo1View(APIView):
      
          def get(self, request, *args, **kwargs):
              models.UserInfo.objects.create(name='v100', age=1)
              models.UserInfo.objects.create(name="v200", age="xxx") # 報錯
              return Response("...")
      

      3 Logging日志

      什么時候用到日志?

      • 可預知的情況,寫日志
      • 不可預知情況,寫日志

      3.1 基礎(chǔ)版

      CRITICAL = 50
      FATAL = CRITICAL
      ERROR = 40
      WARNING = 30
      WARN = WARNING
      INFO = 20
      DEBUG = 10
      NOTSET = 0
      
      import logging
      
      # 1. 對日志進行配置
      logging.basicConfig(
          filename='error.log',  # 日志文件
          format='%(asctime)s :  %(message)s',  # 寫日志時,文件的格式。
          datefmt='%Y-%m-%d %H:%M:%S %p',
          level=20  # 級別,以后只有大于20的級別時,才能真正日志內(nèi)容寫入到文件中。
      )
      
      # 2.寫日志
      """
      CRITICAL = 50
      FATAL = CRITICAL
      ERROR = 40
      WARNING = 30
      WARN = WARNING
      INFO = 20
      DEBUG = 10
      NOTSET = 0
      """
      logging.debug("你好呀")  # 10,你好呀
      logging.info("中午好")  # 10,你好呀
      logging.error("你傻呀")  # 40,你傻呀
      

      image

      默認這種形式不支持在文件中寫入日志:

      import logging
      import traceback
      
      # 1. 對日志進行配置
      logging.basicConfig(
          filename='v10.log',  # 日志文件
          format='%(asctime)s :  %(message)s',  # 寫日志時,文件的格式。
          datefmt='%Y-%m-%d %H:%M:%S %p',
          level=20  # 級別,以后只有大于20的級別時,才能真正日志內(nèi)容寫入到文件中。
      )
      
      # 2. 對日志進行配置(不生效,因為已配置過后生成在內(nèi)存,不再支持設(shè)置)
      logging.basicConfig(
          filename='v100.log',  # 日志文件
          format='%(asctime)s :  %(message)s',  # 寫日志時,文件的格式。
          datefmt='%Y-%m-%d %H:%M:%S %p',
          level=20  # 級別,以后只有大于20的級別時,才能真正日志內(nèi)容寫入到文件中。
      )
      
      
      logging.error("沙雕alex")
      

      3.2 對象版(支持多文件)

      • Formatter,格式化。

      • FileHandler,維護文件,專門用于往文件中寫內(nèi)容。

      • Logger,定義級別,大于這個級別才調(diào)用 FileHandler 去寫內(nèi)容。

      • 寫日志

        logger = Logger()
        logger.error("內(nèi)容") # 10 "xxx"
        

      示例1:

      import logging
      
      # 定義 Formatter
      fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
      
      # 定義 FileHandler
      handler_object = logging.FileHandler('v2.log', 'a', encoding='utf-8')
      handler_object.setFormatter(fmt)
      
      # 定義 Logger
      logger_object = logging.Logger('s1', level=logging.INFO)  # 20
      logger_object.addHandler(handler_object)
      
      # ===>寫日志<====
      logger_object.error("alex是個大sb") # 40>20則寫入日志
      

      示例2:

      import logging
      
      # 定義 Formatter
      fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
      
      # 定義 FileHandler
      handler_object = logging.FileHandler('v2.log', 'a', encoding='utf-8')
      handler_object.setFormatter(fmt)
      
      handler_object2 = logging.FileHandler('v22.log', 'a', encoding='utf-8')
      handler_object2.setFormatter(fmt)
      
      # 定義 Logger
      logger_object = logging.Logger('s1', level=logging.INFO)  # 20
      logger_object.addHandler(handler_object)
      logger_object.addHandler(handler_object2)
      
      # 寫日志
      logger_object.error("alex是個大sb")
      

      3.3 配置版

      示例1:簡單配置

      import logging.config
      
      # 1. 定義字典
      LOGGING_CONFIG = {
          "version": 1,
          "disable_existing_loggers": True,  # 刪除已存在其他日志的Handler
          'formatters': {
              'standard': {
                  'format': '{asctime} {levelname} :{message}',
                  'style': '{',
                  "datefmt": '%Y-%m-%d %H:%M:%S %p',
              },
          },
          'handlers': {
              'console': {
                  'class': 'logging.StreamHandler',  # 寫到終端的輸出流中
                  'formatter': 'standard',  # 用到的什么格式
              },
              'demo': {
                  "class": 'logging.handlers.RotatingFileHandler',  # 寫到文件中
                  'formatter': 'standard',
                  'filename': 'demo.log',  # 日志的文件名
                  'maxBytes': 1024,  # 根據(jù)文件大小拆分日志
                  'backupCount': 30,  # 5份文件
                  "encoding": "utf-8"
              }
          },
          'loggers': {
              'nb': {
                  'handlers': ['console', 'demo'],
                  'level': "INFO",  # >=20 則觸發(fā)日志
                  'propagate': False
              }
          }
      }
      
      # 2. 根據(jù)自定對logging進行配置
      logging.config.dictConfig(LOGGING_CONFIG)
      
      # 3. 寫日志
      logger_object = logging.getLogger("nb")
      logger_object.info('6666666666')
      

      示例2:多文件配置

      import logging.config
      
      # 1. 定義字典
      LOGGING_CONFIG = {
          "version": 1,
          "disable_existing_loggers": True,  # 刪除已存在其他日志的Handler
          'formatters': {
              'standard': {
                  'format': '{asctime} {levelname} {threadName} :{message}',
                  'style': '{',
                  "datefmt": '%Y-%m-%d %H:%M:%S %p',
              },
              'simple': {
                  'format': '%(asctime)s %(levelname)s  %(message)s',
                  'style': '%',
                  "datefmt": '%Y-%m-%d',
              },
          },
          'handlers': {
              'console': {
                  'class': 'logging.StreamHandler',
                  'formatter': 'simple',
              },
              'run': {
                  # 運行日志,按天自動分割
                  "class": 'logging.handlers.TimedRotatingFileHandler',  # 基于時間
                  'formatter': 'standard',
                  'filename': "run.log",
                  'when': 'D',  # 根據(jù)天拆分日志
                  'interval': 1,  # 1天
                  'backupCount': 3,  # 保留備份
                  "encoding": "utf-8"
              },
              'error': {
                  # 錯誤日志,按照文件大小分割
                  "class": 'logging.handlers.RotatingFileHandler',
                  'formatter': 'standard',
                  'filename': 'error.log',
                  'maxBytes': 1024 * 1025 * 50,  # 根據(jù)文件大小拆分日志 50M
                  'backupCount': 5,
                  "encoding": "utf-8"
              },
          },
          'loggers': {
              'run': {
                  'handlers': ['run'],
                  'level': "INFO",  # >=20 則觸發(fā)日志
                  'propagate': True  # 觸發(fā)父級-->’root'
              },
              'error': {
                  'handlers': ['console', 'error'],
                  'level': "ERROR",  # >=20 則觸發(fā)日志
                  'propagate': False
              }
          },
          'root': {
              'handlers': ['console', ],
              'level': 'DEBUG',
              'propagate': True
          }
      }
      
      # 2. 根據(jù)自定對logging進行配置
      logging.config.dictConfig(LOGGING_CONFIG)
      
      # 3. 寫日志
      # root = logging.getLogger()
      # root.info("測試測試")
      
      # run = logging.getLogger('run')
      # run.info("測試測試")
      
      # run = logging.getLogger('error')
      # run.info("有信息了")
      # run.error("錯誤了")
      

      示例3:過濾

      import logging
      
      
      class CallbackFilter(logging.Filter):
          def __init__(self, callback):
              self.callback = callback
      
          def filter(self, record):
              if self.callback(record):
                  return True
              return False
      
      
      class DynamicFilter(logging.Filter):
          def filter(self, record):
              # record,包含了日志相關(guān)的對象 logging.LogRecord
              # print(record, type(record))
              if not record.msg:
                  return False
              return True
      
      import logging.config
      
      # 1. 定義字典
      LOGGING_CONFIG = {
          "version": 1,
          "disable_existing_loggers": True,  # 刪除已存在其他日志的Handler
          'formatters': {
              'standard': {
                  'format': '{asctime} {levelname} {threadName} :{message}',
                  'style': '{',
                  "datefmt": '%Y-%m-%d %H:%M:%S %p',
              },
              'simple': {
                  'format': '%(asctime)s %(levelname)s  %(message)s',
                  'style': '%',
                  "datefmt": '%Y-%m-%d',
              },
          },
          "filters": {
              "dy": {
                  "()": "utils.DynamicFilter"
              },
              "call": {
                  "()": "utils.CallbackFilter",
                  "callback": lambda record: len(record.msg) > 4
              }
          },
          'handlers': {
              'console': {
                  'class': 'logging.StreamHandler',
                  'formatter': 'simple',
              },
              'run': {
                  # 運行日志,按天自動分割
                  "class": 'logging.handlers.TimedRotatingFileHandler',
                  'formatter': 'standard',
                  'filters': ["dy", 'call'],
                  'filename': "run.log",
                  'when': 'D',  # 根據(jù)天拆分日志
                  'interval': 1,  # 1天
                  'backupCount': 3,  # 保留備份
                  "encoding": "utf-8"
              },
              'error': {
                  # 錯誤日志,按照文件大小分割
                  "class": 'logging.handlers.RotatingFileHandler',
                  'formatter': 'standard',
                  'filename': 'error.log',
                  'maxBytes': 1024 * 1025 * 50,  # 根據(jù)文件大小拆分日志 50M
                  'backupCount': 5,
                  "encoding": "utf-8"
              },
          },
          'loggers': {
              'run': {
                  'handlers': ['run'],
                  'level': "INFO",  # >=20 則觸發(fā)日志
                  'propagate': True
              },
              'error': {
                  'handlers': ['console', 'error'],
                  'level': "ERROR",  # >=20 則觸發(fā)日志
                  'propagate': False
              }
          },
          'root': {
              'handlers': ['console', ],
              'level': 'DEBUG',
              'propagate': True
          }
      }
      
      # 2. 根據(jù)自定對logging進行配置
      logging.config.dictConfig(LOGGING_CONFIG)
      
      # 3. 寫日志
      run = logging.getLogger('run')
      run.info("測試測xxxxx")
      

      3.4 Django

      ###########
      # LOGGING #
      ###########
      import os
      # BASE_LOG_DIR = BASE_DIR / 'log'
      BASE_LOG_DIR = os.path.join(BASE_DIR, 'log')
      BASE_LOG_DIR.mkdir(exist_ok=True)  # 文件夾不存在則創(chuàng)建,存在不創(chuàng)建
      
      # The callable to use to configure logging
      LOGGING_CONFIG = "logging.config.dictConfig"
      
      # Custom logging configuration.
      # 1. 定義字典
      LOGGING = {
          "version": 1,
          "disable_existing_loggers": False,  # 刪除已存在其他日志的Handler
          'formatters': {
              'standard': {
                  'format': '{asctime} {levelname} {threadName} :{message}',
                  'style': '{',
                  "datefmt": '%Y-%m-%d %H:%M:%S %p',
              },
              'simple': {
                  'format': '%(asctime)s %(levelname)s  %(message)s',
                  'style': '%',
                  "datefmt": '%Y-%m-%d',
              },
          },
          # "filters": {
          #     "dy": {
          #         "()": "django.utils.log.RequireDebugFalse"
          #     },
          #     "call": {
          #         "()": "django.utils.log.CallbackFilter",
          #         "callback": lambda record: len(record.msg) > 4
          #     }
          # },
          'handlers': {
              'console': {
                  'class': 'logging.StreamHandler',
                  'formatter': 'simple',
              },
              'run': {
                  # 運行日志,按天自動分割
                  "class": 'logging.handlers.TimedRotatingFileHandler',
                  'formatter': 'standard',
                  # 'filters': ["dy", 'call'],
                  'filename': os.path.join(BASE_LOG_DIR, 'run.log'),
                  'when': 'D',  # 根據(jù)天拆分日志
                  'interval': 1,  # 1天
                  'backupCount': 3,  # 保留備份
                  "encoding": "utf-8"
              },
              'error': {
                  # 錯誤日志,按照文件大小分割
                  "class": 'logging.handlers.RotatingFileHandler',
                  'formatter': 'standard',
                  'filename': os.path.join(BASE_LOG_DIR, 'error.log'),
                  'maxBytes': 1024 * 1025 * 50,  # 根據(jù)文件大小拆分日志 50M
                  'backupCount': 5,
                  "encoding": "utf-8"
              },
          },
          'loggers': {
              'run': {
                  'handlers': ['run'],
                  'level': "INFO",  # >=20 則觸發(fā)日志
                  'propagate': True
              },
              'error': {
                  'handlers': ['console', 'error'],
                  'level': "ERROR",  # >=40 則觸發(fā)日志
                  'propagate': False
              }
          },
          'root': {
              'handlers': ['console', ],
              'level': 'DEBUG',
              'propagate': True
          }
      }
      
      logger = logging.getLogger("error")
      logger.error("...")
      
      logger = logging.getLogger("run")
      logger.info("...")
      
      logger = logging.getLogger()
      logger.info("...")
      
      posted @ 2023-01-25 17:05  角角邊  Views(66)  Comments(0)    收藏  舉報
      主站蜘蛛池模板: 日韩熟女乱综合一区二区| 99精产国品一二三产品香蕉| 人妻日韩精品中文字幕| 亚洲国产性夜夜综合| 男女性杂交内射女bbwxz| 实拍女处破www免费看| 亚洲成人高清av在线| 日本xxxx色视频在线播放| 国产成人亚洲精品自产在线| 9191国语精品高清在线| 松阳县| 精品国产伦理国产无遮挡| 亚洲国产成人无码电影| 日本欧美大码a在线观看| 中国CHINA体内裑精亚洲日本| 99精品国产成人一区二区| 欧美高清狂热视频60一70| 女人爽到高潮的免费视频| 国产亚洲精品久久久久久久软件| 国产精品一区二区色综合| 久久久精品国产精品久久| 东京热一精品无码av| 国产农村激情免费专区| 人妻丝袜AV中文系列先锋影音| 少妇高潮毛片免费看| 高清国产一区二区无遮挡| 国厂精品114福利电影免费| 开心五月婷婷综合网站| 人妻系列无码专区无码中出| 漂亮人妻被强中文字幕久久 | 成年女人黄小视频| 亚洲精品综合久中文字幕| 精品人妻一区二区三区蜜臀| 中文字幕午夜福利片午夜福利片97| 成人免费视频一区二区三区| 国产嫩草精品网亚洲av| 久久精品国产99久久久古代| 日韩精品无码一区二区三区视频| 自拍日韩亚洲一区在线| 枝江市| 日韩va中文字幕无码电影|