星期六, 6月 18, 2022

[C#] NLog - 偵錯

[C#] NLog - DatabaseTarget 測試呼叫 Store Procedure 時,Exception 資料一直沒有 insert 進 DB,一查發現原來 NLog 為了不影響主程式運作,預設是不會拋出任何 Exception

要讓 NLog 可以拋出 Exception 必須設定 ThrowExceptions 屬性、如要輸出錯誤訊息至檔案可以透過 InternalLogger 來做到

InternalLogger.LogFile

InternalLogger.LogFile 是 NLog Exception 的檔案路徑,但並不是全部的 Layout Renderers 都支援,看 官方文章 - Internal Logging 介紹,從 NLog4.6 開始才開始逐漸可以使用

模擬 NLog 內發生錯誤
using NLog;
using NLog.Common;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using System;
using System.Data;

namespace NLogSample
{
    internal class Program
    {
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        static void Main(string[] args)
        {
            ExceptionThrowConfig();

            try
            {
                ExceptionMethod();
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        private static void ExceptionMethod()
        {
            int numerator = 1;
            int denominator = 0;
            Console.WriteLine(numerator / denominator);
        }

        private static void ExceptionThrowConfig()
        {
            InternalLogger.LogFile = @"d:\Logs\InternalLog.txt";
            InternalLogger.LogLevel = LogLevel.Error;
            LogManager.ThrowExceptions = true;

            DatabaseTarget target = new DatabaseTarget();

            target.ConnectionString = "Data Source=.;Initial Catalog=AdventureWorks2019;Integrated Security=True";

            // 錯誤的呼叫 Store Procedure 方式
            target.CommandType = CommandType.StoredProcedure;
            target.CommandText = "exec uspLogInsert @LogTime , @Message";

            target.Parameters.Add(new DatabaseParameterInfo() { Name = "@LogTime", Layout = "${date}" });
            target.Parameters.Add(new DatabaseParameterInfo("@Message", new SimpleLayout("${exception}")));

            SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Trace);
        }
    }
}

關鍵錯誤訊息,這樣呼叫 Store Procedure 是錯誤的
2022-06-15 22:51:55.7917 Error DatabaseTarget([unnamed]): Error when writing to database. Exception: System.Data.SqlClient.SqlException (0x80131904): 找不到預存程序 'exec uspLogInsert @LogTime , @Message'。
完整錯誤訊息
2022-06-15 22:51:55.7917 Error DatabaseTarget([unnamed]): Error when writing to database. Exception: System.Data.SqlClient.SqlException (0x80131904): 找不到預存程序 'exec uspLogInsert @LogTime , @Message'。
   於 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   於 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   於 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   於 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   於 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   於 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   於 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   於 System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   於 System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   於 NLog.Targets.DatabaseTarget.ExecuteDbCommandWithParameters(LogEventInfo logEvent, IDbConnection dbConnection, IDbTransaction dbTransaction)
   於 NLog.Targets.DatabaseTarget.WriteLogEventSuppressTransactionScope(LogEventInfo logEvent, String connectionString)
ClientConnectionId:404d03a2-984b-4b6e-81bf-ad66fb425678
Error Number:2812,State:62,Class:16

沒有留言:

張貼留言