| #region Apache License |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to you under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #endregion |
| |
| // SSCLI 1.0 has no support for ADO.NET |
| #if !SSCLI |
| |
| using System; |
| using System.Collections; |
| using System.Configuration; |
| using System.Data; |
| using System.IO; |
| |
| using log4net.Util; |
| using log4net.Layout; |
| using log4net.Core; |
| |
| namespace log4net.Appender |
| { |
| /// <summary> |
| /// Appender that logs to a database. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// <see cref="AdoNetAppender"/> appends logging events to a table within a |
| /// database. The appender can be configured to specify the connection |
| /// string by setting the <see cref="ConnectionString"/> property. |
| /// The connection type (provider) can be specified by setting the <see cref="ConnectionType"/> |
| /// property. For more information on database connection strings for |
| /// your specific database see <a href="http://www.connectionstrings.com/">http://www.connectionstrings.com/</a>. |
| /// </para> |
| /// <para> |
| /// Records are written into the database either using a prepared |
| /// statement or a stored procedure. The <see cref="CommandType"/> property |
| /// is set to <see cref="System.Data.CommandType.Text"/> (<c>System.Data.CommandType.Text</c>) to specify a prepared statement |
| /// or to <see cref="System.Data.CommandType.StoredProcedure"/> (<c>System.Data.CommandType.StoredProcedure</c>) to specify a stored |
| /// procedure. |
| /// </para> |
| /// <para> |
| /// The prepared statement text or the name of the stored procedure |
| /// must be set in the <see cref="CommandText"/> property. |
| /// </para> |
| /// <para> |
| /// The prepared statement or stored procedure can take a number |
| /// of parameters. Parameters are added using the <see cref="AddParameter"/> |
| /// method. This adds a single <see cref="AdoNetAppenderParameter"/> to the |
| /// ordered list of parameters. The <see cref="AdoNetAppenderParameter"/> |
| /// type may be subclassed if required to provide database specific |
| /// functionality. The <see cref="AdoNetAppenderParameter"/> specifies |
| /// the parameter name, database type, size, and how the value should |
| /// be generated using a <see cref="ILayout"/>. |
| /// </para> |
| /// </remarks> |
| /// <example> |
| /// An example of a SQL Server table that could be logged to: |
| /// <code lang="SQL"> |
| /// CREATE TABLE [dbo].[Log] ( |
| /// [ID] [int] IDENTITY (1, 1) NOT NULL , |
| /// [Date] [datetime] NOT NULL , |
| /// [Thread] [varchar] (255) NOT NULL , |
| /// [Level] [varchar] (20) NOT NULL , |
| /// [Logger] [varchar] (255) NOT NULL , |
| /// [Message] [varchar] (4000) NOT NULL |
| /// ) ON [PRIMARY] |
| /// </code> |
| /// </example> |
| /// <example> |
| /// An example configuration to log to the above table: |
| /// <code lang="XML" escaped="true"> |
| /// <appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender" > |
| /// <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> |
| /// <connectionString value="data source=SQLSVR;initial catalog=test_log4net;integrated security=false;persist security info=True;User ID=sa;Password=sa" /> |
| /// <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" /> |
| /// <parameter> |
| /// <parameterName value="@log_date" /> |
| /// <dbType value="DateTime" /> |
| /// <layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" /> |
| /// </parameter> |
| /// <parameter> |
| /// <parameterName value="@thread" /> |
| /// <dbType value="String" /> |
| /// <size value="255" /> |
| /// <layout type="log4net.Layout.PatternLayout" value="%thread" /> |
| /// </parameter> |
| /// <parameter> |
| /// <parameterName value="@log_level" /> |
| /// <dbType value="String" /> |
| /// <size value="50" /> |
| /// <layout type="log4net.Layout.PatternLayout" value="%level" /> |
| /// </parameter> |
| /// <parameter> |
| /// <parameterName value="@logger" /> |
| /// <dbType value="String" /> |
| /// <size value="255" /> |
| /// <layout type="log4net.Layout.PatternLayout" value="%logger" /> |
| /// </parameter> |
| /// <parameter> |
| /// <parameterName value="@message" /> |
| /// <dbType value="String" /> |
| /// <size value="4000" /> |
| /// <layout type="log4net.Layout.PatternLayout" value="%message" /> |
| /// </parameter> |
| /// </appender> |
| /// </code> |
| /// </example> |
| /// <author>Julian Biddle</author> |
| /// <author>Nicko Cadell</author> |
| /// <author>Gert Driesen</author> |
| /// <author>Lance Nehring</author> |
| public class AdoNetAppender : BufferingAppenderSkeleton |
| { |
| #region Public Instance Constructors |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="AdoNetAppender" /> class. |
| /// </summary> |
| /// <remarks> |
| /// Public default constructor to initialize a new instance of this class. |
| /// </remarks> |
| public AdoNetAppender() |
| { |
| ConnectionType = "System.Data.OleDb.OleDbConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; |
| UseTransactions = true; |
| CommandType = System.Data.CommandType.Text; |
| m_parameters = new ArrayList(); |
| ReconnectOnError = false; |
| } |
| |
| #endregion // Public Instance Constructors |
| |
| #region Public Instance Properties |
| |
| /// <summary> |
| /// Gets or sets the database connection string that is used to connect to |
| /// the database. |
| /// </summary> |
| /// <value> |
| /// The database connection string used to connect to the database. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The connections string is specific to the connection type. |
| /// See <see cref="ConnectionType"/> for more information. |
| /// </para> |
| /// </remarks> |
| /// <example>Connection string for MS Access via ODBC: |
| /// <code>"DSN=MS Access Database;UID=admin;PWD=;SystemDB=C:\data\System.mdw;SafeTransactions = 0;FIL=MS Access;DriverID = 25;DBQ=C:\data\train33.mdb"</code> |
| /// </example> |
| /// <example>Another connection string for MS Access via ODBC: |
| /// <code>"Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\Work\cvs_root\log4net-1.2\access.mdb;UID=;PWD=;"</code> |
| /// </example> |
| /// <example>Connection string for MS Access via OLE DB: |
| /// <code>"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Work\cvs_root\log4net-1.2\access.mdb;User Id=;Password=;"</code> |
| /// </example> |
| public string ConnectionString |
| { |
| get { return m_connectionString; } |
| set { m_connectionString = value; } |
| } |
| |
| /// <summary> |
| /// The appSettings key from App.Config that contains the connection string. |
| /// </summary> |
| public string AppSettingsKey |
| { |
| get { return m_appSettingsKey; } |
| set { m_appSettingsKey = value; } |
| } |
| |
| #if NET_2_0 |
| /// <summary> |
| /// The connectionStrings key from App.Config that contains the connection string. |
| /// </summary> |
| /// <remarks> |
| /// This property requires at least .NET 2.0. |
| /// </remarks> |
| public string ConnectionStringName |
| { |
| get { return m_connectionStringName; } |
| set { m_connectionStringName = value; } |
| } |
| #endif |
| |
| /// <summary> |
| /// Gets or sets the type name of the <see cref="IDbConnection"/> connection |
| /// that should be created. |
| /// </summary> |
| /// <value> |
| /// The type name of the <see cref="IDbConnection"/> connection. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The type name of the ADO.NET provider to use. |
| /// </para> |
| /// <para> |
| /// The default is to use the OLE DB provider. |
| /// </para> |
| /// </remarks> |
| /// <example>Use the OLE DB Provider. This is the default value. |
| /// <code>System.Data.OleDb.OleDbConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</code> |
| /// </example> |
| /// <example>Use the MS SQL Server Provider. |
| /// <code>System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</code> |
| /// </example> |
| /// <example>Use the ODBC Provider. |
| /// <code>Microsoft.Data.Odbc.OdbcConnection,Microsoft.Data.Odbc,version=1.0.3300.0,publicKeyToken=b77a5c561934e089,culture=neutral</code> |
| /// This is an optional package that you can download from |
| /// <a href="http://msdn.microsoft.com/downloads">http://msdn.microsoft.com/downloads</a> |
| /// search for <b>ODBC .NET Data Provider</b>. |
| /// </example> |
| /// <example>Use the Oracle Provider. |
| /// <code>System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</code> |
| /// This is an optional package that you can download from |
| /// <a href="http://msdn.microsoft.com/downloads">http://msdn.microsoft.com/downloads</a> |
| /// search for <b>.NET Managed Provider for Oracle</b>. |
| /// </example> |
| public string ConnectionType |
| { |
| get { return m_connectionType; } |
| set { m_connectionType = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the command text that is used to insert logging events |
| /// into the database. |
| /// </summary> |
| /// <value> |
| /// The command text used to insert logging events into the database. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Either the text of the prepared statement or the |
| /// name of the stored procedure to execute to write into |
| /// the database. |
| /// </para> |
| /// <para> |
| /// The <see cref="CommandType"/> property determines if |
| /// this text is a prepared statement or a stored procedure. |
| /// </para> |
| /// <para> |
| /// If this property is not set, the command text is retrieved by invoking |
| /// <see cref="GetLogStatement(LoggingEvent)"/>. |
| /// </para> |
| /// </remarks> |
| public string CommandText |
| { |
| get { return m_commandText; } |
| set { m_commandText = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the command type to execute. |
| /// </summary> |
| /// <value> |
| /// The command type to execute. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// This value may be either <see cref="System.Data.CommandType.Text"/> (<c>System.Data.CommandType.Text</c>) to specify |
| /// that the <see cref="CommandText"/> is a prepared statement to execute, |
| /// or <see cref="System.Data.CommandType.StoredProcedure"/> (<c>System.Data.CommandType.StoredProcedure</c>) to specify that the |
| /// <see cref="CommandText"/> property is the name of a stored procedure |
| /// to execute. |
| /// </para> |
| /// <para> |
| /// The default value is <see cref="System.Data.CommandType.Text"/> (<c>System.Data.CommandType.Text</c>). |
| /// </para> |
| /// </remarks> |
| public CommandType CommandType |
| { |
| get { return m_commandType; } |
| set { m_commandType = value; } |
| } |
| |
| /// <summary> |
| /// Should transactions be used to insert logging events in the database. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if transactions should be used to insert logging events in |
| /// the database, otherwise <c>false</c>. The default value is <c>true</c>. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Gets or sets a value that indicates whether transactions should be used |
| /// to insert logging events in the database. |
| /// </para> |
| /// <para> |
| /// When set a single transaction will be used to insert the buffered events |
| /// into the database. Otherwise each event will be inserted without using |
| /// an explicit transaction. |
| /// </para> |
| /// </remarks> |
| public bool UseTransactions |
| { |
| get { return m_useTransactions; } |
| set { m_useTransactions = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the <see cref="SecurityContext"/> used to call the NetSend method. |
| /// </summary> |
| /// <value> |
| /// The <see cref="SecurityContext"/> used to call the NetSend method. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Unless a <see cref="SecurityContext"/> specified here for this appender |
| /// the <see cref="SecurityContextProvider.DefaultProvider"/> is queried for the |
| /// security context to use. The default behavior is to use the security context |
| /// of the current thread. |
| /// </para> |
| /// </remarks> |
| public SecurityContext SecurityContext |
| { |
| get { return m_securityContext; } |
| set { m_securityContext = value; } |
| } |
| |
| /// <summary> |
| /// Should this appender try to reconnect to the database on error. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if the appender should try to reconnect to the database after an |
| /// error has occurred, otherwise <c>false</c>. The default value is <c>false</c>, |
| /// i.e. not to try to reconnect. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The default behaviour is for the appender not to try to reconnect to the |
| /// database if an error occurs. Subsequent logging events are discarded. |
| /// </para> |
| /// <para> |
| /// To force the appender to attempt to reconnect to the database set this |
| /// property to <c>true</c>. |
| /// </para> |
| /// <note> |
| /// When the appender attempts to connect to the database there may be a |
| /// delay of up to the connection timeout specified in the connection string. |
| /// This delay will block the calling application's thread. |
| /// Until the connection can be reestablished this potential delay may occur multiple times. |
| /// </note> |
| /// </remarks> |
| public bool ReconnectOnError |
| { |
| get { return m_reconnectOnError; } |
| set { m_reconnectOnError = value; } |
| } |
| |
| #endregion // Public Instance Properties |
| |
| #region Protected Instance Properties |
| |
| /// <summary> |
| /// Gets or sets the underlying <see cref="IDbConnection" />. |
| /// </summary> |
| /// <value> |
| /// The underlying <see cref="IDbConnection" />. |
| /// </value> |
| /// <remarks> |
| /// <see cref="AdoNetAppender" /> creates a <see cref="IDbConnection" /> to insert |
| /// logging events into a database. Classes deriving from <see cref="AdoNetAppender" /> |
| /// can use this property to get or set this <see cref="IDbConnection" />. Use the |
| /// underlying <see cref="IDbConnection" /> returned from <see cref="Connection" /> if |
| /// you require access beyond that which <see cref="AdoNetAppender" /> provides. |
| /// </remarks> |
| protected IDbConnection Connection |
| { |
| get { return m_dbConnection; } |
| set { m_dbConnection = value; } |
| } |
| |
| #endregion // Protected Instance Properties |
| |
| #region Implementation of IOptionHandler |
| |
| /// <summary> |
| /// Initialize the appender based on the options set |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// This is part of the <see cref="IOptionHandler"/> delayed object |
| /// activation scheme. The <see cref="ActivateOptions"/> method must |
| /// be called on this object after the configuration properties have |
| /// been set. Until <see cref="ActivateOptions"/> is called this |
| /// object is in an undefined state and must not be used. |
| /// </para> |
| /// <para> |
| /// If any of the configuration properties are modified then |
| /// <see cref="ActivateOptions"/> must be called again. |
| /// </para> |
| /// </remarks> |
| override public void ActivateOptions() |
| { |
| base.ActivateOptions(); |
| |
| if (SecurityContext == null) |
| { |
| SecurityContext = SecurityContextProvider.DefaultProvider.CreateSecurityContext(this); |
| } |
| |
| InitializeDatabaseConnection(); |
| } |
| |
| #endregion |
| |
| #region Override implementation of AppenderSkeleton |
| |
| /// <summary> |
| /// Override the parent method to close the database |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Closes the database command and database connection. |
| /// </para> |
| /// </remarks> |
| override protected void OnClose() |
| { |
| base.OnClose(); |
| DiposeConnection(); |
| } |
| |
| #endregion |
| |
| #region Override implementation of BufferingAppenderSkeleton |
| |
| /// <summary> |
| /// Inserts the events into the database. |
| /// </summary> |
| /// <param name="events">The events to insert into the database.</param> |
| /// <remarks> |
| /// <para> |
| /// Insert all the events specified in the <paramref name="events"/> |
| /// array into the database. |
| /// </para> |
| /// </remarks> |
| override protected void SendBuffer(LoggingEvent[] events) |
| { |
| if (ReconnectOnError && (Connection == null || Connection.State != ConnectionState.Open)) |
| { |
| LogLog.Debug(declaringType, "Attempting to reconnect to database. Current Connection State: " + ((Connection == null) ? SystemInfo.NullText : Connection.State.ToString())); |
| |
| InitializeDatabaseConnection(); |
| } |
| |
| // Check that the connection exists and is open |
| if (Connection != null && Connection.State == ConnectionState.Open) |
| { |
| if (UseTransactions) |
| { |
| // Create transaction |
| // NJC - Do this on 2 lines because it can confuse the debugger |
| using (IDbTransaction dbTran = Connection.BeginTransaction()) |
| { |
| try |
| { |
| SendBuffer(dbTran, events); |
| |
| // commit transaction |
| dbTran.Commit(); |
| } |
| catch (Exception ex) |
| { |
| // rollback the transaction |
| 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); |
| } |
| } |
| } |
| |
| #endregion // Override implementation of BufferingAppenderSkeleton |
| |
| #region Public Instance Methods |
| |
| /// <summary> |
| /// Adds a parameter to the command. |
| /// </summary> |
| /// <param name="parameter">The parameter to add to the command.</param> |
| /// <remarks> |
| /// <para> |
| /// Adds a parameter to the ordered list of command parameters. |
| /// </para> |
| /// </remarks> |
| public void AddParameter(AdoNetAppenderParameter parameter) |
| { |
| m_parameters.Add(parameter); |
| } |
| |
| |
| #endregion // Public Instance Methods |
| |
| #region Protected Instance Methods |
| |
| /// <summary> |
| /// Writes the events to the database using the transaction specified. |
| /// </summary> |
| /// <param name="dbTran">The transaction that the events will be executed under.</param> |
| /// <param name="events">The array of events to insert into the database.</param> |
| /// <remarks> |
| /// <para> |
| /// The transaction argument can be <c>null</c> if the appender has been |
| /// configured not to use transactions. See <see cref="UseTransactions"/> |
| /// property for more information. |
| /// </para> |
| /// </remarks> |
| virtual protected void SendBuffer(IDbTransaction dbTran, LoggingEvent[] events) |
| { |
| // string.IsNotNullOrWhiteSpace() does not exist in ancient .NET frameworks |
| if (CommandText != null && CommandText.Trim() != "") |
| { |
| using (IDbCommand dbCmd = Connection.CreateCommand()) |
| { |
| // Set the command string |
| dbCmd.CommandText = CommandText; |
| |
| // Set the command type |
| dbCmd.CommandType = CommandType; |
| // Send buffer using the prepared command object |
| if (dbTran != null) |
| { |
| dbCmd.Transaction = dbTran; |
| } |
| // prepare the command, which is significantly faster |
| dbCmd.Prepare(); |
| // run for all events |
| foreach (LoggingEvent e in events) |
| { |
| // clear parameters that have been set |
| dbCmd.Parameters.Clear(); |
| |
| // Set the parameter values |
| foreach (AdoNetAppenderParameter param in m_parameters) |
| { |
| param.Prepare(dbCmd); |
| param.FormatValue(dbCmd, e); |
| } |
| |
| // Execute the query |
| dbCmd.ExecuteNonQuery(); |
| } |
| } |
| } |
| else |
| { |
| // create a new command |
| using (IDbCommand dbCmd = Connection.CreateCommand()) |
| { |
| if (dbTran != null) |
| { |
| dbCmd.Transaction = dbTran; |
| } |
| // run for all events |
| foreach (LoggingEvent e in events) |
| { |
| // Get the command text from the Layout |
| string logStatement = GetLogStatement(e); |
| |
| LogLog.Debug(declaringType, "LogStatement [" + logStatement + "]"); |
| |
| dbCmd.CommandText = logStatement; |
| dbCmd.ExecuteNonQuery(); |
| } |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Formats the log message into database statement text. |
| /// </summary> |
| /// <param name="logEvent">The event being logged.</param> |
| /// <remarks> |
| /// This method can be overridden by subclasses to provide |
| /// more control over the format of the database statement. |
| /// </remarks> |
| /// <returns> |
| /// Text that can be passed to a <see cref="System.Data.IDbCommand"/>. |
| /// </returns> |
| virtual protected string GetLogStatement(LoggingEvent logEvent) |
| { |
| if (Layout == null) |
| { |
| ErrorHandler.Error("AdoNetAppender: No Layout specified."); |
| return ""; |
| } |
| else |
| { |
| StringWriter writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture); |
| Layout.Format(writer, logEvent); |
| return writer.ToString(); |
| } |
| } |
| |
| /// <summary> |
| /// Creates an <see cref="IDbConnection"/> instance used to connect to the database. |
| /// </summary> |
| /// <remarks> |
| /// This method is called whenever a new IDbConnection is needed (i.e. when a reconnect is necessary). |
| /// </remarks> |
| /// <param name="connectionType">The <see cref="Type"/> of the <see cref="IDbConnection"/> object.</param> |
| /// <param name="connectionString">The connectionString output from the ResolveConnectionString method.</param> |
| /// <returns>An <see cref="IDbConnection"/> instance with a valid connection string.</returns> |
| virtual protected IDbConnection CreateConnection(Type connectionType, string connectionString) |
| { |
| IDbConnection connection = (IDbConnection)Activator.CreateInstance(connectionType); |
| connection.ConnectionString = connectionString; |
| return connection; |
| } |
| |
| /// <summary> |
| /// Resolves the connection string from the ConnectionString, ConnectionStringName, or AppSettingsKey |
| /// property. |
| /// </summary> |
| /// <remarks> |
| /// ConnectiongStringName is only supported on .NET 2.0 and higher. |
| /// </remarks> |
| /// <param name="connectionStringContext">Additional information describing the connection string.</param> |
| /// <returns>A connection string used to connect to the database.</returns> |
| virtual protected string ResolveConnectionString(out string connectionStringContext) |
| { |
| if (ConnectionString != null && ConnectionString.Length > 0) |
| { |
| connectionStringContext = "ConnectionString"; |
| return ConnectionString; |
| } |
| |
| #if NET_2_0 |
| if (!String.IsNullOrEmpty(ConnectionStringName)) |
| { |
| ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[ConnectionStringName]; |
| if (settings != null) |
| { |
| connectionStringContext = "ConnectionStringName"; |
| return settings.ConnectionString; |
| } |
| else |
| { |
| throw new LogException("Unable to find [" + ConnectionStringName + "] ConfigurationManager.ConnectionStrings item"); |
| } |
| } |
| #endif |
| |
| if (AppSettingsKey != null && AppSettingsKey.Length > 0) |
| { |
| connectionStringContext = "AppSettingsKey"; |
| string appSettingsConnectionString = SystemInfo.GetAppSetting(AppSettingsKey); |
| if (appSettingsConnectionString == null || appSettingsConnectionString.Length == 0) |
| { |
| throw new LogException("Unable to find [" + AppSettingsKey + "] AppSettings key."); |
| } |
| return appSettingsConnectionString; |
| } |
| |
| connectionStringContext = "Unable to resolve connection string from ConnectionString, ConnectionStrings, or AppSettings."; |
| return string.Empty; |
| } |
| |
| /// <summary> |
| /// Retrieves the class type of the ADO.NET provider. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Gets the Type of the ADO.NET provider to use to connect to the |
| /// database. This method resolves the type specified in the |
| /// <see cref="ConnectionType"/> property. |
| /// </para> |
| /// <para> |
| /// Subclasses can override this method to return a different type |
| /// if necessary. |
| /// </para> |
| /// </remarks> |
| /// <returns>The <see cref="Type"/> of the ADO.NET provider</returns> |
| virtual protected Type ResolveConnectionType() |
| { |
| try |
| { |
| return SystemInfo.GetTypeFromString(ConnectionType, true, false); |
| } |
| catch (Exception ex) |
| { |
| ErrorHandler.Error("Failed to load connection type [" + ConnectionType + "]", ex); |
| throw; |
| } |
| } |
| |
| #endregion // Protected Instance Methods |
| |
| #region Private Instance Methods |
| |
| /// <summary> |
| /// Connects to the database. |
| /// </summary> |
| private void InitializeDatabaseConnection() |
| { |
| string connectionStringContext = "Unable to determine connection string context."; |
| string resolvedConnectionString = string.Empty; |
| |
| try |
| { |
| DiposeConnection(); |
| |
| // Set the connection string |
| resolvedConnectionString = ResolveConnectionString(out connectionStringContext); |
| |
| Connection = CreateConnection(ResolveConnectionType(), resolvedConnectionString); |
| |
| using (SecurityContext.Impersonate(this)) |
| { |
| // Open the database connection |
| Connection.Open(); |
| } |
| } |
| catch (Exception e) |
| { |
| // Sadly, your connection string is bad. |
| ErrorHandler.Error("Could not open database connection [" + resolvedConnectionString + "]. Connection string context [" + connectionStringContext + "].", e); |
| |
| Connection = null; |
| } |
| } |
| |
| /// <summary> |
| /// Cleanup the existing connection. |
| /// </summary> |
| /// <remarks> |
| /// Calls the IDbConnection's <see cref="IDbConnection.Close"/> method. |
| /// </remarks> |
| private void DiposeConnection() |
| { |
| if (Connection != null) |
| { |
| try |
| { |
| Connection.Close(); |
| } |
| catch (Exception ex) |
| { |
| LogLog.Warn(declaringType, "Exception while disposing cached connection object", ex); |
| } |
| Connection = null; |
| } |
| } |
| |
| #endregion // Private Instance Methods |
| |
| #region Protected Instance Fields |
| |
| /// <summary> |
| /// The list of <see cref="AdoNetAppenderParameter"/> objects. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The list of <see cref="AdoNetAppenderParameter"/> objects. |
| /// </para> |
| /// </remarks> |
| protected ArrayList m_parameters; |
| |
| #endregion // Protected Instance Fields |
| |
| #region Private Instance Fields |
| |
| /// <summary> |
| /// The security context to use for privileged calls |
| /// </summary> |
| private SecurityContext m_securityContext; |
| |
| /// <summary> |
| /// The <see cref="IDbConnection" /> that will be used |
| /// to insert logging events into a database. |
| /// </summary> |
| private IDbConnection m_dbConnection; |
| |
| /// <summary> |
| /// Database connection string. |
| /// </summary> |
| private string m_connectionString; |
| |
| /// <summary> |
| /// The appSettings key from App.Config that contains the connection string. |
| /// </summary> |
| private string m_appSettingsKey; |
| |
| #if NET_2_0 |
| /// <summary> |
| /// The connectionStrings key from App.Config that contains the connection string. |
| /// </summary> |
| private string m_connectionStringName; |
| #endif |
| |
| /// <summary> |
| /// String type name of the <see cref="IDbConnection"/> type name. |
| /// </summary> |
| private string m_connectionType; |
| |
| /// <summary> |
| /// The text of the command. |
| /// </summary> |
| private string m_commandText; |
| |
| /// <summary> |
| /// The command type. |
| /// </summary> |
| private CommandType m_commandType; |
| |
| /// <summary> |
| /// Indicates whether to use transactions when writing to the database. |
| /// </summary> |
| private bool m_useTransactions; |
| |
| /// <summary> |
| /// Indicates whether to reconnect when a connection is lost. |
| /// </summary> |
| private bool m_reconnectOnError; |
| |
| #endregion // Private Instance Fields |
| |
| #region Private Static Fields |
| |
| /// <summary> |
| /// The fully qualified type of the AdoNetAppender class. |
| /// </summary> |
| /// <remarks> |
| /// Used by the internal logger to record the Type of the |
| /// log message. |
| /// </remarks> |
| private readonly static Type declaringType = typeof(AdoNetAppender); |
| |
| #endregion Private Static Fields |
| } |
| |
| /// <summary> |
| /// Parameter type used by the <see cref="AdoNetAppender"/>. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// This class provides the basic database parameter properties |
| /// as defined by the <see cref="System.Data.IDbDataParameter"/> interface. |
| /// </para> |
| /// <para>This type can be subclassed to provide database specific |
| /// functionality. The two methods that are called externally are |
| /// <see cref="Prepare"/> and <see cref="FormatValue"/>. |
| /// </para> |
| /// </remarks> |
| public class AdoNetAppenderParameter |
| { |
| #region Public Instance Constructors |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="AdoNetAppenderParameter" /> class. |
| /// </summary> |
| /// <remarks> |
| /// Default constructor for the AdoNetAppenderParameter class. |
| /// </remarks> |
| public AdoNetAppenderParameter() |
| { |
| Precision = 0; |
| Scale = 0; |
| Size = 0; |
| } |
| |
| #endregion // Public Instance Constructors |
| |
| #region Public Instance Properties |
| |
| /// <summary> |
| /// Gets or sets the name of this parameter. |
| /// </summary> |
| /// <value> |
| /// The name of this parameter. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The name of this parameter. The parameter name |
| /// must match up to a named parameter to the SQL stored procedure |
| /// or prepared statement. |
| /// </para> |
| /// </remarks> |
| public string ParameterName |
| { |
| get { return m_parameterName; } |
| set { m_parameterName = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the database type for this parameter. |
| /// </summary> |
| /// <value> |
| /// The database type for this parameter. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The database type for this parameter. This property should |
| /// be set to the database type from the <see cref="DbType"/> |
| /// enumeration. See <see cref="IDataParameter.DbType"/>. |
| /// </para> |
| /// <para> |
| /// This property is optional. If not specified the ADO.NET provider |
| /// will attempt to infer the type from the value. |
| /// </para> |
| /// </remarks> |
| /// <seealso cref="IDataParameter.DbType" /> |
| public DbType DbType |
| { |
| get { return m_dbType; } |
| set |
| { |
| m_dbType = value; |
| m_inferType = false; |
| } |
| } |
| |
| /// <summary> |
| /// Gets or sets the precision for this parameter. |
| /// </summary> |
| /// <value> |
| /// The precision for this parameter. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The maximum number of digits used to represent the Value. |
| /// </para> |
| /// <para> |
| /// This property is optional. If not specified the ADO.NET provider |
| /// will attempt to infer the precision from the value. |
| /// </para> |
| /// </remarks> |
| /// <seealso cref="IDbDataParameter.Precision" /> |
| public byte Precision |
| { |
| get { return m_precision; } |
| set { m_precision = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the scale for this parameter. |
| /// </summary> |
| /// <value> |
| /// The scale for this parameter. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The number of decimal places to which Value is resolved. |
| /// </para> |
| /// <para> |
| /// This property is optional. If not specified the ADO.NET provider |
| /// will attempt to infer the scale from the value. |
| /// </para> |
| /// </remarks> |
| /// <seealso cref="IDbDataParameter.Scale" /> |
| public byte Scale |
| { |
| get { return m_scale; } |
| set { m_scale = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the size for this parameter. |
| /// </summary> |
| /// <value> |
| /// The size for this parameter. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The maximum size, in bytes, of the data within the column. |
| /// </para> |
| /// <para> |
| /// This property is optional. If not specified the ADO.NET provider |
| /// will attempt to infer the size from the value. |
| /// </para> |
| /// <para> |
| /// For BLOB data types like VARCHAR(max) it may be impossible to infer the value automatically, use -1 as the size in this case. |
| /// </para> |
| /// </remarks> |
| /// <seealso cref="IDbDataParameter.Size" /> |
| public int Size |
| { |
| get { return m_size; } |
| set { m_size = value; } |
| } |
| |
| /// <summary> |
| /// Gets or sets the <see cref="IRawLayout"/> to use to |
| /// render the logging event into an object for this |
| /// parameter. |
| /// </summary> |
| /// <value> |
| /// The <see cref="IRawLayout"/> used to render the |
| /// logging event into an object for this parameter. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The <see cref="IRawLayout"/> that renders the value for this |
| /// parameter. |
| /// </para> |
| /// <para> |
| /// The <see cref="RawLayoutConverter"/> can be used to adapt |
| /// any <see cref="ILayout"/> into a <see cref="IRawLayout"/> |
| /// for use in the property. |
| /// </para> |
| /// </remarks> |
| public IRawLayout Layout |
| { |
| get { return m_layout; } |
| set { m_layout = value; } |
| } |
| |
| #endregion // Public Instance Properties |
| |
| #region Public Instance Methods |
| |
| /// <summary> |
| /// Prepare the specified database command object. |
| /// </summary> |
| /// <param name="command">The command to prepare.</param> |
| /// <remarks> |
| /// <para> |
| /// Prepares the database command object by adding |
| /// this parameter to its collection of parameters. |
| /// </para> |
| /// </remarks> |
| virtual public void Prepare(IDbCommand command) |
| { |
| // Create a new parameter |
| IDbDataParameter param = command.CreateParameter(); |
| |
| // Set the parameter properties |
| param.ParameterName = ParameterName; |
| |
| if (!m_inferType) |
| { |
| param.DbType = DbType; |
| } |
| if (Precision != 0) |
| { |
| param.Precision = Precision; |
| } |
| if (Scale != 0) |
| { |
| param.Scale = Scale; |
| } |
| if (Size != 0) |
| { |
| param.Size = Size; |
| } |
| |
| // Add the parameter to the collection of params |
| command.Parameters.Add(param); |
| } |
| |
| /// <summary> |
| /// Renders the logging event and set the parameter value in the command. |
| /// </summary> |
| /// <param name="command">The command containing the parameter.</param> |
| /// <param name="loggingEvent">The event to be rendered.</param> |
| /// <remarks> |
| /// <para> |
| /// Renders the logging event using this parameters layout |
| /// object. Sets the value of the parameter on the command object. |
| /// </para> |
| /// </remarks> |
| virtual public void FormatValue(IDbCommand command, LoggingEvent loggingEvent) |
| { |
| // Lookup the parameter |
| IDbDataParameter param = (IDbDataParameter)command.Parameters[ParameterName]; |
| |
| // Format the value |
| object formattedValue = Layout.Format(loggingEvent); |
| |
| // If the value is null then convert to a DBNull |
| if (formattedValue == null) |
| { |
| formattedValue = DBNull.Value; |
| } |
| |
| param.Value = formattedValue; |
| } |
| |
| #endregion // Public Instance Methods |
| |
| #region Private Instance Fields |
| |
| /// <summary> |
| /// The name of this parameter. |
| /// </summary> |
| private string m_parameterName; |
| |
| /// <summary> |
| /// The database type for this parameter. |
| /// </summary> |
| private DbType m_dbType; |
| |
| /// <summary> |
| /// Flag to infer type rather than use the DbType |
| /// </summary> |
| private bool m_inferType = true; |
| |
| /// <summary> |
| /// The precision for this parameter. |
| /// </summary> |
| private byte m_precision; |
| |
| /// <summary> |
| /// The scale for this parameter. |
| /// </summary> |
| private byte m_scale; |
| |
| /// <summary> |
| /// The size for this parameter. |
| /// </summary> |
| private int m_size; |
| |
| /// <summary> |
| /// The <see cref="IRawLayout"/> to use to render the |
| /// logging event into an object for this parameter. |
| /// </summary> |
| private IRawLayout m_layout; |
| |
| #endregion // Private Instance Fields |
| } |
| } |
| |
| #endif // !SSCLI |