Log4net Custom Field Persistence to Oracle via ODP.NET Managed Driver
Environment Confgiuration
Development environment requires Visual Studio 2010, Oracle 11g database, log4net 1.2.13, and Oracle.ManagedDataAccess.dll version 4.121.1.0.
Implementation Procedure
Configuration Setup
Create log4net configuration file with Oracle-specific parameters:
<appender name="OracleManagedAppender" type="CustomNamespace.ManagedOracleAppender">
<bufferSize value="1"/>
<connectionType value="Oracle.ManagedDataAccess.Client.OracleConnection,Oracle.ManagedDataAccess" />
<connectionString value="Data Source=localhost:1521/orcl;User ID=appuser;Password=securepwd;" />
<commandText value="INSERT INTO APP_LOGS (LOG_TIME,SEVERITY,MESSAGE,EXCEPTION,LOGGER,SOURCE,USER_ID,LOG_CATEGORY)
VALUES (:log_timestamp, :log_level, :log_message, :log_exception, :logger, :source, :userid, :logtype)"/>
<parameter name=":log_timestamp">
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter name=":userid">
<dbType value="String" />
<layout type="CustomLayout">
<conversionPattern value="%USERID" />
</layout>
</parameter>
<parameter name=":logtype">
<dbType value="String" />
<layout type="CustomLayout">
<conversionPattern value="%LOGTYPE" />
</layout>
</parameter>
</appender>
Custom Appender Implementation
Create managed Oracle appender with array binding support:
public class ManagedOracleAppender : BufferingAppenderSkeleton
{
private OracleConnection dbConnection;
private OracleCommand dbCommand;
private string connectionString;
protected override void SendBuffer(LoggingEvent[] events)
{
using (var transaction = dbConnection.BeginTransaction())
{
try
{
foreach (var parameter in parameters)
{
var values = events.Select(e =>
parameter.Layout.Format(e) ?? DBNull.Value).ToArray();
dbCommand.Parameters[parameter.Name].Value = values;
}
dbCommand.ArrayBindCount = events.Length;
dbCommand.ExecuteNonQuery();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
// Connection initialization and parameter binding logic omitted for brevity
}
Custom Layout Registration
Register custom fields in pattern converter:
GlobalPatternRegistry.Add("USERID", typeof(UserIdPatternConverter));
GlobalPatternRegistry.Add("LOGTYPE", typeof(LogTypeConverter));
Runtime Configuration
Initialize logger in application startup:
// Global.asax
log4net.Config.XmlConfigurator.Configure(
new FileInfo(Server.MapPath("~/log4net.config")));
// AssemblyInfo.cs
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
Usage Example
private static readonly ILog Logger = LogManager.GetLogger("OracleLogger");
public void LogCustomEntry(CustomLogEntry entry)
{
Logger.Info(entry);
}