国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Django搭建個人博客:日志記錄

Lowky / 2901人閱讀

摘要:每一條日志記錄也包含級別,代表對應消息的嚴重程度。即格式化器,主要功能是確定最終輸出的形式和內容。最好是日志能夠按自然天進行記錄和分割。

上一章學習了自動化測試,很好,現在我們可以絞盡腦汁寫出一份全面的測試,來保證代碼永遠健康了。

話雖如此,但是作為一個獨立開發者很難寫出真正全面的測試代碼。這是因為用戶在使用你的網站時可不會循規蹈矩,而是會以各種怪異的姿勢瀏覽網頁、上傳數據。但這也不是壞事,用戶就是天然的測試人員,他們會很可愛的幫你找出一大堆的bug,陪你度過難眠的夜晚(伴隨著編程能力的提升)。

現在的問題是,開發者如何得知用戶到底遇到了哪些問題?用戶們大部分都與你素昧平生,分部在世界各地。更糟糕的是,部署在線上時由于配置了DEBUG = False,出錯時并不會出現報錯頁面,連用戶自己都不清楚到底是哪里有bug。

Django給你的答案:日志

日志的組成

日志是指程序在運行過程中,對狀態、時間、錯誤等的記錄。即把運行過程中產生的信息輸出或保存起來,供開發者查閱。

Django使用Python內置的logging模塊處理日志。關于該模塊的使用,Python文檔里有非常詳細的討論。如果你從未用過,本文提供一個快速入門。

日志事件的信息流程如下:

這個圖看不懂也沒關系。以后你需要深度使用日志時,會回來仔細研究它的。

一份日志配置由LoggersHandlersFiltersFormatters四部分組成。

Loggers

Logger記錄器,是日志系統的入口。它有三個重要的工作

向應用程序(也就是你的項目)公開幾種方法,以便運行時記錄消息

根據傳遞給Logger的消息的嚴重性,確定出需要處理的消息

將需要處理的消息傳遞給所有感興趣的處理器(Handler

每一條寫入logger的消息都是一條日志記錄。每一條日志記錄也包含級別,代表對應消息的嚴重程度。常用的級別如下:

DEBUG:排查故障時使用的低級別系統信息,通常開發時使用

INFO:一般的系統信息,并不算問題

WARNING:描述系統發生的小問題的信息,但通常不影響功能

ERROR:描述系統發生的大問題的信息,可能會導致功能不正常

CRITICAL:描述系統發生嚴重問題的信息,應用程序有崩潰風險

當logger處理一條消息時,會將自己的日志級別和這條消息的日志級別做對比。如果消息的級別匹配或者高于logger的日志級別,它就會被進一步處理;否則這條消息就會被忽略掉。

當logger確定了一條消息需要處理之后,會把它傳給Handler

Handlers

Handler處理器,它的主要功能是決定如何處理logger中每一條消息,比如把消息輸出到屏幕、文件或者Email中。

和logger一樣,handler也有級別的概念。如果一條日志記錄的級別不匹配或者低于handler的日志級別,則會被handler忽略。

一個logger可以有多個handler,每一個handler可以有不同的日志級別。這樣就可以根據消息的重要性不同,來提供不同類型的輸出。例如,你可以添加一個handler把ERRORCRITICAL消息發到你的Email,再添加另一個 handler把所有的消息(包括ERRORCRITICAL消息)保存到文件里。

Filters

Filter過濾器。在日志記錄從logger傳到handler的過程中,使用Filter做額外的控制。例如只允許某個特定來源的ERROR消息輸出。

Filter還被用來在日志輸出之前對日志記錄做修改。例如當滿足一定條件時,把日志記錄從 ERROR 降到 WARNING 級別。

Filter在logger和handler中都可以添加;多個filter可以鏈接起來使用,來做多重過濾操作。

Formatters

Formatter即格式化器,主要功能是確定最終輸出的形式和內容

日志配置示例

說了這么多腦殼都說暈了,接下來看兩個示例。

簡單示例

在Django中可以通過字典的形式對整個項目的日志進行配置,配置的位置當然是在settings.py中了。一個簡單的配置如下:

my_blog/settings.py

...
import os

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "file": {
            "level": "DEBUG",
            "class": "logging.FileHandler",
            "filename": os.path.join(BASE_DIR, "logs/debug.log"),
        },
    },
    "loggers": {
        "django": {
            "handlers": ["file"],
            "level": "DEBUG",
            "propagate": True,
        },
    },
}

字典中的version指明了配置的版本;disable_existing_loggers指明是否禁止默認配置的記錄器。這兩項通常不需要去改動,重點看下loggershandlers的配置:

如前面說,一條消息首先傳遞給logger。Django中內置了幾種記錄器,比如這里用到的Django記錄器,它會接收Django層次結構中的所有消息。然后我們定義了需要處理DEBUG以上級別的消息,并把這些消息傳遞給名叫file的處理器。"propagate": True意思是本記錄器處理過的消息其他處理器也可以繼續處理。

現在消息來到名叫filehandlers中了。這個處理器定義了消息處理級別仍然為DEBUG,在class中定義將消息輸出到文件中去,文件地址為項目目錄的logs/debug.log

因為這里沒有配置filtersformatters,因此會采用默認的設置。

需要注意的是日志的輸出文件的目錄logs/一定要提前創建好,并且確保項目擁有此目錄的寫入權限。

這個日志系統就配置好了!接下來運行項目,隨便刷新幾個頁面看看debug.log中有沒有寫入消息:

logs/debug.log

(0.001) 
            SELECT name, type FROM sqlite_master
            WHERE type in ("table", "view") AND NOT name="sqlite_sequence"
            ORDER BY name; args=None
(0.000) SELECT "django_migrations"."app", "django_migrations"."name" FROM "django_migrations"; args=()
...
...
...

debug.log文件中出現了一大堆冗長的信息,因為DEBUG級別會包含所有的數據庫查詢記錄。

默認情況下,僅在調試模式下才會顯示DEBUG級別的消息日志,部署在線上時只會將INFO或以上的信息進行記錄。

再試試別的。把上面代碼中記錄器和處理器的日志級別都改為INFO

LOGGING = {
    ...
    "handlers": {
        "file": {
            "level": "INFO",
            ...
        },
    },
    "loggers": {
        "django": {
            "level": "INFO",
            ...
        },
    },
}

再刷新幾次界面,看看輸出的內容:

"GET /article/article-list/ HTTP/1.1" 200 14438
"GET /article/article-detail/32/ HTTP/1.1" 200 33364
"GET /accounts/login/ HTTP/1.1" 200 7180
...

這次清爽多了,輸出的主要是頁面的拉取信息。

讓我們再看看ERROR信息長什么樣的。在地址欄輸入一個不存在的文章詳情頁面地址:

http://127.0.0.1:8000/article/article-detail/9999/

很明顯這會得到一個數據不存在的報錯:

Internal Server Error: /article/article-detail/9999/
Traceback (most recent call last):
  File "E:django_projectenvlibsite-packagesdjangocorehandlersexception.py", line 34, in inner
    response = get_response(request)
    ...
article.models.ArticlePost.DoesNotExist: ArticlePost matching query does not exist.
"GET /article/article-detail/9999/ HTTP/1.1" 500 80792

ERROR日志輸出了整個bug的回溯,和你在瀏覽器中的報錯是完全一樣的,這些信息就非常的有用了。基本上ERROR信息能夠暴露出用戶在使用你的網站過程中的大部分問題;也就是說每一個ERROR都是需要你去解決掉的。ERROR信息的錯誤碼通常都是“500”,也就是服務器內部錯誤的代碼。

不過仔細想想,似乎找不到對應的資源在很多時候并不是bug,而是用戶在輸入url時自己犯了錯誤。所以我們把文章詳情視圖的ArticlePost.objects.get(id=id)改成get_object_or_404(ArticlePost, id=id)試試:

article/views.py

...
from django.shortcuts import get_object_or_404

def article_detail(request, id):
    # 取出相應的文章
    # article = ArticlePost.objects.get(id=id)
    article = get_object_or_404(ArticlePost, id=id)

    ...

服務器重啟后再次刷新一個不存在的頁面,看看日志:

Not Found: /article/article-detail/9999/
"GET /article/article-detail/9999/ HTTP/1.1" 404 1780

現在它不是一條ERROR信息了,而是變為了WARNING,所以也沒有了錯誤回溯(錯誤碼也由 500 變成了 404)。這里就能看出這兩個方法的重要區別了;在項目中到底選擇哪個沒有定論,還是以你的具體需求決定。

復雜示例

接下來再看一個復雜的日志配置:

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "verbose": {
            "format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
            "style": "{",
        },
        "simple": {
            "format": "{levelname} {message}",
            "style": "{",
        },
    },
    "filters": {
        "require_debug_true": {
            "()": "django.utils.log.RequireDebugTrue",
        },
    },
    "handlers": {
        "console": {
            "level": "INFO",
            "filters": ["require_debug_true"],
            "class": "logging.StreamHandler",
            "formatter": "simple"
        },
        "mail_admins": {
            "level": "ERROR",
            "class": "django.utils.log.AdminEmailHandler",
            "formatter": "verbose",
        },
        "file": {
            "level": "WARNING",
            "class": "logging.FileHandler",
            "filename": os.path.join(BASE_DIR, "logs/debug.log"),
            "formatter": "verbose",
        },
    },
    "loggers": {
        "django": {
            "handlers": ["console"],
            "propagate": True,
        },
        "django.request": {
            "handlers": ["file", "mail_admins"],
            "level": "WARNING",
            "propagate": False,
        },
    }
}

讓我們來分解一下此配置。

配置中定義了兩個格式化器

verbose:詳細的格式化器,依次輸出:消息級別、發生時間、拋出模塊、進程ID、線程ID、提示信息

simple:簡要的格式化器,僅輸出消息級別和提示信息

一個過濾器

require_debug_true:使用此過濾器的消息僅在調試時才會生效

三個處理器

console:處理INFO以上級別消息,輸出簡要信息到命令行中;此處理器僅在調試模式生效

mail_admins:處理ERROR以上級別消息,輸出詳細信息到Email中

file:處理WARNING以上級別消息,輸出詳細信息到文件中

兩個記錄器

django:將django產生的所有消息轉交給console處理器

django.request:將網絡請求相關消息轉交給filemail_admins這兩個處理器。注意這里的"propagate": False使得此記錄器處理過的消息就不再讓django記錄器再次處理了

讀者可以嘗試制造不同級別的消息,看看日志系統是否正常工作。當然最重要的,跟Email有關的配置一定要事先把Email給設置好,即下面的內容填成你的:

# SMTP服務器
EMAIL_HOST = "your smtp"
# 郵箱名
EMAIL_HOST_USER = "your email"
# 郵箱密碼
EMAIL_HOST_PASSWORD = "your password"
# 發送郵件的端口
EMAIL_PORT = 25
# 是否使用 TLS
EMAIL_USE_TLS = True
# 默認的發件人
DEFAULT_FROM_EMAIL = "your email"
日志分割

現在我們已經可以愉快的記錄日志了,接下來一個問題是如何去分割日志?假設你的網站能夠有幸運行十年時間,如果不間斷的往同一個文件中寫日志信息,最終它會變成一個拖垮服務器的龐然大物。

最好是日志能夠按自然天進行記錄和分割。好在這個問題也不需要你去費腦筋,Python幫你搞定了。

只需要把處理器稍稍改一下:

my_blog/settings.py

...
LOGGING = {
    ...
    "handlers": {
        ...
        "file": {
            ...
            # 注釋掉 class
            # "class": "logging.FileHandler",
            
            #新增內容
            "class": "logging.handlers.TimedRotatingFileHandler",
            "when": "midnight",
            "backupCount": 30,
            
        },
    },
    ...
}

TimedRotatingFileHandler:Python內置的隨時間分割日志文件的模塊

when:分割時間為凌晨

backupCount:日志文件保存日期為30天

接下來把系統時間往后調一天,然后重新啟動服務器:

python manage.py runserver --noreload

注意這次啟動有點不一樣,后面有個--noreload后綴。這是因為通常Django的調試服務器運行時會順帶啟動重載器,所以每當重載器檢測到代碼有變化后,會自動重啟服務器,相當的方便。但問題是分割文件與重載器同時操作日志文件會產生沖突,因此這里一定要用--noreload暫時將重載器禁止掉。

然后就可以愉快的刷幾條消息到文件中啦。你會發現老日志已經更名為debug.log.2019-07-17了,而剛刷的新消息則保存在debug.log中。

除了上面介紹的TimedRotatingFileHandler,Python還提供了一個按照文件大小分割的RotatingFileHandler。有興趣的看Python官方文檔
自定義日志

內置配置實際上已經能夠滿足90%以上的日志需求了,但總有時候你想在一些奇怪的地方進行記錄,這就需要你自己在代碼中插入自定義的日志記錄代碼了。

自定義日志用起來也是相當方便的:

from my_blog.settings import LOGGING
import logging

logging.config.dictConfig(LOGGING)
logger = logging.getLogger("django.request")

def whatever(request):
    # do something
    logger.warning("Something went wrong!")
    # do something else

導入剛才寫的日志框架并將django.request配置到logger對象中。然后你就可以在任何地方安插任何級別的消息了。消息內容可以用字符串的格式化方法(str.format()),玩出各種花樣。

關于日志的入門介紹就到此為止了,想深入學習的讀者請繼續閱讀本文的參考文章:

Django logging

Python 3 logging

總結

和上章類似,本章的內容也是概念偏多,希望讀者盡可能去理解,最起碼要囫圇吞棗的把日志成功移植到你的項目中去。獲取一份好的日志,有時候遠比開發一個無關緊要的新功能更重要。

比較起來博主認為對博客項目來說,日志比測試還重要,畢竟用戶的使用體驗是最佳的實踐。

但請不要誤會我的意思。測試和日志就像兩兄弟,測試解決開發中的問題,日志解決維護中的問題。有機的結合起來,你的項目才能夠長期穩定健康。


有疑問請在杜賽的個人網站留言,我會盡快回復。

或Email私信我:dusaiphoto@foxmail.com

項目完整代碼:Django_blog_tutorial

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/45179.html

相關文章

  • 使用 django-blog-zinnia 搭建個人博客

    摘要:語法支持再次打開文件,在文件的最后添加指明了使用語法標記,做了兩個拓展,其中表示支持語法高亮,包含的特性請參見相關文檔。語法高亮支持注意這一步必須在安裝完主題之后。 目前網上搭建個人博客的方案很多,雖然使用諸如 Wordpress ( PHP )、Hexo ( Node.js ) 等可以方便快速地搭建一款功能齊全的高性能個人博客,但是本文將嘗試一種更為小眾化的方案 —— 一款基于 dj...

    褰辯話 評論0 收藏0
  • Django搭建個人博客:View視圖初探

    摘要:比如,在一個博客應用中,你可能會創建如下幾個視圖博客首頁展示最近的幾項內容。這些需求都靠視圖來完成。首先寫一個最簡單的視圖函數,在瀏覽器中打印出字符串。調用函數時會返回一個含字符串的對象。換句話說,的作用是將映射到視圖中。 Django 中的視圖的概念是「一類具有相同功能和模板的網頁的集合」。比如,在一個博客應用中,你可能會創建如下幾個視圖: 博客首頁:展示最近的幾項內容。 內容詳情...

    Turbo 評論0 收藏0
  • Django搭建個人博客:編寫博客文章的Model模型

    摘要:在里寫一個數據庫驅動的應用的第一步是定義模型,也就是數據庫結構設計和附加的其它元數據。模型元數據是任何不是字段的東西,例如排序選項數據庫表名單數和復數名稱和。 Django 框架主要關注的是模型(Model)、模板(Template)和視圖(Views),稱為MTV模式。 它們各自的職責如下: 層次 職責 模型(Model),即數據存取層 處理與數據相關的所有事務: 如何存取...

    winterdawn 評論0 收藏0
  • Django搭建個人博客:設置文章的欄目

    摘要:而文章分類一個重要的途徑就是設置欄目。修改文件欄目的欄目標題創建時間文章欄目的一對多外鍵欄目的有兩個字段,名稱和創建日期。修改文章的欄目功能,也就完成了。對個人博客來說,欄目數據的變動通常是很少的。 博客的文章類型通常不止一種:有時候你會寫高深莫測的技術文章,有時候又純粹只記錄一下當天的心情。 因此對文章的分類就顯得相當的重要了,既方便博主對文章進行分類歸檔,也方便用戶有針對性的閱讀。...

    keelii 評論0 收藏0
  • Django搭建個人博客:在博文中發表評論

    摘要:確認創建成功后,記得在中注冊因為我們想顯示發表評論的時間,修改時區設置為上海的時區。處理錯誤請求發表評論僅接受請求。返回到一個適當的中即用戶發送評論后,重新定向到文章詳情頁面。總結本章實現了發表評論展示評論的功能。 在沒有互聯網的年代,我們用日記來記錄每天的心得體會。小的時候我有一個帶鎖的日記本,生怕被別人看見里面寫了啥,鑰匙藏得那叫一個絕。 現在時代變了,網絡版的日記本:博客,卻巴不...

    Jinkey 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<