Asp.Net Core 2.0 項目實戰(9) 日誌記錄,基於Nlog或Microsoft.Extensions.Logging的實現及調用實例

Asp.Net Core 2.0 項目實戰(1) NCMVC開源下載了html

Asp.Net Core 2.0 項目實戰(2)NCMVC一個基於Net Core2.0搭建的角色權限管理開發框架前端

Asp.Net Core 2.0 項目實戰(3)NCMVC角色權限管理前端UI預覽及下載linux

Asp.Net Core 2.0 項目實戰(4)ADO.NET操做數據庫封裝、 EF Core操做及實例web

Asp.Net Core 2.0 項目實戰(5)Memcached踩坑,基於EnyimMemcachedCore整理MemcachedHelper幫助類。ajax

Asp.Net Core 2.0 項目實戰(6)Redis配置、封裝幫助類RedisHelper及使用實例數據庫

Asp.Net Core 2.0 項目實戰(7)MD5加密、AES&DES對稱加解密json

Asp.Net Core 2.0 項目實戰(8)Core下緩存操做、序列化操做、JSON操做等Helper集合類緩存

Asp.Net Core 2.0 項目實戰(9) 日誌記錄,基於Nlog或Microsoft.Extensions.Logging的實現及調用實例服務器

Asp.Net Core 2.0 項目實戰(10) 基於cookie登陸受權認證並實現前臺會員、後臺管理員同時登陸cookie

Asp.Net Core 2.0 項目實戰(11) 基於OnActionExecuting全局過濾器,頁面操做權限過濾控制到按鈕級

本文目錄
1. Net下日誌記錄
2. NLog的使用
    2.1 添加nuget引用NLog.Web.AspNetCore
    2.2 配置文件設置
    2.3 依賴配置及調用
    2.4 日誌類型介紹
    2.5 產生的日誌文件
3. 基於Microsoft.Extensions.Logging封裝
    3.1 添加引用Microsoft.Extensions.Logging
    3.2 實現咱們的Logger
    3.3 調用WLogger
2018-03-28 補充

4. 總結

1.  Net下日誌記錄

  Net Freamwork框架下在日誌記錄框架有不少,常見的有NLog、Log4Net、Loggr和內置 Microsoft.Diagnostics.Trace/Debug/TraceSource等。Asp.Net Core 2.0下大部分框架已不支持,Microsoft提供Microsoft.Extensions.Logging供你們實現本身的記錄日誌框架。如今筆者瞭解到的NLog已支持Net Core,下面咱們介紹下nlog在項目中的使用以及基於Microsoft.Extensions.Logging封裝本身的日誌記錄類。

1.  NLog的使用

  2.1添加nuget引用NLog.Web.AspNetCore

  

  2.2配置文件設置

    在Asp.Net Core 2.0項目實戰項目中,咱們把配置文件統一放在configs文件夾中,方便管理。讀取時用Path.Combine("configs", "nlog.config")便可。下面是nlog.config的配置。

<?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="Warn"
      internalLogFile="internal-nlog.txt">

  <!--define various log targets-->
  <targets>
    <!--write logs to file-->
    <target xsi:type="File" name="allfile" fileName="nlog-all-${shortdate}.log"
                 layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
    <target xsi:type="File" name="ownFile-web" fileName="nlog-my-${shortdate}.log"
                 layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
    <target xsi:type="Null" name="blackhole" />
  </targets>

  <rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />

    <!--Skip Microsoft logs and so log only own logs-->
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>

</nlog>
nlog.config

  2.3依賴配置及調用

    在startup.cs中配置日誌工廠,添加使用的服務配置後在項目中就能夠調用。

 

     /// <summary>
        /// 配置
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddNLog();//添加NLog  
            //讀取Nlog配置文件,這裏若是是小寫,文件也必定是小寫,不然linux下不識別  
            env.ConfigureNLog(Path.Combine("configs", "nlog.config"));
    }

 

     nlog調用,如在Controller中調用,如:在HomeController中

  2.4 日誌類型介紹

public enum LogLevel
{
  Debug = 1,
  Verbose = 2,
  Information = 3,
  Warning = 4,
  Error = 5,
  Critical = 6,
  None = int.MaxValue
}

  2.5產生的日誌文件

    日誌的位置默認是在bin\Debug\netcoreapp2.0下面

 

    日誌文件內容根據文件名能夠很方便的區分開,其中nlog-all包含的內比較多,nlog-my中就只包含了咱們記錄日誌的內容,你們動手試一下。

 

3.基於Microsoft.Extensions.Logging封裝

  因爲受老項目webform影響,記錄日誌是在第三方類庫dll中封裝好了幫助類,這樣在能夠在項目中任何位置方便調用,這裏個人nc.common工具庫WLogger基於Microsoft NET Core的日誌模型主要由三個核心對象構成,它們分別是Logger、LoggerProvider和LoggerFactory。如今只實現了文件記錄日誌txt,數據庫模式有業務需求的朋友可本身擴展。

 

  3.1添加引用Microsoft.Extensions.Logging

    擴展微軟日誌記錄框架,集成一個本身的Logger,如今擴展的是txt形式,後續可參考完善數據庫模式。添加引用dll後,增長配置文件並配置,這裏我先加在appsettings.json文件中,主要是配置是否開啓日誌和日誌記錄。

 

 

  3.2 實現咱們的Logger

    首先實現日誌工廠的擴展LoggerFactoryExtensions,爲net core 依賴注入LoggerFactory擴張一個方法,提供增長日誌寫文件方式的入口。

using Microsoft.Extensions.Logging;

namespace NC.Common
{
    public static class LoggerFactoryExtensions
    {
        public static ILoggerFactory AddFileLogger(this ILoggerFactory factory)
        {
            factory.AddProvider(new FileLoggerProvider());
            return factory;
        }
    }
}
LoggerFactoryExtensions

    而後實現ILoggerProvider接口,FileLoggerProvider提供程序真正具備日誌寫入功能的Logger。

using Microsoft.Extensions.Logging;

namespace NC.Common
{
    public class FileLoggerProvider : ILoggerProvider
    {
        /// <summary>
        /// 默認構造函數,根據Provider進此構造函數
        /// </summary>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public ILogger CreateLogger(string categoryName)
        {
            return new FileLogger(categoryName);
        }

        public void Dispose()
        {
        }
    }
}
FileLoggerProvider

    最後實現ILogger接口FileLogger繼承並進行封裝,方便寫入文本日誌。

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace NC.Common
{
    public class FileLogger : ILogger
    {
        private string name;
        private bool IsOpen;
        private string WPath;
        
        public FileLogger(string _name)
        {
            name = _name;
        }
        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }
        /// <summary>
        /// 是否禁用
        /// </summary>
        /// <param name="logLevel"></param>
        /// <returns></returns>
        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }
        /// <summary>
        /// 實現接口ILogger
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <param name="logLevel"></param>
        /// <param name="eventId"></param>
        /// <param name="state"></param>
        /// <param name="exception"></param>
        /// <param name="formatter"></param>
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            IsOpen = UtilConf.GetSection("WLogger")["IsOpen"] == "true" ? true : false;
            if (IsOpen)
            {
                //獲取日誌信息
                var message = formatter?.Invoke(state, exception);
                //日誌寫入文件
                LogToFile(logLevel, message);
            }
        }

        /// <summary>
        /// 記錄日誌
        /// </summary>
        /// <param name="level">等級</param>
        /// <param name="message">日誌內容</param>
        private void LogToFile(LogLevel level, string message)
        {
            var filename = GetFilename();
            var logContent = GetLogContent(level, message);
            File.AppendAllLines(filename, new List<string> { logContent }, Encoding.UTF8);
        }
        /// <summary>
        /// 獲取日誌內容
        /// </summary>
        /// <param name="level">等級</param>
        /// <param name="message">日誌內容</param>
        /// <returns></returns>
        private string GetLogContent(LogLevel level, string message)
        {
            return $"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.h3")}]{level}|{name}|{message}";
        }

        private string DirectorySeparatorChar = Path.DirectorySeparatorChar.ToString();//目錄分隔符
        /// <summary>
        /// 獲取文件名
        /// </summary>
        private string GetFilename()
        {
            var dir = "";
            WPath = UtilConf.GetSection("WLogger")["WPath"];
            if (WPath.IndexOf(":") > -1)
            {
                dir = WPath;
            }
            else
            {
                //此方法不是真正的獲取應用程序的當前方法,而是執行dotnet命令所在目錄
                dir = Directory.GetCurrentDirectory() + WPath;
                
            }
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            var result = $"{dir}/WLog-{DateTime.Now.ToString("yyyy-MM-dd")}.txt".Replace("/",DirectorySeparatorChar);

            return result;
        }
    }
}
FileLogger

  3.3 調用WLogger

    在nc.common類庫中封裝好logger實現後,在調用鏈接使用數據庫在core類庫中調用實例以下。

    首先咱們先作一下封裝調用類

 

using Microsoft.Extensions.Logging;

namespace NC.Common
{
    public class UtilLogger<T>
    {
        private static ILogger iLog;
        public static ILogger Log
        {
            get
            {
                if (iLog != null) return iLog;

                ////第一種寫法
                //ILoggerFactory loggerFactory = new LoggerFactory();
                //loggerFactory.AddFileLogger();
                //iLog = loggerFactory.CreateLogger<DbCommand>();

                //第二種寫法
                iLog = new LoggerFactory().AddFileLogger().CreateLogger<T>();
                return iLog;
            }
            set => iLog = value;
        }
    }
}

    而後在DbCommand中調用就能夠直接寫成:

      public static ILogger Log = UtilLogger<DbCommand>.Log;//日誌記錄

      Log. LogInformation(string);

      Log.LogError(string)

    詳細方法還能夠參考

 

2018-03-28補充:

  日誌記錄與全局錯誤處理結合,首先建立全局錯誤過濾類HttpGlobalExceptionFilter並在startup.cs中ConfigureServices方法下添加

services.AddMvc(options =>
            {
                options.Filters.Add(typeof(HttpGlobalExceptionFilter));//全局錯誤過濾日誌
            }).AddControllersAsServices();

  而後實現OnException方法並記錄日誌,這樣系統只要報異常,日誌 就會被記錄下來。

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using NC.Common;

namespace NC.MVC
{
    /// <summary>
    /// 錯誤處理類
    /// </summary>
    public class HttpGlobalExceptionFilter : IExceptionFilter
    {
        private readonly IHostingEnvironment _env;
        public static ILogger Log = UtilLogger<HttpGlobalExceptionFilter>.Log;//日誌記錄

        public HttpGlobalExceptionFilter(IHostingEnvironment env)
        {
            this._env = env;
        }

        public ContentResult FailedMsg(string msg = null)
        {
            string retResult = "{\"status\":" + JHEnums.ResultStatus.Failed + ",\"msg\":\"" + msg + "\"}";//, msg);
            string json = JsonHelper.ObjectToJSON(retResult);
            return new ContentResult() { Content = json };
        }
        public void OnException(ExceptionContext filterContext)
        {
            if (filterContext.ExceptionHandled)
                return;

            //執行過程出現未處理異常
            Exception ex = filterContext.Exception;
#if DEBUG
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                string msg = null;

                if (ex is Exception)
                {
                    msg = ex.Message;
                    filterContext.Result = this.FailedMsg(msg);
                    filterContext.ExceptionHandled = true;
                    return;
                }
            }

            this.LogException(filterContext);
            return;
#endif
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                string msg = null;

                if (ex is Exception)
                {
                    msg = ex.Message;
                }
                else
                {
                    this.LogException(filterContext);
                    msg = "服務器錯誤";
                }

                filterContext.Result = this.FailedMsg(msg);
                filterContext.ExceptionHandled = true;
                return;
            }
            else
            {
                //對於非 ajax 請求
                this.LogException(filterContext);
                return;
            }
        }
        /// <summary>
        /// 記錄日誌
        /// </summary>
        /// <param name="filterContext"></param>
        private void LogException(ExceptionContext filterContext)
        {
            string mid = filterContext.HttpContext.Request.Query["mid"];//codding 後續完善每一個action帶一個id
            var areaName = (filterContext.RouteData.DataTokens["area"] == null ? "" : filterContext.RouteData.DataTokens["area"]).ToString().ToLower();
            var controllerName = (filterContext.RouteData.Values["controller"]).ToString().ToLower();
            var actionName = (filterContext.RouteData.Values["action"]).ToString().ToLower();

            #region --記錄日誌 codding 後續增長自定義字段的日誌。如:記錄Controller/action,模塊ID等--
            Log.LogError(filterContext.Exception, "全局錯誤:areaName:" + areaName + ",controllerName:" + controllerName + ",action:" + actionName);
            #endregion
        }
    }
}
HttpGlobalExceptionFilter

 

 

4.總結

  無論是生產環境仍是開發環境,總會碰到這樣或那樣的問題,這時日誌記錄就爲咱們提供了記錄分析問題的便利性,net core 2.0下記錄日誌功能是最須要咱們及時實現的功能,這樣爲咱們接下來的學習提供技術支撐。另外net core 生態還不完善,不少功能須要咱們本身動手去實現,在這裏但願你們多動手去實現去分享,文中有不清楚或有問題歡迎留言討論。

參考:

https://msdn.microsoft.com/magazine/mt694089

https://www.cnblogs.com/artech/p/inside-net-core-logging-2.html

http://www.javashuo.com/article/p-clhsmmzu-kq.html

相關文章
相關標籤/搜索