1. 程式人生 > >ASP.NET Core 實戰:使用 NLog 將日誌信息記錄到 MongoDB

ASP.NET Core 實戰:使用 NLog 將日誌信息記錄到 MongoDB

uil cfg init com shutdown 右鍵 重新 系統 文件的

  在項目開發中,日誌系統是系統的一個重要組成模塊,通過在程序中記錄運行日誌、錯誤日誌,可以讓我們對於系統的運行情況做到很好的掌控。同時,收集日誌不僅僅可以用於診斷排查錯誤,由於日誌同樣也是大量的數據,通過對這些數據進行集中分析,可以產生極大的價值。
  
  在微服務的系統架構中,由於一個系統會被拆成很多個功能模塊,每個模塊負責不同的功能,對於日誌系統的要求也會更高,比較常見的有 EFLK(ElasticSearch + Filebeat + LogStash + Kibana) 方案,而對於我們這種單體應用來說,由於程序的代碼比較集中,所以我們主要采用手寫日誌幫助類或是使用第三方組件的形式進行日誌信息的記錄。
  
  系列目錄地址:ASP.NET Core 項目實戰
  
  二、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.dasheng178.com /schemas/NLog.xsd"
  
  xmlns:xsi="http://www.michenggw.com /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=www.tongqt178.com"NLog.Web.AspNetCore"/>
  
  <add assembly="NLog.Mongo"www.meiwanyule.cn/>
  
  </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 是個好地方,多搜搜,很大可能你就會得到解決方案。

ASP.NET Core 實戰:使用 NLog 將日誌信息記錄到 MongoDB