【问题标题】:16,000 SqlExceptions logged in two minutes from one user一位用户在两分钟内记录了 16,000 个 SqlExceptions
【发布时间】:2013-08-28 17:46:41
【问题描述】:

我通过处理System.Windows.Forms.Application.ThreadException 创建了一个异常记录系统。我对我的日志记录的可靠性相当有信心,但这让我想知道是什么原因造成的。此外,当服务器速度如此之慢导致超时时,有多少Exceptions可以登录到服务器上。

基本上,当我们的 SQL 服务器在一天中进行导入过程时,用户收到 SqlExceptionsException.Message 的“超时已过期。超时时间在完成之前已过操作或服务器没有响应”。现在,在此期间记录的大多数异常都正常间隔,但在 3 个不同的日子里,一位客户在几分钟内记录了数千条 SqlException

所以我问:

  1. 日志记录代码是否是导致记录如此多异常的罪魁祸首
  2. 如果System.Data.SqlClient 在幕后有任何东西可以产生这么多,以及是否有任何配置可以防止这种情况发生。
  3. 如果事件处理中有任何可能导致事件被重发这么多次。

日志记录函数的调用是一条直线,这让我相信它实际上捕获了数千个异常,尽管我无法理解会生成多少个异常。

但是,记录器中有一个后备循环,我想知道这是否是原因。虽然在我的测试中,在异常处理程序中未捕获的异常会导致程序崩溃,所以我在异常处理期间看不到异常,然后自己处理和记录。此外,21.5k 总堆栈跟踪中没有一个表明处理程序中发生了异常。

这是记录器本身的代码:(请注意,tries 和相关逻辑是新添加的,以防止潜在的无限循环)

    ''' <summary>
    ''' Tries to log an Exception to the database.
    ''' </summary>
    ''' <param name="out">The results of Exception handling</param>
    ''' <param name="ex">The Exception to log.</param>
    ''' <param name="customMessage">A custom message to append to the Exception's message when logging to DB.</param>
    Private Shared Sub LogException(ByVal out As ExceptionLogOutcome, ByVal ex As Exception, Optional ByVal customMessage As String = "", Optional ByVal priority As ExceptionDE.Priority = ExceptionDE.Priority.Medium)
        If ex IsNot Nothing Then

            out.ExceptionDataEntity = New DataEntity.ExceptionDE(ex, priority, CurrentBatchAuditDate, CurrentMachineID, CurrentBatchID, CurrentDocNum, CurrentTransactionID, CurrentUser)

            If customMessage.Length > 0 Then
                out.ExceptionDataEntity.Message &= " NOTE: " & customMessage
            End If

            Dim retry As Boolean = False
            Dim tries As Integer = 0
            Do
                Try
                    DataAccess.LoggerDAO.CreateExceptionLog(out.ExceptionDataEntity)
                Catch exc As SqlClient.SqlException
                    retry = MsgBox(String.Format("An error occured while logging an exception in the program.  Retry?"), MsgBoxStyle.RetryCancel) = MsgBoxResult.Retry

                    If Not retry Then
                        'Failure logging
                        out.WasLogged = False
                        Return
                    End If
                Catch exc As Exception
                    out.LoggingException = exc
                    out.WasLogged = False
                    Return
                End Try
            Loop While retry And tries < 10
        Else
            'Ex is nothing
            out.WasLogged = False
            Return
        End If

        out.WasLogged = True
        Return
    End Sub

但是,进一步导致我排除我自己的代码是问题的原因是,我在 21.5k 重复记录的 SqlExceptions 上做了一个不同的选择,并且只返回了 4 个唯一的堆栈跟踪,没有一个表明发生了异常在处理期间,并且在任何类型的循环中都没有。 2 个在触发 Sql 查询代码的Keydown 处理程序中,一个在触发查询的Load 处理程序中,一个在Click 事件中。

这是两个堆栈跟踪,客户端代码 FWIW 除外:

at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
at System.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(Boolean encrypt, Boolean trustServerCert, Boolean& marsCapable)
at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, SqlConnection owningObject)
at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnection owningObject)
at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(String host, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, Int64 timerStart)
at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Open()

还有#2

at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.ReadBuffer()
at System.Data.SqlClient.TdsParserStateObject.ReadByte()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()   

【问题讨论】:

    标签: sql-server vb.net logging exception-handling sqlclient


    【解决方案1】:

    我将在这里冒险,看看这是否可能是问题所在。

    1. 您永远不会增加重试计数器。 (这可能不是主要问题)

    2. 如果有人按下重试,重试值设置为真。此值永远不会再次设置为 false。因此,如果第二次重试成功,它将无限循环,直到失败,用户可以选择取消。

    【讨论】:

    • 天哪,逻辑失败。这是#2。
    • 我为您实际提供了正确的错误代码而喝彩:)
    • 好吧,我几乎排除了它,这是最糟糕的部分。但我想,以防万一,特别是因为它是链条中唯一带有循环的部分。最有趣的部分是用户必须让程序在沙漏上停留 2 分钟,同时它会喷出 DB 条目。
    • 你应该庆幸他没有继续重试。那么他还是会坐在那里。 :D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多