­

Django(37)配置django日誌

前言

  django框架的日誌通過python內置的logging模塊實現的,既可以記錄自定義的一些信息描述,也可以記錄系統運行中的一些對象數據,還可以記錄包括堆棧跟蹤、錯誤代碼之類的詳細信息。
  logging主要由4部分組成:LoggersHandlersFiltersFormatters
 

settings中完整的配置

如果想自定義配置日誌信息,我們可以在settings.py文件中配置,那配置的格式是怎麼樣的呢?我們可以通過from django.utils.log import DEFAULT_LOGGING查看Django中默認的日誌配置信息,然後依葫蘆畫瓢即可

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,  
    'incremental':True,
    'filters': {},
    'formatters': {},
    'handlers': {},
    'loggers': {}
}

上述是默認的日誌配置信息的格式,我們依次介紹

  • version:配置信息的版本
  • disable_existing_loggers:默認為True,True:設置已存在的logger失效。False:讓已存在的logger不失效,保證日誌信息完整。一般情況下設置為False
  • incremental:默認為False。True:是將配置解釋為現有配置的增量。False:配置會覆蓋已有默認配置。一般此項不用配置
  • filter:過濾器
  • formatters:格式器
  • handlers:處理器
  • loggers:日誌器
     

Formatters

  日誌記錄最終需要呈現為文本,formatter程序描述該文本的確切格式。formatter通常由包含LogRecord屬性的Python格式化字符串組成 ; 但是,也可以編寫自定義formatter來實現特定的格式化行為。
 

1.settings中配置:

3個參數(具體看後面的Formatter類):

  • ():指定格式器的類,不指定的話,默認使用logging.Formattr。一般用默認即可
  • format:格式化字符串
  • style:樣式選擇
  • datefmt:日期格式化字符串,使用的是python中時間日期格式化符號

案例

LOGGING = {
    'formatters': {
        'verbose': {
            '()': 'logging.Formatter',
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    }
}

配置了2個格式器:

  • simple:只輸出簡單的:日誌級別名稱 日誌消息
  • verbose:輸出:日誌級別名稱 生成日誌消息的時間 模塊 進程 線程 日誌消息
     

2.內置格式器

Formatter:默認格式器,初始化參數:fmt=None, datefmt=None, style='%'

  • fmt:格式化字符串,指定輸出格式,如:'{levelname}{process:d}{message}'
  • datefmt:日期格式化字符串,為None則使用ISO8601格式化,如:'2010-01-01 08:03:26,870'
  • style:’%’,'{‘ 或 ‘$’,3選一:
    • ‘%’:默認是這個,使用python%格式化 , 如: %(levelname)s
    • ‘{‘:使用 str.format格式化(django框架使用這個), 如:{levelname}
    • ‘$’:使用類string.Template格式化,如:\$levelname

格式化字符串的種類

%(name)s:記錄器logger的名稱
%(levelno)s:日誌級別對應的數字
%(levelname)s:日誌級別名稱
%(pathname)s:日誌記錄調用的源文件的完整路徑
%(filename)s:日誌記錄調用的源文件名
%(module)s:模塊名
%(lineno)d:日誌調用的行數
%(funcName)s:函數名
%(created)f:日誌創建時間,time.time()
%(asctime)s:日誌創建時間,文本類型
%(msecs)d:日誌創建時間的毫秒部分
%(relativeCreated)d:日誌創建時間 - 加載日誌模塊的時間 的 毫秒數
%(thread)d:線程ID
%(threadName)s:線程名
%(process)d:進程ID
%(processName)s:進程名
%(message)s:日誌消息

 

Filters

過濾器filter用於提供對日誌記錄從logger傳遞到handler的附加控制
​默認情況下,loggerhandler將處理滿足日誌級別要求的任何日誌消息,但是,通過安裝filter,可以在日誌記錄過程中添加其他條件。例如,可以安裝僅允許ERROR級別 來自特定源的消息的filter。
​filter還可用於在發出之前修改日誌記錄。例如,如果滿足一組特定條件,可以編寫一個過濾器,將ERROR日誌記錄降級為WARNING記錄。
​filter可以安裝在loggerhandler上; 可以在鏈中使用多個filter來執行多個過濾操作。
 

1.settings中配置

LOGGING = {
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
}

配置了2個過濾器

  • require_debug_false:使用類:RequireDebugFalse
  • require_debug_true:使用類:RequireDebugTrue
     

Handlers

  這個類是確定logger中消息發生的引擎程序,描述特定的日誌記錄行為,譬如控制台打印、寫入日誌文件、通過網絡進行發送等
  與logger一樣,handler也具有日誌級別,如果日誌記錄的日誌級別未達到或超過handler的級別,則handler將忽略該消息。
  一個logger可以有多個handler,每個handler可以有不同的日誌級別和記錄方法
 

1.settings中配置

4個參數(如下),加上對應class類的初始化參數

  • class(必需):處理程序類的名稱
  • level(可選的):處理程序的級別
  • formatter(可選的):處理程序的格式化程序
  • filters(可選的):處理程序的過濾器的列表
     

2.內置處理器

  1. python3的logging中的handler
    • StreamHandler:輸出到stream,未指定則使用sys.stderr輸出到控制台

    • FileHandler:繼承自StreamHandler,輸出到文件,默認情況下,文件無限增長
      初始化參數:filename,mode ='a',encoding = None,delay = False
      delay如果為True,那麼會延遲到第一次調用emit寫入數據時才打開文件

        'handlers': {
                'file': {
                    'level': 'DEBUG',
                    'class': 'logging.FileHandler',
                    'filename': '/path/to/django/app.log', #參數配置在這裡,多個參數按順序繼續配置即可, 如果要添加encoding,那麼在下面添加 encoding: 'utf-8' 即可
                },
            }
      
    • RotatingFileHandler:自動按大小切分的log文件(常用)
      初始化參數:filename,mode ='a',maxBytes = 0,backupCount = 0,encoding = None,delay = False
      maxBytes:最大位元組數,超過時創建新的日誌文件,如果backupCountmaxBytes有一個為0,那麼就一直使用一個文件
      backupCount:最大文件個數,新文件的擴展名是指定的文件後加序號”.1″等,譬如:backupCount=5,基礎文件名為:app.log,那麼達到指定maxBytes之後,會關閉文件app.log,將app.log重命名為app.log.1,如果app.log.1存在,那麼就順推,先將 app.log.1重命名為app.log.2,再將現在的app.log命名為app.log.1,最大創建到app.log.5(舊的app.log.5會被刪除),然後重新創建app.log文件進行日誌寫入,也就是永遠只會對app.log文件進行寫入。

    • TimedRotatingFileHandler:按時間自動切分的log文件,文件後綴 %Y-%m-%d_%H-%M-%S
      初始化參數:filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None
      when:時間間隔類型,不區分大小寫

        'S':秒
        'M':分鐘
        'H':小時
        'D':天
        'W0'-'W6':星期幾(0 = 星期一)
        'midnight':如果atTime未指定,則在 000秒 翻轉,否則在atTime時間翻轉
      

      interval:間隔的數值
      backupCount: 文件個數
      encoding:編碼
      delay:True是寫入文件時才打開文件,默認False,實例化時即打開文件
      utc:False則使用當地時間,True則使用UTC時間
      atTime:必須是datetime.time實例,指定文件第一次切分的時間,when設置為S,M,H,D時,該設置會被忽略

    • SMTPHandler:通過email發送日誌記錄消息
      初始化參數:mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None, timeout=5.0
      mailhost:發件人郵箱服務器地址(默認25端口)或地址和指定端口的元組,如:(‘smtp.163.com’, 25)
      fromaddr:發件人郵箱
      toaddrs:收件人郵箱列表
      subject:郵件標題
      credentials:如果郵箱服務器需要登錄,則傳遞(username, password)元組
      secure:使用TLS加密協議
       

Loggers

 

1.settings中配置

通過在settings中配置LOGGING配置項實現日誌配置,共4個配置項(都是可選的,不過一般會指定handler):

  • level:指定記錄日誌的級別,沒有配置則處理所有級別的日子
  • propagate:設置該記錄器的日誌是否傳播到父記錄器,不設置則是True
  • filters:指定過濾器列表
  • handlers:指定處理器列表

示例如下:

LOGGING = {
    'version': 1,  # 固定值,現在只有這一個版本
    'disable_existing_loggers': False, # 設置已存在的logger不失效
    'loggers': {
        '': {
            'handlers': ['console'],
        },
        'django': {
            'handlers': ['console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}

配置了4個 logger, 分別對應2個不同的handler(console輸出日誌到控制台,mail_admins輸出日誌到郵件)

  • ”:默認的記錄器,不指定特定名稱,那麼就是使用這個記錄器,沒有配置level,那麼就是處理所有級別的日誌,傳遞所有級別的日誌到console控制器
  • django:傳遞所有級別的日誌到console控制器
  • django.request:django記錄器的子記錄器,處理ERROR級別及以上的日誌,propagate設置為 False,表明不傳播日誌給 “django”,該logger傳遞日誌到mail_admins控制器
  • myproject.custom:處理INFO級別及以上的日誌,應用了一個 special 的過濾器來過濾日誌,傳遞日誌到2個控制器([‘console’, ‘mail_admins’])處理
     

注意
django框架有個默認的配置:DEFAULT_LOGGING,一旦配置了自己的LOGGING後,那麼所有的默認的LOGGER全部都失效,失效不等於沒有記錄器了,而是說記錄器不起作用了,即不會記錄日誌,也不會將日誌傳播給父記錄器。因此你應該非常小心使用,因為你會感覺你丟了日誌一樣,可以手動設置同名的logger實現覆蓋,如:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'loggers': {
        #  覆蓋了 django 記錄器,所有django的記錄日誌最後全部寫入到文件中
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

 

2.django內置的logger

  內置的logger在django項目運行中會自動記錄日誌,與我們手動創建的logger的執行沒有關係,除非我們也創建相同的logger
django框架調用的地方在:django.core.servers.basehttp中(如WSGIRequestHandler)

  • django:django框架中所有消息的記錄器,一般使用它的子記錄器,而不是它發佈消息,因為默認情況下子記錄器的日誌會傳播到根記錄器django,除非設置 ‘propagate’: False
  • django.request:記錄與請求處理相關的消息。5XX響應作為ERROR消息; 4XX響應作為WARNING消息引發。記錄到django.security記錄器的請求不會記錄到django.request

發送給此記錄器的消息具有以下額外上下文:

  • status_code:與請求關聯的HTTP響應代碼

  • request:生成日誌消息的請求對象。

  • django.server:記錄與runserver命令調用的服務器接收的請求的處理相關的消息。5XX響應記錄為ERROR 消息,4XX響應記錄為WARNING消息,其他所有響應記錄為INFO
    發送給此記錄器的消息具有以下額外上下文:

    • status_code:與請求關聯的HTTP響應代碼
    • request:生成日誌消息的請求對象。
  • django.template:記錄與模板呈現相關的消息

  • django.db.backends:記錄代碼和數據庫交互相關的消息

  • django.security.*:記錄任何SuspiciousOperation和其他安全相關錯誤(django.security.csrf )的消息

  • django.db.backends.schema:記錄數據庫遷移過程中的日誌,但是不記錄執行的查詢SQL語句等,發送給此記錄器的消息具有以下額外上下文:

    • sql:已執行的SQL語句。
    • params:SQL調用中使用的參數

 

實戰案例

如果你對以上的介紹覺得寫得很亂又複雜,沒關係,下面直接教你在項目中如何使用,基本就3種用法

  • 通過文件分割日誌
  • 通過時間分割日誌
  • 通過郵箱發送日誌
     

案例1:通過文件分割日誌

首先配置settings.py中的logging,代碼如下

BASE_LOG_DIR = os.path.join(BASE_DIR, 'log')

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,  # 設置已存在的logger不失效
    'filters': {},
    'formatters': {
        'standard': {
            'format': '[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d:%(funcName)s]:%(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
        'simple':{
            'format':'[%(asctime)s][%(levelname)s]:%(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(BASE_LOG_DIR, 'debug.log'),
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小50M
            'backupCount': 5,
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'default'],
            'level': 'INFO',
            'propagate': True
        },
    },
}

接下來在views.pyurls.py函數中寫入函數,代碼如下

# urls.py
urlpatterns = [
    path('', views.index, name="index"),
]

# views.py
logger = logging.getLogger('django')
def index(request):
    logger.debug('debug 測試')
    logger.info('info 測試')
    logger.warning('warning 測試')
    logger.error('error 測試')
    return HttpResponse('success')

然後我們訪問127.0.0.1/logging/,我們可以看到控制台的代碼

Starting development server at //127.0.0.1:8000/
Quit the server with CONTROL-C.
[2021-05-30 15:03:09][INFO]:info 測試
[2021-05-30 15:03:09][WARNING]:warning 測試
[2021-05-30 15:03:09][ERROR]:error 測試
[2021-05-30 15:03:09][INFO]:"GET /logging/ HTTP/1.1" 200 7

這是因為我們在django記錄器中配置了console控制器,格式要求也是符合我們所寫的,接着查看項目的log目錄下會新增了一個debug.log這樣一個日誌文件,文件內容如下

[2021-05-30 15:03:04][INFO][autoreload.py:578:run_with_reloader]:Watching for file changes with StatReloader
[2021-05-30 15:03:09][INFO][views.py:12:index]:info 測試
[2021-05-30 15:03:09][WARNING][views.py:13:index]:warning 測試
[2021-05-30 15:03:09][ERROR][views.py:14:index]:error 測試
[2021-05-30 15:03:09][INFO][basehttp.py:154:log_message]:"GET /logging/ HTTP/1.1" 200 7

debug.log日誌輸出格式更加詳細,這是因為我們在default控制器中,使用的standard格式器。

 
總結:以上就是我們最常用的一種日誌配置—文件日誌,當中的細節例如格式啊等等的可以自己更改
 

案例2:時間分割日誌

代碼設置如下:

'time_handler': {
      'level': 'INFO',
      'class': 'logging.handlers.TimedRotatingFileHandler',
      'filename': os.path.join(BASE_LOG_DIR, "time.log"),
      'when': 'S',
      'interval': 10,
      'backupCount': 5,
      'formatter': 'standard',
      'encoding': 'utf-8',
  }

以上設置為間隔10秒,生成一個日誌文件
 

案例3:日誌郵箱發送

代碼設置如下:

'email_handler': {
      'level': 'ERROR',
      'class': 'logging.handlers.SMTPHandler',
      'formatter': 'standard',
      'mailhost': ('smtp.163.com', 25),
      'fromaddr': 'xxxx@163.com',
      'toaddrs': ['xxx@qq.com'],
      'subject': 'test',
      'credentials': ('郵箱用戶名', '郵箱密碼'),
  },

接下來出現ERROR級別的日誌,就會發送郵件,如果你出現報錯代碼為550,那麼就是你郵箱的權限沒有開通,到郵箱的設置中開啟SMTP服務即可

Tags: