一、前言 在項目開發中,日誌系統是系統的一個重要組成模塊,通過在程式中記錄運行日誌、錯誤日誌,可以讓我們對於系統的運行情況做到很好的掌控。同時,收集日誌不僅僅可以用於診斷排查錯誤,由於日誌同樣也是大量的數據,通過對這些數據進行集中分析,可以產生極大的價值。 在微服務的系統架構中,由於一個系統會被拆成 ...
一、前言
在項目開發中,日誌系統是系統的一個重要組成模塊,通過在程式中記錄運行日誌、錯誤日誌,可以讓我們對於系統的運行情況做到很好的掌控。同時,收集日誌不僅僅可以用於診斷排查錯誤,由於日誌同樣也是大量的數據,通過對這些數據進行集中分析,可以產生極大的價值。
在微服務的系統架構中,由於一個系統會被拆成很多個功能模塊,每個模塊負責不同的功能,對於日誌系統的要求也會更高,比較常見的有 EFLK(ElasticSearch + Filebeat + LogStash + Kibana) 方案,而對於我們這種單體應用來說,由於程式的代碼比較集中,所以我們主要採用手寫日誌幫助類或是使用第三方組件的形式進行日誌信息的記錄。
系列目錄地址:ASP.NET Core 項目實戰
倉儲地址:https://github.com/Lanesra712/Grapefruit.VuCore
二、Step by Step
1、為什麼選擇 NLog 和 MongoDB
在 ASP.NET Core 中,巨硬為我們提供了一個 ILogger 介面,通過 ILogger 介面,我們可以很方便的將日誌信息輸出到控制臺中,不過,在控制臺中查看日誌信息會顯得不太方便,因此,我們可以通過實現該介面或是直接使用第三方的框架來實現將日誌信息記錄到別的存儲介質中。
在 .NET Framework 時代,對於第三方的日誌框架的選擇,絕大多數童鞋首選的都會是 log4net 這一根據 Log4j 移植的日誌框架,不過,由於 log4net 目前已經接近有3年的時間沒更新了,所以就不在考慮範圍內。綜合比較下官方文檔中推薦的幾款第三方日誌框架,最終還是選擇 NLog 這一目前使用人數相對來說比較多的框架,畢竟用戶多的話,遇到什麼問題也好找資料。
通常,我們會將日誌信息記錄到 txt or log 文件中,雖然你可以通過修改日誌佈局讓日誌信息具有良好的可讀性,不過在信息多的情況下查閱時還是會顯得不太方便。因為不僅做到對於錯誤信息做到記錄,還需要記錄程式在運行時的訪問日誌,所以將日誌信息寫入到關係型資料庫中就不是特別合適了。
而 MongoDB 作為一個文檔型的 NoSQL 資料庫,相比於傳統的關係型資料庫,NoSQL 資料庫具有更好的擴展性、以及能提供更出色的性能,因此,我最終選擇將日誌信息記錄到 MongoDB 中。當然,最主要的原因還是目前在工作中有開始嘗試用 MongoDB 存儲用戶上傳的文件,在找資料的過程中看到有使用 MongoDB 存儲日誌的案例,Grapefruit.VuCore 既然作為一個學習項目,所以就要多嘗試嘗試啊。
2、安裝 MongoDB(Windows)
因為是第一次使用 MongoDB,所以我們需要提前安裝 MongoDB Server,我是直接安裝到我的開發機上(Windows 10),所以這裡只是演示如何在 Windows 上進行 MongoDB 的安裝與配置,如何在 Linux or Docker 中進行安裝配置,我將在後面的文章中進行演示。畢竟,這個項目的最終準備通過 Docker 部署到 Linux 上的,總在 Windows 上玩是不合適滴。
首先,打開 MongoDB 官網獲取到我們的安裝包下載地址(MongoDB Community Download),選擇 Server tab 後按照我們的操作系統選擇安裝包下載即可。
雙擊下載好的 msi 文件,開始安裝,這裡我選擇 Complete(完整)安裝,如果你想要指定安裝的組件和安裝的位置,你可以選擇 Custom(自定義安裝)。
在 MongoDB 之前的版本中,如果我們需要將 MongoDB Server 作為 Windows 服務,需要我們在安裝完成之後進行配置,但是從 MongoDB 4.0 開始,我們就可以在安裝期間直接配置和啟動我們的 MongoDB 作為 Windows 服務了,當我們安裝成功後就會自動啟動 MongoDB 服務。嗯,相信我,如果你上網搜索 Windows 下的 MongoDB 安裝,你會發現 90% 的文章因為是針對 MongoDB 之前版本的,都會在安裝完成之後需要你指定日誌地址、指定存儲地址,配置 Windows 服務啊,而如果你和我一樣,安裝的是 MongoDB 4.0 以上的版本,這些統統都不要,是不是很超值。
這裡勾選上 Install MongoD as a Service,當我們安裝完成後就會自動啟動 MongoDB 服務,同時,對於這裡的配置項,我們不做任何的改動。
Service Name:創建的 Windows 服務名稱,如果已經存在了,則需要更換名稱
Data Directory:存儲數據的目錄
Log Directory:存儲 MongoDB Log 日誌的目錄
點擊 Next 之後,安裝程式會詢問你是否需要安裝 MongoDB Compass,MongoDB Compass 是官方的一個可視化管理工具,畢竟總是用黑乎乎的 shell 還是不太方便的,這裡看你自己的需求,決定是否安裝這個工具。
當我們安裝完成後,MongoDB 的服務也就已經啟動了,此時,你就可以連接上你的 MongoDB Server 了,這裡我是使用 Navicat 進行連接。對於這個服務,你同樣可以在電腦管理中對這個服務進行管理。
在預設情況下,當我們安裝好 MongoDB 後是不允許遠程訪問以及不存在任何的用戶許可權的。而這些,在我們正式使用中都是需要考慮的。
首先,配置我們的 MongoDB Server 以允許用戶進行遠程訪問。找到程式安裝路徑下麵的 mongod.cfg 文件(如果你使用的是預設配置,則該文件位於 C:\Program Files\MongoDB\Server\4.0\bin),修改 bindIp 屬性值為 0.0.0.0,重啟 MongoDB 服務,確保 27017 埠外界可以訪問後,則可以遠程訪問我們的 MongoDB 服務。
當我們允許遠程訪問我們的 MongoDB 服務後,我們更應該為 MongoDB 配置許可權。與我們經常使用的 SQL Server 或是 MySQL 不同,MongoDB 中的許可權是針對每一個資料庫的,也就是說我們需要為使用到的資料庫創建用戶並配置許可權。
打開 Navicat,連接安裝好的 MongoDB 服務。
第一步將預設資料庫切換到 admin 資料庫,創建一個管理員用戶,這裡我就將管理員用戶的角色設置為 root 用戶。
//切換到 admin 資料庫 use admin //創建一個管理員用戶 db.createUser( { user: "user name", pwd: "user password", roles: [ { role: "root", db: "admin" } ] } )
當我們創建好管理員用戶後,我們就可以為資料庫配置用戶與許可權了。右擊連接名稱,新建一個資料庫 GrapefruitVuCore,切換到 GrapefruitVuCore 資料庫後,新建一個可以讀寫的用戶 grapefruit。用戶都創建完成後,關閉我們的 MongoDB 連接。
//切換到 admin 資料庫 use GrapefruitVuCore //創建一個管理員用戶 db.createUser( { user: "grapefruit", pwd: "grapefruit", roles: [ { role: "readWrite", db: "GrapefruitVuCore" } ] } )
當用戶已經創建完成之後,我們就可以修改配置文件,啟用許可權控制。還是在 mongod.cfg 中,取消 security 節點的註釋,添加授權配置,修改完成後,重啟服務,此時,MongoDB 就必須通過賬戶密碼登錄了。
當服務重啟之後,如果你還是按照之前的方式連接,則會提示你許可權不足,你需要修改 Navicat 的連接配置。將驗證方式修改成 Password,輸入賬戶、密碼,並指定需要登錄的資料庫,重新連接即可。
PS:這裡,我使用賬戶、密碼登錄進入 GrapefruitVuCore 後,右側的連接下麵是沒有顯示這個資料庫的,但這個資料庫是真實存在的,不曉得這是個啥問題。
MongoDB 內置的用戶角色許可權:
read:允許用戶讀取授權的資料庫
readWrite:允許用戶讀寫授權的資料庫
dbAdmin:允許用戶在授權的資料庫中執行管理操作,如索引創建、刪除,查看統計或訪問system.profile
userAdmin:允許用戶向 system.users 集合寫入,可以在指定資料庫里創建、刪除和管理用戶
clusterAdmin:只在 admin 資料庫中可用,賦予用戶所有分片和複製集相關函數的管理許可權。
readAnyDatabase:只在 admin 資料庫中可用,賦予用戶所有資料庫的讀許可權
readWriteAnyDatabase:只在 admin 資料庫中可用,賦予用戶所有資料庫的讀寫許可權
userAdminAnyDatabase:只在 admin 資料庫中可用,賦予用戶所有資料庫的 userAdmin 許可權
dbAdminAnyDatabase:只在 admin 資料庫中可用,賦予用戶所有資料庫的 dbAdmin 許可權。
root:只在admin資料庫中可用。超級賬號,超級許可權
3、使用 NLog 記錄日誌信息
當我們安裝配置好 MongoDB 後,有了存儲日誌信息的介質,我們就可以使用 NLog 來記錄我們的程式日誌信息了。首先,我們需要為項目中添加對於 NLog 的引用,右擊 Grapefruit.WebApi 打開管理 Nuget 程式包頁面或是使用程式包管理器控制台選中預設項目為 Grapefruit.WebApi,添加 NLog、NLog.Web.AspNetCore、NLog.Mongo。
Install-Package NLog Install-Package NLog.Web.AspNetCore Install-Package NLog.Mongo
NLog 和 NLog.Web.AspNetCore 為 ASP.NET Core 添加了對於 NLog 的平臺支持,在 NLog 中,我們可以通過繼承 NLog.Targets.TargetWithLayout 來為 NLog 添加更多的輸出介質支持,而 NLog.Mongo 就是為 NLog 添加輸出日誌信息到 MongoDB 的支持。嗯,嘗試了自己寫,一直有問題,最後還是用的別人寫好的,哈哈哈,水平太菜。
當我們添加好引用後,在 Grapefruit.WebApi 下添加一個 NLog 的配置文件 nlog.config(文件名全部需要小寫),右鍵 nlog.config,打開屬性視窗,將複製到輸出目錄修改成較新才複製或是總是複製都可以。
在配置文件中,nlog 節點必須是 xml 文件的根節點,同時包含三個主要的子節點:extensions、targets、rules。
extensions:當你不僅僅只使用 NLog 這一個基礎的 dll ,並使用了一些基於 NLog 擴展的工具時,你就需要在 extensions 節點下麵添加引用的程式集名稱。例如,這裡,我添加了 NLog.Web.AspNetCore 這個程式集從而達到 NLog 對於 ASP.NET Core 的支持,以及添加了 NLog.Mongo 這個程式集用來將日誌信息輸出到 MongoDB 中。
targets:targets 節點下包含了我們需要輸出的日誌的信息內容以及日誌信息的佈局,例如,這裡我按照日期輸出兩個文件 nlog-all-date.log 和 nlog-own-date.log,分別記錄所有的日誌信息以及我們自定義記錄的信息。因為我們是需要將日誌信息寫入 MongoDB 中的,這裡我也添加了一個子節點用來設置寫入 MongoDB 資料庫中的數據欄位。
rules:rules 節點是將需要記錄的日誌級別關聯到記錄日誌的方式上。這裡,我是將只要是 Trace 以上的都進行日誌記錄。
<?xml version="1.0" encoding="utf-8"?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="info" internalLogFile="c:\Temp\GrapefruitVuCore\internal-nlog.txt"> <!-- enable asp.net core and mongodb layout renderers --> <extensions> <add assembly="NLog.Web.AspNetCore"/> <add assembly="NLog.Mongo"/> </extensions> <!--internal-nlog:NLog啟動及載入config信息--> <!--nlog-all:所有日誌記錄信息--> <!--nlog-own:自定義日誌記錄信息--> <!-- the targets to write to --> <targets> <!-- write logs to file --> <target xsi:type="File" name="allfile" fileName="c:\Temp\GrapefruitVuCore\nlog-all-${shortdate}.log" layout="日誌記錄時間:${longdate}${newline}日誌級別:${uppercase:${level}}${newline}日誌來源:${logger}${newline}日誌信息:${message}${newline}錯誤信息:${exception:format=tostring}${newline}==============================================================${newline}" /> <!-- another file log, only own logs. Uses some ASP.NET core renderers --> <target xsi:type="File" name="ownFile-web" fileName="c:\Temp\GrapefruitVuCore\nlog-own-${shortdate}.log" layout="日誌記錄時間:${longdate}${newline}日誌級別:${uppercase:${level}}${newline}日誌來源:${logger}${newline}日誌信息:${message}${newline}錯誤信息:${exception:format=tostring}${newline}url: ${aspnet-request-url}${newline}action: ${aspnet-mvc-action}${newline}==============================================================${newline}" /> <!-- write log to mongodb--> <target xsi:type="Mongo" name="mongo" databaseName="GrapefruitVuCore" collectionName="Logs" connectionString="mongodb://grapefruit:grapefruit@localhost:27017/GrapefruitVuCore" cappedCollectionSize="26214400"> <property name="LongDate" layout="${longdate}" bsonType="DateTime" /> <property name="Level" layout="${level}" /> <property name="Logger" layout="${logger}"/> <property name="Message" layout="${message}" /> <property name="Exception" layout="${exception:format=tostring}" /> <property name="Url" layout="${aspnet-request-url}" /> <property name="Action" layout="${aspnet-mvc-action}" /> <property name="UserName" layout="${windows-identity}" /> </target> </targets> <!-- rules to map from logger name to target --> <rules> <!--All logs, including from Microsoft--> <logger name="*" minlevel="Trace" writeTo="allfile" /> <!--Skip non-critical Microsoft logs and so log only own logs--> <logger name="Microsoft.*" maxLevel="Info" final="true" /> <!-- BlackHole without writeTo --> <logger name="*" minlevel="Trace" writeTo="ownFile-web" /> <!--Add logs to mongodb--> <logger name="*" minlevel="Trace" writeTo="mongo"/> </rules> </nlog>
當我們設置好配置文件後就可以在 Program.cs 中啟用 NLog 去記錄日誌。運行我們的項目後,就可以查看記錄的日誌信息了,這裡我在 txt 文件中和 MongoDB 中都有記錄日誌信息,具體看你自己的需求了。
public class Program { public static void Main(string[] args) { //載入日誌配置信息文件後去捕獲所有的錯誤 var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger(); try { logger.Info("Init Log API Information"); CreateWebHostBuilder(args).Build().Run(); } catch (Exception ex) { logger.Error(ex, "Stop Log Information Because Of Exception"); } finally { LogManager.Shutdown(); } } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .ConfigureLogging(logging => { logging.ClearProviders();//移除其它已經註冊的日誌處理程式 logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);//記錄最小日誌級別 }) .UseNLog();//註入 NLog 服務 }
另外,在 appsettings.json 中指定的 Logging 配置會覆蓋任何對於 SetMinimumLevel 方法的調用。因此,你可以刪除配置文件中的 default 屬性,或是根據你自己的需要進行調整。
{ "Logging": { "LogLevel": { "Default": "Trace", "Microsoft": "Information" } } }
三、總結
本章主要是演示如何在 Windows 上安裝 MongoDB Server 以及在 ASP.NET Core 項目中使用 NLog 將日誌信息記錄到 MongoDB 中。在我們使用這些這些第三方開源框架時,可能會遇到很多問題,當你無法解決的時候,項目的 Issue 是個好地方,多搜搜,很大可能你就會得到解決方案。