簡體   English   中英

拋出未處理的異常時阻止 Microsoft 日志記錄

[英]Prevent Microsoft Logging from log when Unhandled exception thrown

我有 ASP.NET Core 3.0 網站。
我在項目上安裝了NLog ,這里是配置

public static void Main(string[] args)
{
    var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
    BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args)
{
    return WebHost.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
        })
        .UseNLog()
        .UseStartup<Startup>()
        .UseUrls("http://*:8080")
        .Build();
}



public class Startup
{
    // some constructors

    public void ConfigureServices(IServiceCollection services)
    {
        var serviceProvider = services.BuildServiceProvider();
        var logger = serviceProvider.GetService<ILogger<object>>();
        services.AddSingleton<ILogger>(logger);
    }
}

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="false"
      throwExceptions="true"
      internalLogLevel="Off">

  <extensions>
    <add assembly="NLog.Web.AspNetCore"/>
  </extensions>

  <variable name="sperator" value="-----------------------------------" />

  <targets>
    <target name="allfile"
            xsi:type="File"
            fileName="${basedir}/Logs/${date:format=yyyy-MM-dd}.log"
            archiveEvery="Day"
            archiveFileName="${basedir}/Logs/Log${shortdate}-{#}.log"
            archiveNumbering="Sequence"
            layout="eventId : ${event-properties:item=EventId_Name}${newline}${message} ${newline} ${sperator} ${newline}" />

  </targets>

  <!-- rules to map from logger name to target -->
  <rules>
    <logger name="*" minlevel="Trace" writeTo="allfile" />
  </rules>
</nlog>

appsettings.config

"Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },

最后一件事我有一個中間件來處理從應用程序中任何地方拋出的所有異常

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public ExceptionMiddleware(RequestDelegate next, ILogger logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
        context.Response.Clear();
        context.Response.ContentType = "application/json";

        var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
        if (contextFeature == null)
            return;

        string jsonResult = "";

        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        EventId eventId = new EventId(0, Guid.NewGuid().ToString());
        _logger.LogError(eventId, message: $"Date : {DateTime.Now.ToString()} \nPath : {context.Request.Path} \nStackTrace: {contextFeature.Error.ToString()}");

        jsonResult = JsonConvert.SerializeObject(new
        {
           ErrorMessage = contextFeature.Error.Message,
           StackTrace = contextFeature.Error.StackTrace
        });

        await context.Response.WriteAsync(jsonResult);
    }
}

問題是

當我拋出異常時,我會在日志文件中得到兩個日志(即使我只記錄一次)
我現在確信第一個是由 Asp.NET CORE 自動完成的,因為異常被視為未處理的異常(即使存在處理異常的中間件)

這是我得到的日志

eventId : UnhandledException
An unhandled exception has occurred while executing the request. 
 ----------------------------------- 

eventId : 88e05695-fc66-4d99-8537-aba8f0fa211b
Date : 1/1/2020 5:09:17 PM 
Path : /api/AppParameter/ThrowException 
StackTrace: System.Exception: this exception has been throw for testing the NLog
   at BT_IQM.Services.WebApi.Controllers.AppParameterController.ThrowException() in C:\Users\BitegPC\Source\Repos\BT_Backend_Architecture\BT_IQM.Services.WebApi\Controllers\AppParameterController.cs:line 80
   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.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   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.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at BT_IQM.Services.WebApi.Utility.LanguageMiddleware.Invoke(HttpContext context) in C:\Users\BitegPC\Source\Repos\BT_Backend_Architecture\BT_IQM.Services.WebApi\Utility\LanguageMiddlewareExtensions.cs:line 27
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) 
 ----------------------------------- 

第二個日志正是我在中間件中登錄的內容,但我的問題出在第一個日志中(我根本不想顯示),第二個日志對我來說就足夠了

我認為我的問題在於日志的配置(特別是在 appsettings.config 文件中)

更新

這是注冊異常中間件的擴展方法

public static class ExceptionMiddlewareExtensions
{
    public static void ConfigureExceptionHandler(this IApplicationBuilder app, ILogger logger)
    {
        app.UseExceptionHandler(appError => appError.UseMiddleware<ExceptionMiddleware>());
    }
}

這是整個配置方法

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger logger
{
    app.ConfigureExceptionHandler(logger);
    app.ConfigureLanguageMiddleware();

    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });
}

app.UseExceptionHandler(appError => appError.UseMiddleware<ExceptionMiddleware>());

好的,這里的問題是您使用的是 ASP.NET Core 附帶的ExceptionHandlerMiddleware 這個中間件負責捕獲異常,然后按照您配置它的方式處理它。

您使用它的方式是將異常處理程序應用程序管道傳遞給它,您可以在其中運行自己的中間件,然后生成結果。

現在,如果您查看ExceptionHandlerMiddleware的源代碼,那么您可以看到它最終將如何捕獲異常並調用其異常處理程序:

ExceptionDispatchInfo edi;
try
{
    var task = _next(context);
    // …
    return Task.CompletedTask;
}
catch (Exception exception)
{
    edi = ExceptionDispatchInfo.Capture(exception);
}

return HandleException(context, edi);

所以它運行中間件管道並捕獲任何異常,如果到目前為止它最終運行HandleException 這是HandleException做的第一件事:

private async Task HandleException(HttpContext context, ExceptionDispatchInfo edi)
{
    _logger.UnhandledException(edi.SourceException);
    // …

    // much later then:
    await _options.ExceptionHandler(context);

    // …
}

因此,它在進一步查看異常並最終調用配置的異常處理程序之前記錄它捕獲了未處理的異常,然后調用您的自定義中間件。

最后,您將無法阻止此日志記錄,因此您現在有三個選擇:

  1. 通過Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware過濾鍵顯式過濾掉日志。 這無需更改appsettings.json代碼即可完成。 有關詳細信息,請參閱有關日志過濾的文檔:

     "Logging": { "LogLevel": { "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None" } }
  2. 從中間件中刪除日志並僅使用現有日志。

  3. 不要將您的中間件作為ExceptionHandlerMiddleware一部分調用,而是使其成為一個普通的中間件,它本身可以捕獲異常,然后可以做任何您想做的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM