繁体   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