天天看點

django 1.8 官方文檔翻譯:13-3 日志日志

日志

日志快速入門

Django 使用Python 内建的

logging

子產品列印日志。該子產品的用法在Python 本身的文檔中有詳細的讨論。如果你從來沒有使用過Python 的logging 架構(或者即使使用過),請參見下面的快速導論。

logging 的組成

Python 的logging 配置由四個部分組成:

Logger 為日志系統的入口。每個logger 是一個具名的容器,可以向它寫入需要處理的消息。

每個logger 都有一個日志級别。日志級别表示該logger 将要處理的消息的嚴重性。Python 定義以下幾種日志級别:

  • DEBUG

    :用于調試目的的底層系統資訊
  • INFO

    :普通的系統資訊
  • WARNING

    :表示出現一個較小的問題。
  • ERROR

    :表示出現一個較大的問題。
  • CRITICAL

    :表示出現一個緻命的問題。

寫入logger 的每條消息都是一個日志記錄。每個日志記錄也具有一個日志級别,它表示對應的消息的嚴重性。每個日志記錄還可以包含描述正在列印的事件的有用元資訊。這些元資訊可以包含很多細節,例如回溯棧或錯誤碼。

當給一條消息給logger 時,會将消息的日志級别與logger 的日志級别進行比較。如果消息的日志級别大于等于logger 的日志級别,該消息将會往下繼續處理。如果小于,該消息将被忽略。

Logger 一旦決定消息需要處理,它将傳遞該消息給一個Handler。

Handler 決定如何處理logger 中的每條消息。它表示一個特定的日志行為,例如将消息寫到螢幕上、寫到檔案中或者寫到網絡socket。

與logger 一樣,handler 也有一個日志級别。如果消息的日志級别小于handler 的級别,handler 将忽略該消息。

Logger 可以有多個handler,而每個handler 可以有不同的日志級别。利用這種方式,可以根據消息的重要性提供不同形式的處理。例如,你可以用一個handler 将

ERROR

CRITICAL

消息發送給一個頁面服務,而用另外一個hander 将所有的消息(包括

ERROR

CRITICAL

消息)記錄到一個檔案中用于以後進行分析。

Filter 用于對從logger 傳遞給handler 的日志記錄進行額外的控制。

預設情況下,滿足日志級别的任何消息都将被處理。通過安裝一個filter,你可以對日志處理添加額外的條件。例如,你可以安裝一個filter,隻允許處理來自特定源的

ERROR

消息。

Filters 還可以用于修改将要處理的日志記錄的優先級。例如,如果日志記錄滿足特定的條件,你可以編寫一個filter 将日志記錄從

ERROR

降為

WARNING

Filters 可以安裝在logger 上或者handler 上;多個filter 可以串聯起來實作多層filter 行為。

最後,日志記錄需要轉換成文本。Formatter 表示文本的格式。Fomatter 通常由包含

日志記錄屬性

的Python 格式字元串組成;你也可以編寫自定義的fomatter 來實作自己的格式。

使用logging

配置好logger、handler、filter 和formatter 之後,你需要在代碼中放入logging 調用。使用logging 架構非常簡單。下面是個例子:

# import the logging library
import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # Log an error message
        logger.error('Something went wrong!')
           

就是這樣!每次滿足

bad_mojo

條件,将寫入一條錯誤日志記錄。

命名logger

logging.getLogger()

調用擷取(如有必要則建立)一個logger 的執行個體。Logger 執行個體通過名字辨別。Logger 使用名稱的目的是用于辨別其配置。

Logger 的名稱習慣上通常使用

__name__

,即包含該logger 的Python 子產品的名字。這允許你基于子產品filter 和handle 日志調用。如果你想使用其它方式組織日志消息,可以提供點号分隔的名稱來辨別你的logger:

# Get an instance of a specific named logger
logger = logging.getLogger('project.interesting.stuff')
           

點号分隔的logger 名稱定義一個層級。

project.interesting

logger 被認為是

project.interesting.stuff

logger 的上一級;

project

logger 是

project.interesting

logger 的上一級。

層級為何如此重要?因為可以設定logger 傳播它們的logging 調用給它們的上一級。利用這種方式,你可以在根logger 上定義一系列的handler,并捕獲子logger 中的所有logging 調用。在

project

命名空間中定義的handler 将捕獲

project.interesting

project.interesting.stuff

logger 上的所有日志消息。

這種傳播行為可以基于每個logger 進行控制。如果你不想讓某個logger 傳播消息給它的上一級,你可以關閉這個行為。

logging 調用

Logger 執行個體為每個預設的日志級别提供一個入口方法:

  • logger.debug()

  • logger.info()

  • logger.warning()

  • logger.error()

  • logger.critical()

還有另外兩個調用:

  • logger.log()

    :列印消息時手工指定日志級别。
  • logger.exception()

    :建立一個

    ERROR

    級别日志消息,它封裝目前異常棧的幀。

配置logging

當然,隻是将logging 調用放入你的代碼中還是不夠的。你還需要配置logger、handler、filter 和formatter 來確定日志的輸出是有意義的。

Python 的logging 庫提供幾種配置logging 的技術,從程式接口到配置檔案。預設情況下,Django 使用

dictConfig 格式

為了配置logging,你需要使用

LOGGING

來定義字典形式的logging 設定。這些設定描述你的logging 設定的logger、handler、filter 和formatter,以及它們的日志等級和其它屬性。

預設情況下,

LOGGING

設定與

Django 的預設logging 配置

進行合并。

如果

LOGGING

中的

disable_existing_loggers

鍵為

True

(預設值),那麼預設配置中的所有logger 都将禁用。Logger 的禁用與删除不同;logger 仍然存在,但是将默默丢棄任何傳遞給它的資訊,也不會傳播給上一級logger。是以,你應該非常小心使用

'disable_existing_loggers': True

;它可能不是你想要的。你可以設定

disable_existing_loggers

False

,并重新定義部分或所有的預設loggers;或者你可以設定

LOGGING_CONFIG

None

,并

自己處理logging 配置

Logging 的配置屬于Django

setup()

函數的一部分。是以,你可以肯定在你的項目代碼中logger 是永遠可用的。

示例

的完整文檔是logging 字典配置最好的資訊源。但是為了讓你嘗嘗,下面是幾個例子。

首先,下面是一個簡單的配置,它将來自

django.request

logger 的所有日志請求寫入到一個本地檔案:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/path/to/django/debug.log',
        },
    },
    'loggers': {
        'django.request': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}
           

如果你使用這個示例,請確定修改

'filename'

路徑為運作Django 應用的使用者有權限寫入的一個位置。

其次,下面這個示例示範如何讓日志系統将Django 的日志列印到控制台。

django.request

django.security

不會傳播日志給上一級。它在本地開發期間可能有用。

預設情況下,這個配置隻會将

INFO

和更進階别的日志發送到控制台。Django 中這樣的日志資訊不多。可以設定環境變量

DJANGO_LOG_LEVEL=DEBUG

來看看Django 的debug 日志,它包含所有的資料庫查詢是以非常詳盡。

import os

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        },
    },
}
           

最後,下面是相當複雜的一個logging 設定:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        }
    },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers': ['null'],
            'propagate': True,
            'level': 'INFO',
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}
           

這個logging 配置完成以下事情:

  • 以‘dictConfig version 1’格式解析配置。目前為止,這是dictConfig 格式唯一的版本。
  • 定義兩個formatter:
    • simple

      ,它隻輸出日志的級别(例如,

      DEBUG

      )和日志消息。

      format

      字元串是一個普通的Python 格式化字元串,描述每行日志的細節。輸出的完整細節可以在 formatter 文檔 中找到。
    • verbose

      ,它輸出日志級别、日志消息,以及時間、程序、線程和生成日志消息的子產品。
  • 定義filter ——

    project.logging.SpecialFilter

    ,并使用别名

    special

    。如果filter 在構造時要求額外的參數,可以在filter 的配置字段中用額外的鍵提供。在這個例子中,在執行個體化

    SpecialFilter

    時,

    foo

    參數的值将使用

    bar

  • 定義三個handler:
    • null

      ,一個NullHandler,它傳遞

      DEBUG

      (和更進階)的消息給

      /dev/null

    • console

      ,一個StreamHandler,它将列印

      DEBUG

      (和更進階)的消息到stderr。這個handler 使用

      simple

      輸出格式。
    • mail_admins

      ,一個AdminEmailHandler,它将用郵件發送

      ERROR

      (和更進階)的消息到站點管理者。這個handler 使用

      special

      filter。
  • 配置三個logger:
    • django

      ,它傳遞所有

      INFO

      和更進階的消息給

      null

      handler。
    • django.request

      ERROR

      消息給

      mail_admins

      handler。另外,标記這個logger 不 向上傳播消息。這表示寫入

      django.request

      的日志資訊将不會被

      django

      logger 處理。
    • myproject.custom

      INFO

      和更進階的消息并通過

      special

      filter 的消息給兩個handler ——

      console

      mail_admins

      。這表示所有

      INFO

      (和更進階)的消息将列印到控制台上;

      ERROR

      CRITICAL

      消息還會通過郵件發送出來。

自定義logging 配置

如果你不想使用Python 的dictConfig 格式配置logger,你可以指定你自己的配置模式。

LOGGING_CONFIG

設定定義一個可調用對象,将它用來配置Django 的logger。預設情況下,它指向Python 的

logging.config.dictConfig()

函數。但是,如果你想使用不同的配置過程,你可以使用其它隻接受一個參數的可調用對象。配置logging 時,将使用

LOGGING

的内容作為參數的值。

禁用logging 配置

如果你完全不想配置logging(或者你想使用自己的方法手工配置logging),你可以設定

LOGGING_CONFIG

None

。這将禁用

Django 預設logging

的配置過程。下面的示例禁用Django 的logging 配置,然後手工配置logging:

settings.py

LOGGING_CONFIG = None

import logging.config
logging.config.dictConfig(...)
           

設定

LOGGING_CONFIG

None

隻表示禁用自動配置過程,而不是禁用logging 本身。如果你禁用配置過程,Django 仍然執行logging 調用,隻是調用的是預設定義的logging 行為。

Django’s logging extensions

Django 提供許多工具用于處理在網站伺服器環境中獨特的日志需求。

Django 提供幾個内建的logger。

django

django

是一個捕獲所有資訊的logger。消息不會直接送出給這個logger。

記錄與處理請求相關的消息。5XX 響應作為

ERROR

消息;4XX 響應作為

WARNING

這個logger 的消息具有以下額外的上下文:

  • status_code

    :請求的HTTP 響應碼。
  • request

    :生成日志資訊的請求對象。

django.db.backends

與資料庫互動的代碼相關的消息。例如,HTTP請求執行應用級别的SQL 語句将以

DEBUG

級别記錄到該logger。

  • duration

    :執行SQL 語句花費的時間。
  • sql

    :執行的SQL 語句。
  • params

    :SQL 調用中用到的參數。

由于性能原因,SQL的日志隻在

設定

之後開啟。DEBUG 設定為

True

,無論日志級别或者安裝的處理器是什麼。

這裡的日志不包含架構級别的的初始化(例如,

SET TIMEZONE

)和事務管理查詢(例如,

BEGIN

COMMIT

ROLLBACK

)。如果你希望看到所有的資料庫查詢,可以打開資料庫中的查詢日志。

django.security.*

Security logger 将收到任何出現

SuspiciousOperation

的消息。SuspiciousOperation 的每個子類型都有一個子logger。日志的級别取決于異常處理的位置。大部分情況是一個warning 日志,而如果

SuspiciousOperation

到達WSGI handler 則記錄為一個error。例如,如果請求中包含的HTTP

Host

頭部與

ALLOWED_HOSTS

不比對,Django 将傳回400 響應,同時将記錄一個error 消息到

django.security.DisallowedHost

logger。

預設情況下隻會配置

django.security

logger,其它所有的子logger 都将傳播給上一級logger。

django.security

logger 的配置與

django.request

logger 相同,任何error 消息将用郵件發送給站點管理者。由于

SuspiciousOperation

導緻400 響應的請求不會在

django.request

logger 中記錄日志,而隻在

django.security

logger 中記錄日志。

若要默默丢棄某種類型的SuspiciousOperation,你可以按照下面的示例覆寫其logger:

'loggers': {
    'django.security.DisallowedHost': {
        'handlers': ['null'],
        'propagate': False,
    },
},
           

django.db.backends.schema

New in Django 1.7.

遷移架構

執行的SQL 查詢會改變資料庫的模式時,則記錄這些SQL 查詢。注意,它不會記錄

RunPython

執行的查詢。

在Python logging 子產品提供的handler 基礎之上,Django 還提供另外一個handler。

class

AdminEmailHandler

(include_html=False, email_backend=None)

[source]

這個handler 将它收到的每個日志資訊用郵件發送給站點管理者。

如果日志記錄包含

request

屬性,該請求的完整細節都将包含在郵件中。

如果日志記錄包含棧回溯資訊,該棧回溯也将包含在郵件中。

AdminEmailHandler

include_html

參數用于控制郵件中是否包含HTML 附件,這個附件包含

DEBUG

True

時的完整網頁。若要在配置中設定這個值,可以将它包含在

django.utils.log.AdminEmailHandler

handler 的定義中,像下面這樣:

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
    }
},
           

注意,郵件中的HTML 包含完整的回溯棧,包括棧每個層級局部變量的名稱和值以及你的Django 設定。這些資訊可能非常敏感,你也許不想通過郵件發送它們。此時可以考慮使用類似

Sentry

這樣的東西,回溯棧的完整資訊和安全資訊不會 通過郵件發送。你還可以從錯誤報告中顯式過濾掉特定的敏感資訊 —— 更多資訊參見

過濾錯誤報告

通過設定

AdminEmailHandler

email_backend

參數,可以覆寫handler 使用的

email backend

,像這樣:

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'email_backend': 'django.core.mail.backends.filebased.EmailBackend',
    }
},
           

預設情況下,将使用

EMAIL_BACKEND

中指定的郵件後端。

send_mail

(subject, message, *args, **kwargs)

New in Django 1.8.

發送郵件給管理者使用者。若要自定它的行為,可以子類化

AdminEmailHandler

類并覆寫這個方法。

在Python logging 子產品提供的過濾器的基礎之上,Django 還提供兩個過濾器。

CallbackFilter

(callback)

這個過濾器接受一個回調函數(它接受一個單一參數,也就是要記錄的東西),并且對每個傳遞給過濾器的記錄調用它。如果回調函數傳回False,将不會進行記錄的處理。

例如,要從admin郵件中過濾掉

UnreadablePostError

(隻在使用者取消上傳時産生),你可以建立一個過濾器函數:

from django.http import UnreadablePostError

def skip_unreadable_post(record):
    if record.exc_info:
        exc_type, exc_value = record.exc_info[:2]
        if isinstance(exc_value, UnreadablePostError):
            return False
    return True
           

然後把它添加到logger的配置中:

'filters': {
    'skip_unreadable_posts': {
        '()': 'django.utils.log.CallbackFilter',
        'callback': skip_unreadable_post,
    }
},
'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'filters': ['skip_unreadable_posts'],
        'class': 'django.utils.log.AdminEmailHandler'
    }
},
           

RequireDebugFalse

這個過濾器隻在設定後傳遞記錄。DEBUG 為 False。

這個過濾器遵循

LOGGING

預設的配置,以確定

AdminEmailHandler

隻在

DEBUG

False

的時候發送錯誤郵件。

'filters': {
    'require_debug_false': {
        '()': 'django.utils.log.RequireDebugFalse',
    }
},
'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'filters': ['require_debug_false'],
        'class': 'django.utils.log.AdminEmailHandler'
    }
},
           

RequireDebugTrue

這個過濾器類似于

RequireDebugFalse

,除了記錄隻在

DEBUG

True

時傳遞的情況。

Django’s default logging configuration

預設情況下,Django 的logging 配置如下:

DEBUG

True

時:

  • django

    的全局logger會向控制台發送級别等于或進階

    INFO

    的所有消息。Django在這個時候并不會做任何日志調用(所有在

    DEBUG

    級别上的日志,或者被

    django.request

    django.security

    處理的日志)。
  • py.warnings

    logger,它處理來自

    warnings.warn()

    的消息,會向控制台發送消息。

DEBUG

False

  • django.request

    django.security

    loggers 向

    AdminEmailHandler

    發送帶有

    ERROR

    CRITICAL

    級别的消息。這些logger 會忽略任何級别等于或小于

    WARNING

    的資訊,被記錄的日志不會傳遞給其他logger(它們不會傳遞給

    django

    的全局 logger,即使

    DEBUG

    True

    )。

另見

配置日志

來了解如何補充或者替換預設的日志配置。

譯者: Django 文檔協作翻譯小組 ,原文: Logging 本文以 CC BY-NC-SA 3.0 協定釋出,轉載請保留作者署名和文章出處。 人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。