控制台应用程序未在 AppDomain.CurrentDomain.UnhandledException 中使用 NLOG 记录错误

Console application not logging error with NLOG in AppDomain.CurrentDomain.UnhandledException

下面的代码没有记录到我的数据库。是因为控制台应用程序关闭得太快了吗?如果是,我该如何防止这种情况?

   private static ILogger _logger;

      static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e)
        {
            _logger.Error((Exception)e.ExceptionObject);
        }
    
        private static void Main(string[] args)
        {
            var container = new Container();
            _logger = container.GetInstance<ILogger>();
    AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
            throw new Exception("test");

您可以在离开 UnhandledExceptionTrapper 方法之前调用 LogManager.Shutdown()。这在内部调用 LogManager.Flush() which

Flush any pending log messages (in case of asynchronous targets) with the default timeout of 15 seconds.

参见 NSLog Flush documentation

其他疑难解答

在调试控制台中,如果连接出现 SQL 错误,则会显示错误消息,但默认情况下您不会看到是否存在无效配置。

由于 NLog 提供了广泛的配置选项,因此很容易出现导致无日志记录的小配置错误。一个典型的例子是不正确的 ConnectionStringDBProvider.

例如,假设您配置了错误的 DBProvider。

你可以打电话给

LogManager.GetCurrentClassLogger().Debug("test logging");
LogManager.Flush();

它会默默地失败。

但是,如果您插入

LogManager.ThrowExceptions = true;

在调用测试日志之前,您将在调试控制台中看到相应的消息。例如,如果您有一个无效的 DBProvider,如 Npgsql.NpgsqlConnection1, Npgsql(注意其中无效的 1),您将看到

Unhandled exception. NLog.NLogRuntimeException: Exception occurred in NLog
 ---> NLog.NLogRuntimeException: Target Database Target[nlog-db] failed to initialize.
 ---> System.TypeLoadException: Could not load type 'Npgsql.NpgsqlConnection1' from assembly 'Npgsql'.

这会清楚地指出哪里出了问题。

更多诊断

要查看更多诊断信息,您可以添加以下行:

InternalLogger.LogToConsole = true;
InternalLogger.LogLevel = LogLevel.Trace;

除其他外,您可以看到连接何时打开、写入了哪些数据以及有关刷新的信息,小示例摘录:

2022-03-11 08:47:56.8428 Trace DatabaseTarget(Name=nlog-db): Open connection.
2022-03-11 08:47:57.0275 Trace DatabaseTarget(Name=nlog-db): Executing Text: insert into "public"."log_table"(time_stamp,level,logger,message,stacktrace) values(CAST(@time_stamp AS timestamp),@level,@logger,@message,@stacktrace);
2022-03-11 08:47:57.0380 Trace   DatabaseTarget: Parameter: '@time_stamp' = '2022-03-11T08:47:56.837' (String)
2022-03-11 08:47:57.0380 Trace   DatabaseTarget: Parameter: '@level' = 'Debug' (String)
2022-03-11 08:47:57.0380 Trace   DatabaseTarget: Parameter: '@logger' = 'ConsoleDBLog.Program' (String)
2022-03-11 08:47:57.0395 Trace   DatabaseTarget: Parameter: '@message' = 'test logging' (String)
2022-03-11 08:47:57.0415 Trace   DatabaseTarget: Parameter: '@stacktrace' = '' (String)
2022-03-11 08:47:57.1099 Trace DatabaseTarget(Name=nlog-db): Finished execution, result = 1
2022-03-11 08:47:57.1111 Trace DatabaseTarget(Name=nlog-db): Close connection (KeepConnection = false).
2022-03-11 08:47:57.1167 Debug LogFactory Flush with timeout=15 secs

Self-Contained 示例

using System;
using NLog;
using NLog.Targets;

namespace ConsoleDBLog;

internal static class Program
{
    private static ILogger? _logger;

    static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e)
    {
        _logger?.Error((Exception?) e.ExceptionObject, "unhandled exception");
        LogManager.Shutdown();
    }

    private static void Main()
    {
        SetupDB_NLOG();
        _logger = LogManager.GetCurrentClassLogger();
        AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
        throw new Exception("test");
    }

    static void SetupDB_NLOG()
    {
        DatabaseTarget target = new DatabaseTarget();
        target.Name = "nlog-db";

        target.DBProvider = "Npgsql.NpgsqlConnection, Npgsql";
        target.ConnectionString = "Server=127.0.0.1;Port=5432;User Id=stephan;Password=;Database=stephan;";
        target.CommandText =
            "insert into \"public\".\"log_table\"(time_stamp,level,logger,message,stacktrace) values(CAST(@time_stamp AS timestamp),@level,@logger,@message,@stacktrace);";

        var param = new DatabaseParameterInfo
        {
            Name = "@time_stamp",
            Layout = "${date:format=yyyy-MM-ddTHH\:mm\:ss.fff}"
        };
        target.Parameters.Add(param);

        param = new DatabaseParameterInfo
        {
            Name = "@level",
            Layout = "${level}"
        };
        target.Parameters.Add(param);

        param = new DatabaseParameterInfo
        {
            Name = "@logger",
            Layout = "${logger}"
        };
        target.Parameters.Add(param);

        param = new DatabaseParameterInfo
        {
            Name = "@message",
            Layout = "${message}"
        };
        target.Parameters.Add(param);

        param = new DatabaseParameterInfo
        {
            Name = "@stacktrace",
            Layout = "${exception:format=stacktrace}"
        };
        target.Parameters.Add(param);

        NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Debug);

        //Uncomment the following lines to see things that would silently fail and
        //to get more diagnostic debug output about what is actually running.
        
        // InternalLogger.LogToConsole = true;
        // InternalLogger.LogLevel = LogLevel.Trace;
        // LogManager.ThrowExceptions = true;

        // LogManager.GetCurrentClassLogger().Debug("test logging");
        // LogManager.Flush();
    }
}

它在数据库中给出了以下条目: