---
# System prepended metadata

title: .NetCore NLog 配置 ( 跟原生 Microsoft.Extensions.Logging 配合使用 )
tags: [.NetCore]

---

# .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-----
```