nicko 2005/08/29 15:02:33 Modified: examples/net/1.0/Appenders/SampleAppendersApp/cs/src/Appender FastDbAppender.cs Log: Updated FastDbAppender to support IBulkAppender, use connection pooling, and allow the connection type and database schema to be overridden by a subclass Revision Changes Path 1.3 +133 -16 logging-log4net/examples/net/1.0/Appenders/SampleAppendersApp/cs/src/Appender/FastDbAppender.cs Index: FastDbAppender.cs =================================================================== RCS file: /home/cvs/logging-log4net/examples/net/1.0/Appenders/SampleAppendersApp/cs/src/Appender/FastDbAppender.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- FastDbAppender.cs 15 Jun 2005 16:26:40 -0000 1.2 +++ FastDbAppender.cs 29 Aug 2005 22:02:33 -0000 1.3 @@ -16,6 +16,7 @@ //
#endregion +using System.Data; using System.Data.SqlClient; using log4net.Appender; using log4net.Core; @@ -26,16 +27,29 @@ /// Simple database appender /// </summary> /// <remarks> + /// <para> /// This database appender is very simple and does not support a configurable /// data schema. The schema supported is hardcoded into the appender. /// Also by not extending the AppenderSkeleton base class this appender /// avoids the serializable locking that it enforces. + /// </para> + /// <para> + /// This appender can be subclassed to change the database connection + /// type, or the database schema supported. + /// </para> + /// <para> + /// To change the database connection type the <see cref="GetConnection"/> + /// method must be overridden. + /// </para> + /// <para> + /// To change the database schema supported by the appender the <see cref="InitializeCommand"/> + /// and <see cref="SetCommandValues"/> methods must be overridden. + /// </para> /// </remarks> - public sealed class FastDbAppender : IAppender, IOptionHandler + public class FastDbAppender : IAppender, IBulkAppender, IOptionHandler { private string m_name; private string m_connectionString; - private SqlConnection m_dbConnection; public string Name { @@ -49,32 +63,135 @@ set { m_connectionString = value; } } - public void ActivateOptions() + public virtual void ActivateOptions() { - m_dbConnection = new SqlConnection(m_connectionString); - m_dbConnection.Open(); } - public void Close() + public virtual void Close() { - if (m_dbConnection != null) + } + + public virtual void DoAppend(LoggingEvent loggingEvent) + { + using(IDbConnection connection = GetConnection()) { - m_dbConnection.Close(); + // Open the connection for each event, this takes advantage + // of the builtin connection pooling + connection.Open(); + + using(IDbCommand command = connection.CreateCommand()) + { + InitializeCommand(command); + + SetCommandValues(command, loggingEvent); + command.ExecuteNonQuery(); + } } } - public void DoAppend(LoggingEvent loggingEvent) + public virtual void DoAppend(LoggingEvent[] loggingEvents) { - SqlCommand command = m_dbConnection.CreateCommand(); + using(IDbConnection connection = GetConnection()) + { + // Open the connection for each event, this takes advantage + // of the builtin connection pooling + connection.Open(); + + using(IDbCommand command = connection.CreateCommand()) + { + InitializeCommand(command); + + foreach(LoggingEvent loggingEvent in loggingEvents) + { + SetCommandValues(command, loggingEvent); + command.ExecuteNonQuery(); + } + } + } + } + + /// <summary> + /// Create the connection object + /// </summary> + /// <returns>the connection</returns> + /// <remarks> + /// <para> + /// This implementation returns a <see cref="SqlConnection"/>. + /// To change the connection subclass this appender and + /// return a different connection type. + /// </para> + /// </remarks> + virtual protected IDbConnection GetConnection() + { + return new SqlConnection(m_connectionString); + } + + /// <summary> + /// Initialize the command object supplied + /// </summary> + /// <param name="command">the command to initialize</param> + /// <remarks> + /// <para> + /// This method must setup the database command and the + /// parameters. + /// </para> + /// </remarks> + virtual protected void InitializeCommand(IDbCommand command) + { + command.CommandType = CommandType.Text; command.CommandText = "INSERT INTO [LogTable] ([Time],[Logger],[Level],[Thread],[Message]) VALUES (@Time,@Logger,@Level,@Thread,@Message)"; - command.Parameters.Add("@Time", loggingEvent.TimeStamp); - command.Parameters.Add("@Logger", loggingEvent.LoggerName); - command.Parameters.Add("@Level", loggingEvent.Level.Name); - command.Parameters.Add("@Thread", loggingEvent.ThreadName); - command.Parameters.Add("@Message", loggingEvent.RenderedMessage); + IDbDataParameter param = null; + + // @Time + param = command.CreateParameter(); + param.ParameterName = "@Time"; + param.DbType = DbType.DateTime; + command.Parameters.Add(param); + + // @Logger + param = command.CreateParameter(); + param.ParameterName = "@Logger"; + param.DbType = DbType.String; + command.Parameters.Add(param); + + // @Level + param = command.CreateParameter(); + param.ParameterName = "@Level"; + param.DbType = DbType.String; + command.Parameters.Add(param); + + // @Thread + param = command.CreateParameter(); + param.ParameterName = "@Thread"; + param.DbType = DbType.String; + command.Parameters.Add(param); + + // @Message + param = command.CreateParameter(); + param.ParameterName = "@Message"; + param.DbType = DbType.String; + command.Parameters.Add(param); + } - command.ExecuteNonQuery(); + /// <summary> + /// Set the values for the command parameters + /// </summary> + /// <param name="command">the command to update</param> + /// <param name="loggingEvent">the current logging event to retrieve the values from</param> + /// <remarks> + /// <para> + /// Set the values of the parameters created by the + /// <see cref="InitializeCommand"/> method. + /// </para> + /// </remarks> + virtual protected void SetCommandValues(IDbCommand command, LoggingEvent loggingEvent) + { + ((IDbDataParameter)command.Parameters["@Time"]).Value = loggingEvent.TimeStamp; + ((IDbDataParameter)command.Parameters["@Logger"]).Value = loggingEvent.LoggerName; + ((IDbDataParameter)command.Parameters["@Level"]).Value = loggingEvent.Level.Name; + ((IDbDataParameter)command.Parameters["@Thread"]).Value = loggingEvent.ThreadName; + ((IDbDataParameter)command.Parameters["@Message"]).Value = loggingEvent.RenderedMessage; } } }