Logger 是 asp .net core 的內置 service,因此咱們就不須要在ConfigureService裏面註冊了。同時在asp.net core 2.0版本及之後,系統已經在CreateDefaultBuilder方法裏默認配置了輸出到Console和Debug窗口的Logger。linux
.ConfigureLogging(delegate(WebHostBuilderContext hostingContext, ILoggingBuilder logging) { logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); })
因此咱們能夠Controller裏面直接注入ILoggerFactory而後再建立具體的Logger。git
private readonly ILogger _logger; public HomeController(ILoggerFactory logger) { _logger = logger.CreateLogger<HomeController>(); }
可是還有更好的方式,Container能夠直接提供一個ILogger
private readonly ILogger _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; }
而後在【Output】窗口中能夠看到輸出的日誌:web
LogDemo> info: LogDemo.Controllers.HomeController[0] LogDemo> Return Index view
Log到Debug窗口或者Console窗口仍是比較方便的,可是正式生產環境中這確定不夠用。正式環境應該Log到文件或者數據庫等。接下來試下Nlog。docker
NuGet添加 NLog.Web.AspNetCore。數據庫
<PackageReference Include="Microsoft.AspNetCore.App" />
添加配置文件json
新建一個文件nlog.config(建議所有小寫,linux系統中要注意), 並右鍵點擊其屬性,將其「複製到輸出目錄」設置爲「始終複製」。文件內容以下api
<?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\internal-nlog.txt"> <!-- enable asp.net core layout renderers --> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <!-- the targets to write to --> <targets> <!-- write logs to file --> <target xsi:type="File" name="allfile" fileName="c:\temp\nlog-all-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" /> <!-- another file log, only own logs. Uses some ASP.NET core renderers --> <target xsi:type="File" name="ownFile-web" fileName="c:\temp\nlog-own-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" /> </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" /> </rules> </nlog>
<Content Update="nlog.config"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content>
修改Program.cs文件瀏覽器
添加引用 NLog.Web 和 Microsoft.Extensions.Logging。
在 .UseStartup
.UseNLog()
。
若是要禁用默認的輸出框日誌,能夠調用
logging.ClearProviders()
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .ConfigureLogging(logging => { logging.ClearProviders(); logging.SetMinimumLevel(LogLevel.Trace); }) .UseNLog();
輸出到數據庫
除了把日誌輸出到文件以外,也能夠保存到SQL Server, PostgreSQL, MySQL, Elasticsearch等。下面是保存到SQL Server的一個示例配置:
<?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="d:\temp\logs\internal-nlog.txt"> <!-- enable asp.net core layout renderers --> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <!-- the targets to write to --> <targets> <!-- write logs to file --> <target xsi:type="File" name="allfile" fileName="d:\temp\logs\all-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" /> <target name="blackhole" xsi:type="Null" /> <target name="database" xsi:type="Database" dbProvider="System.Data.SqlClient"> <connectionString> Server=.;Database=Log;Trusted_Connection=True </connectionString> <commandText> insert into dbo.Log ( Application, Logged, Level, Message, Logger, CallSite, Exception ) values ( @Application, @Logged, @Level, @Message, @Logger, @Callsite, @Exception ); </commandText> <parameter name="@application" layout="Application" /> <parameter name="@logged" layout="${date}" /> <parameter name="@level" layout="${level}" /> <parameter name="@message" layout="url: ${aspnet-request-url} | action: ${aspnet-mvc-action} | ${message}" /> <parameter name="@logger" layout="${logger}" /> <parameter name="@callSite" layout="${callsite:filename=true}" /> <parameter name="@exception" layout="${exception:tostring}" /> </target> </targets> <!-- rules to map from logger name to target --> <rules> <!--All logs, including from Microsoft--> <logger name="*" minlevel="Info" 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="Info" writeTo="database" /> </rules> </nlog>
配置簡要說明
targets
:用於配置輸出相關內容,好比 type 屬性可選項爲File、Mail、Console等,用於設置輸出目標,layout屬性用於設置輸出信息的組成元素及格式。
rules
: 實際上是一個「路由表」,日誌是從上到下匹配的。 logger name="Microsoft." maxlevel="Info" final="true" 一句話的 final="true" 過濾掉了"Microsoft." Info級別如下的日誌。
全局異常中間件
除了輸出日誌外,能夠寫一箇中間件來處理全局的異常。
public class GlobalErrorHandlingMiddleware { private readonly RequestDelegate next; private readonly ILogger<GlobalErrorHandlingMiddleware> _logger; public GlobalErrorHandlingMiddleware(RequestDelegate next, ILogger<GlobalErrorHandlingMiddleware> logger) { this.next = next; this._logger = logger; } public async Task Invoke(HttpContext context) { try { await next(context); } catch (Exception ex) { var Request = context.Request; ///訪問路徑 string visit_url = Request.Path; ///URL 請求方法 string method = Request.Method.ToUpper(); ///URL 請求的參數 string url_paramters = string.Empty; if (method == "GET") url_paramters = Request.QueryString.Value; if (method == "POST") { foreach (var item in Request.Form) url_paramters = url_paramters + item.Key + "=" + item.Value + "&"; } ///錯識信息 string err_msg = ex.Message;//ex.StackTrace; ///日誌格式內容 var logs_msg = $"{visit_url}#{method}#{url_paramters}#{err_msg}"; _logger.LogError(logs_msg); var statusCode = context.Response.StatusCode; var msg = $"Status Code: {statusCode}, Message: {ex.Message}"; await HandleExceptionAsync(context, msg); } } private static Task HandleExceptionAsync(HttpContext context, string msg) { //var data = new Result { Title = "異常中間件返回", Msg = msg }; //var result = JsonConvert.SerializeObject(data); //context.Response.ContentType = "application/json;charset=utf-8"; return context.Response.WriteAsync(msg); } } public static class GlobalErrorHandlingMiddlewareExtensions { public static IApplicationBuilder UseGlobalErrorHandlingMiddleware( this IApplicationBuilder builder) { return builder.UseMiddleware<GlobalErrorHandlingMiddleware>(); } }
ELK簡介
ELK是三個開源軟件的縮寫,分別表示:Elasticsearch , Logstash, Kibana , 它們都是開源軟件。如今新增了一個FileBeat,它是一個輕量級的日誌收集處理工具。環境快速搭建
這裏使用docker-compose一鍵搭建ELK測試環境:請確保已經安裝Docker-compose
docker-compose --version
下載代碼從 The ELK stack powered by Docker and Compose 從並運行:
git clone https://github.com/deviantony/docker-elk.git cd docker-elk docker-compose up -d
修改nlog配置文件
<target xsi:type="Network" name="ownLog-tcp" keepConnection="false" address="tcp://IP:5000" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
啓動項目測試,進入 kibana 後臺配置並添加 index pattern。
其餘寫入Elasticsearch的方法
把日誌寫入Elasticsearch的方法能夠有多種: