Hi Georg (and others),

Thanks a lot for that code snippet. I used it as a starting point and made a 
few modifications. Instead of constantly trying to reconnect on each logging 
call (which would block the calling application), I added a new parameter 
"retryDelaySeconds". This will wait X number of seconds before trying the next 
reconnect. Any logging attempts within this window will be ignored. I've pasted 
my SendBuffer() function and a DatabaseReconnect() helper. I'd appreciate 
anyone taking a look and letting me know what they think.

Thanks,
Simon.

PS. Sorry for the multiple return statements :0


                /// <summary>
                /// Inserts the events into the database.
                /// </summary>
                /// <param name="events">The events to insert into the 
database.</param>
                override protected void SendBuffer(LoggingEvent[] events)
                {
                        //if the delay to retry reconnect has not passed, then 
quit function. All events will be lost
                        if (m_blnReconnectOnError && 
(m_dtLastConnectFailure.AddSeconds(m_intRetryDelaySeconds) > DateTime.Now))
                        {
                                ErrorHandler.Error("AdoNetRetryAppender: Not 
sending buffer. Delay of " + m_intRetryDelaySeconds + " secs has not elapsed 
since last error at " + m_dtLastConnectFailure);
                                return;
                        }

                        //first see if we need to open database connection 
(note: this one check alone is not good enough, since the connection state is 
not always updated upon failure)
                        if (m_blnReconnectOnError && (m_dbConnection == null || 
m_dbConnection.State != ConnectionState.Open) && !DatabaseReconnect())
                        {
                                return; //if reconnect fails then quit
                        }

                        bool blnSuccess = false;
                        int intSendAttempts = (m_blnReconnectOnError) ? 2 : 1 ; 
//if we should reconnect on error (and haven't already tried), then make two 
attempts. Otherwise only try once.

                        for (int intAttemptNum=1; 
intAttemptNum<=intSendAttempts && !blnSuccess; intAttemptNum++)
                        {
                                //the first attempt to send buffer failed, so 
force reconnect
                                if (intAttemptNum>1 && !DatabaseReconnect())
                                {
                                        return; //if reconnect fails then quit
                                }

                                // Check that the connection exists and is open
                                if (m_dbConnection != null && 
m_dbConnection.State == ConnectionState.Open)
                                {
                                        if (m_useTransactions)
                                        {
                                                // Create transaction
                                                // NJC - Do this on 2 lines 
because it can confuse the debugger
                                                IDbTransaction dbTran = null;
                                                try
                                                {
                                                        dbTran = 
m_dbConnection.BeginTransaction();
                                                        SendBuffer(dbTran, 
events);

                                                        // commit transaction
                                                        dbTran.Commit();
                                                        blnSuccess = true;
                                                }
                                                catch(Exception ex)
                                                {
                                                        // rollback the 
transaction
                                                        if (dbTran!=null)
                                                        {
                                                                try
                                                                {
                                                                        
dbTran.Rollback();
                                                                }
                                                                catch(Exception)
                                                                {
                                                                        
//Ignore exception
                                                                }
                                                        }

                                                        // Can't insert into 
the database. That's a bad thing
                                                        
ErrorHandler.Error("Exception while writing to database", ex);
                                                }
                                        }
                                        else
                                        {
                                                // Send without transaction
                                                SendBuffer(null, events);
                                                blnSuccess = true;
                                        }
                                }//if connection open

                        }//for
                }//SendBuffer()


                /// <summary>
                /// Attempts to reconnect to the logging database
                /// </summary>
                /// <returns>true if reconnect worked, false otherwise</returns>
                private bool DatabaseReconnect()
                {
                        bool blnReconnected = true;

                        ErrorHandler.Error("AdoNetRetryAppender: Attempting to 
reconnect to database");
                        InitializeDatabaseConnection();
                        InitializeDatabaseCommand();

                        //check if reconnect worked
                        if (m_dbConnection == null || m_dbConnection.State != 
ConnectionState.Open)
                        {
                                ErrorHandler.Error("AdoNetRetryAppender: 
Reconnect to database failed.");
                                m_dtLastConnectFailure = DateTime.Now;  
//record failure
                                blnReconnected = false;
                        }

                        return blnReconnected;
                }//DatabaseReconnect()


-----Original message-----
From: "Georg Jansen" [EMAIL PROTECTED]
Date: Thu, 02 Feb 2006 18:17:43 -0800
To: "'Log4NET User'" [email protected]
Subject: RE: Database Appender

>  
> 
>  
> 
> I did some modifications to the SendBuffer method of AdoNetAppender, and it
> seems to work. I tested it -- starting and stopping SQLServer between log
> calls.
> 
> The modified source is based on the 1.2.9 source where the config parameter
> reconnectonerror is available.
> 
>  
> 
> I have kept the original "retry code" but it doesn't seems like it is
> working, the m_dbConnection.State is not (at least during my test) updated
> if a connection is dropped from the server.
> 
>  
> 
>  
> 
> Regards
> 
> Georg
> 
> http://www.l4ndash.com <http://www.l4ndash.com/>  Log4Net Dashboard /
> Log4Net Viewer 
> 
>  
> 
>  
> 
>  
> 
> override protected void SendBuffer(LoggingEvent[] events)
> 
> {
> 
>    if (m_reconnectOnError && (m_dbConnection == null || m_dbConnection.State
> != ConnectionState.Open))
> 
>    {
> 
>       LogLog.Debug("AdoNetAppender: Attempting to reconnect to database.
> Current Connection State: " +
> ((m_dbConnection==null)?"<null>":m_dbConnection.State.ToString()) );
> 
>  
> 
>       InitializeDatabaseConnection();
> 
>       InitializeDatabaseCommand();
> 
>     }
> 
>  
> 
>     int NoOfReTry;
> 
>     bool Sucess = false;
> 
>  
> 
>     if (m_reconnectOnError)
> 
>     {
> 
>         NoOfReTry = 2;
> 
>     }
> 
>     else
> 
>     {
> 
>         NoOfReTry = 1;
> 
>     
> 
>     }
> 
>  
> 
>     for (int iTryNo = 1; iTryNo <= NoOfReTry && Sucess == false; iTryNo++)
> 
>     {
> 
>         try
> 
>         {
> 
>             if (iTryNo > 1) // second time? --> try to reconnect
> 
>             {
> 
>                 while (iTryNo <= NoOfReTry)
> 
>                 {
> 
>                     LogLog.Debug("AdoNetAppender: Attempting to reconnect to
> database");
> 
>  
> 
>                     InitializeDatabaseConnection();
> 
>                     if (m_dbConnection != null && m_dbConnection.State ==
> ConnectionState.Open)
> 
>                         break;
> 
>  
> 
>                     iTryNo++;
> 
>                 }
> 
>  
> 
>                 if (m_dbConnection == null || m_dbConnection.State !=
> ConnectionState.Open)
> 
>                 {
> 
>                     LogLog.Error("Giving up database reconect after trying:
> " + NoOfReTry.ToString() + " times");
> 
>                     return;
> 
>                 }
> 
>  
> 
>                 InitializeDatabaseCommand();
> 
>             }
> 
>  
> 
>             // Check that the connection exists and is open
> 
>             if (m_dbConnection != null && m_dbConnection.State ==
> ConnectionState.Open)
> 
>             {
> 
>                 if (m_useTransactions)
> 
>                 {
> 
>                     // Create transaction
> 
>                     // NJC - Do this on 2 lines because it can confuse the
> debugger
> 
>                     IDbTransaction dbTran = null;
> 
>                     try
> 
>                     {
> 
>                         dbTran = m_dbConnection.BeginTransaction();
> 
>  
> 
>                         SendBuffer(dbTran, events);
> 
>  
> 
>                         // commit transaction
> 
>                         dbTran.Commit();
> 
>                         Sucess = true;
> 
>                     }
> 
>                     catch (Exception ex)
> 
>                     {
> 
>                         // rollback the transaction
> 
>                         if (dbTran != null)
> 
>                         {
> 
>                             try
> 
>                             {
> 
>                                 dbTran.Rollback();
> 
>                             }
> 
>                             catch (Exception)
> 
>                             {
> 
>                                 // Ignore exception
> 
>                             }
> 
>                         }
> 
>  
> 
>                         // Can't insert into the database. That's a bad
> thing
> 
>                         ErrorHandler.Error("Exception while writing to
> database", ex);
> 
>                     }
> 
>                 }
> 
>                 else
> 
>                 {
> 
>                     // Send without transaction
> 
>                     SendBuffer(null, events);
> 
>                     Sucess = true;
> 
>                 }
> 
>             }
> 
>         }
> 
>  
> 
>         catch (Exception ex)
> 
>         {
> 
>             Sucess = false;
> 
>         }
> 
>     }
> 
> }
> 
>  
> 
>  
> 
>  
> 
>   _____  
> 
> From: Georg Jansen [mailto:[EMAIL PROTECTED] 
> Sent: 2. februar 2006 17:22
> To: 'Log4NET User'
> Subject: RE: Database Appender
> 
>  
> 
>  
> 
> Simon,
> 
>  
> 
> I believe it was done some work on that in 1.2.9 (you are using an earlier
> version, right?)
> 
>  
> 
> I checked the source code for the AdoNetAppender, and in the SendBuffer it
> tries to do a reconnect (if the parameter reconnectonerror is stated in the
> config).
> 
>  
> 
> override protected void SendBuffer(LoggingEvent[] events)
> 
> {
> 
>    if (m_reconnectOnError && (m_dbConnection == null ||
> 
>                    m_dbConnection.State != ConnectionState.Open))
> 
>    {
> 
>       LogLog.Debug("AdoNetAppender: Attempting to reconnect to database.
> 
>                   Current Connection State: " +
> 
>       ((m_dbConnection==null)?"<null>":m_dbConnection.State.ToString()) );
> 
>       InitializeDatabaseConnection();
> 
>       InitializeDatabaseCommand();
> 
>    }
> 
>  
> 
>  
> 
> Problem is that when I tested this (I restarted SQL server between two log
> statements), I still gets an exception stating a "transport layer error".
> 
>  
> 
> I agree with you, Simon this is a problem with applications running for a
> long time for example web applications. A simple solution would be to modify
> the adonetappender and try to do a reconnect whenever the sql statement
> fails (I will give it a try).
> 
>  
> 
>  
> 
> Regards
> 
> Georg
> 
> http://www.l4ndash.com <http://www.l4ndash.com/>  Log4Net Dashboard /
> Log4Net Viewer 
> 
>  
> 
>  
> 
> -----Original Message-----
> From: Simon Wallis [mailto:[EMAIL PROTECTED] 
> Sent: 2. februar 2006 16:31
> To: Log4NET User
> Subject: RE: Database Appender
> 
>  
> 
> Hi,
> 
>  
> 
> Has anyone come up with any creative ways to solve this problem of the
> database connection hanging? The only thing I can think of is to have a
> process that "touches" the config file on an hourly basis. Otherwise we have
> to remember to go around doing this manually on all the servers whenever the
> database is rebooted or there's a temporary network failure.
> 
>  
> 
> I realize it would be a lot of work to add retry or failure semantics to the
> appender, but whenever this is implemented, likely the most flexible
> approach would be to provide a number of options via the config file.
> 
>  
> 
> Simon.
> 
>  
> 
>  
> 
> -----Original Message-----
> 
> Subject:    RE:  Database Appender
> 
> From:       "Nicko Cadell" <nicko () neoworks ! com>
> 
> Date:       2005-01-10 13:59:27
> 
> Message-ID: DDEB64C8619AC64DBC074208B046611C59C838 () kronos ! neoworks ! co
> ! uk
> 
> [Download message RAW]
> 
>  
> 
> Greg,
> 
>  
> 
> The AdoNetAppender does not reopen the connection if there is a failure.
> 
> The database connection is only opened during appender initialisation.
> 
> Error handling is a general issue for appenders but for the
> 
> AdoNetAppender there are a number of options. 
> 
>  
> 
> The current behaviour is for the appender to stop trying to write to the
> 
> database if the connection is closed. An alternative is for the appender
> 
> to try to reconnect to the database. The issues with reconnecting is
> 
> when to try and how many times. The appender could try to reconnect when
> 
> the buffered events are sent. If it fails to contact the server then the
> 
> connection will time out after some time. This is a synchronous call and
> 
> therefore any logging call in your application could randomly incur this
> 
> connection timeout penalty at any time. Is that acceptable behaviour for
> 
> the appender? If the appender cannot reconnect should it discard the
> 
> events that it cannot deliver? or should it store the events and
> 
> redeliver them when/if it does reconnect, if so how many event should it
> 
> store?
> 
>  
> 
> There are no easy solutions to these issues, and different behaviours
> 
> will be appropriate for different situations. The current AdoNetAppender
> 
> implementation does not attempt to support any retry or failure
> 
> semantics. This is one area where we will need to do some work in
> 
> future. If you have any suggestions we would be happy to discuss them. 
> 
>  
> 
> Nicko
> 
>  
> 
> > -----Original Message-----
> 
> > From: Ismay, Greg (CALBRIS) 
> 
> > [mailto:[EMAIL PROTECTED] 
> 
> > Sent: 10 January 2005 04:15
> 
> > To: [email protected]
> 
> > Subject: Database Appender
> 
> > 
> 
> > 
> 
> > > howdy everyone...
> 
> > > 
> 
> > > im using the database ADONetAppender to log to a sql server 
> 
> > database and its all going peachy keen... for a while...
> 
> > > 
> 
> > > ive got the same app installed at 4 of our sites, with the 
> 
> > appender pointing back to a central database accessible over 
> 
> > the wan (i will probably end up using a local db at each 
> 
> > site, but a central db was my going in position, with a "lets 
> 
> > see how it goes before we decentralise" mentality). the wans 
> 
> > pretty fast and im only doing production logging (ie only 
> 
> > errors and fatals) this way.
> 
> > > 
> 
> > > basically, it works for a few days and sometimes up to a 
> 
> > week or so, before the logging just stops.
> 
> > > 
> 
> > > forcing the loggers to reinitialised (ie by "touch"ing the 
> 
> > log4net.config file) makes it all good again...
> 
> > > 
> 
> > > my question is this... are there any known problems with the db 
> 
> > > appender (or any appender) whereby a loss of connection (which can 
> 
> > > happen over the wan) over time could result in the above 
> 
> > state (eg... 
> 
> > > maybe running out of connections in the pool due to them gradually 
> 
> > > getting "stuck")
> 
> > > 
> 
> > > ill troll through the code in a few minutes, but just 
> 
> > thought id ask first.
> 
> > > 
> 
> > > thanks,
> 
> > > 
> 
> > > Greg Ismay
> 
> > > 
> 
> > > Specialist - Database Support (Automation Improvement) Comalco 
> 
> > > Aluminium Limited
> 
> > > 
> 
> > > Phone   :   +61 7 3867 1853
> 
> > > Fax    :   +61 7 3867 1855
> 
> > > Mobile  :   +61 4 1760 6429
> 
> > >
> 
> > 
> 
> 

Reply via email to