# .NetCore NLog 配置 ( 跟原生 Microsoft.Extensions.Logging 配合使用 ) ###### tags: `.NetCore` ## 套件 NLog.Web.AspNetCore ## Startup.cs ``` public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseMiddleware<ErrorHandlingMiddleware>(); // ..... } ``` ## Program.cs ``` public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .UseNLog(); ``` ## ErrorHandlingMiddleware ``` namespace App.Middleware { public class ErrorHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ErrorHandlingMiddleware> _logger; public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger) { _logger = logger; _next = next; } public async Task Invoke(HttpContext context) { try { await _next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex, _logger); } } private async Task HandleExceptionAsync(HttpContext context, Exception ex, ILogger<ErrorHandlingMiddleware> logger) { object errors = null; switch (ex) { case RestException re: logger.LogError($"REST ERROR: {ex.ToString()}"); errors = re.Errors; context.Response.StatusCode = (int)re.Code; break; case Exception e: //這樣傳 NLog.Config 配置 ${exception:format=tostring} 卻解析不出堆疊追蹤,放棄 //logger.LogError(ex, "SERVER ERROR"); logger.LogError($"SERVER ERROR: {ex.ToString()}"); errors = string.IsNullOrWhiteSpace(e.Message) ? "Error" : e.Message; context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; break; } context.Response.ContentType = "application/json"; if (errors != null) { var result = JsonConvert.SerializeObject(new { errors }); await context.Response.WriteAsync(result); } } } } ``` ## 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"> <!-- 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="LogFile" encoding="utf-8" fileName="${basedir}\LogFiles\LogFile${shortdate}.txt" layout="-----Log Start----- ${newline}${newline} [${level:uppercase=true}] ${logger} ${newline} Time: ${longdate} ${newline} Request IP: ${aspnet-request-ip} ${newline} Url: [${aspnet-request-method}] ${aspnet-request-url} ${aspnet-request-querystring} ${newline} ${message} ${newline}${exception:format=tostring}${newline}-----Log End-----${newline}" /> </targets> <!-- rules to map from logger name to target --> <rules> <!--由上到下匹配--> <!--All logs, including from Microsoft--> <!--<logger name="*" minlevel="Info" writeTo="LogFile" />--> <!--寫下 Microsoft.AspNetCore.Server 相關 Log ( Ex. 執行 Server.exe 時無法啟動的錯誤 )--> <logger name="Microsoft.AspNetCore.Server.*" minlevel="Info" final="true" writeTo="LogFile" /> <!--跳過微軟 Log,沒 writeTo ( Skip non-critical Microsoft logs )--> <logger name="Microsoft.*" minlevel="Info" final="true" /> <!--剩下的 Log 全寫這--> <logger name="*" minlevel="Info" writeTo="LogFile" /> </rules> </nlog> ``` ## 結果 ``` -----Log Start----- [ERROR] ECTransfer.Middleware.ErrorHandlingMiddleware Time: 2021-03-26 15:10:53.7105 Request IP: ::1 Url: [GET] https://localhost/Stock/TestGetStock code=C01A01601 SERVER ERROR: System.AggregateException: One or more errors occurred. (A task was canceled.) ---> System.Threading.Tasks.TaskCanceledException: A task was canceled. --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task`1.get_Result() at ECTransfer.Services.BOMDataService.SetBOMData() in C:\Users\user\Desktop\AllPower\Project\ECTransfer\ECTransfer\ECTransfer\ECTransfer\Services\BOMDataService.cs:line 32 at ECTransfer.Services.BOMDataService..ctor(HttpClient httpClient) in C:\Users\user\Desktop\AllPower\Project\ECTransfer\ECTransfer\ECTransfer\ECTransfer\Services\BOMDataService.cs:line 24 at ECTransfer.Controllers.StockController.TestGetStock(String code) in C:\Users\user\Desktop\AllPower\Project\ECTransfer\ECTransfer\ECTransfer\ECTransfer\Controllers\StockController.cs:line 168 at lambda_method(Closure , Object , Object[] ) at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatcher|8_0(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task`1 matcherTask) at ECTransfer.Middleware.ErrorHandlingMiddleware.Invoke(HttpContext context) in C:\Users\user\Desktop\AllPower\Project\ECTransfer\ECTransfer\ECTransfer\ECTransfer\MiddleWare\ErrorHandlingMiddleware.cs:line 25 -----Log End----- ```