本文目錄
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