log4net AdoNetAppender not finding library file for ODBC - log4net

I am trying to use log4net's AdoNetAppender to write a record to an event history table. We use ODBC because we have customers with various database systems, and ODBC is sufficient for our needs. However, I am not able to connect to my database. Here's my configuration file:
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %message%newline" />
</layout>
</appender>
<appender name="OdbcLogger" type="log4net.Appender.AdoNetAppender">
<connectionType value="System.Data.Odbc.Connection, System.Data"/>
<connectionString value="Dsn=Algoma;Server=localhost;Port=5432;uid=anneal;pwd=anneal" />
<bufferSize value="1" />
<commandText value="INSERT INTO event_history (description) values (?)" />
<parameter>
<parameterName value="message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="OdbcLogger" />
</root>
</log4net>
I have log4net internal debugging turned on. Here's the exception message I'm getting:
log4net:ERROR [AdoNetAppender] ErrorCode: GenericFailure. Failed to load connection type [System.Data.Odbc.Connection, System.Data]
System.IO.FileNotFoundException: Could not load file or assembly 'System.Data' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Data'
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type)
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
at log4net.Util.SystemInfo.GetTypeFromString(Assembly relativeAssembly, String typeName, Boolean throwOnError, Boolean ignoreCase)
at log4net.Util.SystemInfo.GetTypeFromString(String typeName, Boolean throwOnError, Boolean ignoreCase)
at log4net.Appender.AdoNetAppender.ResolveConnectionType()
Can someone suggest what I'm doing wrong? Or perhaps show me an example of using an AdoNetAppender to write to a database via ODBC?
Thanks very much

I got it to work by specifying version number, public key and culture:
<appender name="OdbcLogger" type="log4net.Appender.AdoNetAppender">
<connectionType value="System.Data.Odbc.OdbcConnection, System.Data, Version=4.0.30319.18020,publicKeyToken=b77a5c561934e089,culture=neutral"/>
<connectionString value="Dsn=Algoma;Server=localhost;Port=5432;uid=anneal;pwd=anneal" />
<bufferSize value="1" />
<commandText value="INSERT INTO event_history (description) values (?)" />
<parameter>
<parameterName value="message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
</appender>
I was wondering how to find the public key other than by luck in a Google search, which is how I found it. I found that gacutil will tell me.

Related

SQL appender for log4net not working in MVC5 application

I can't get log4net to actually log anything to my database. First I added log4net to my project (MVC).
Then I added this in AssemblyInfo.cs
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
In Global.asax.cs Application_Start I end the method with
log4net.GlobalContext.Properties["ApplicationName"] = "MvcApp";
log.Debug("Application started");
I added the following model:
public class Log
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[Display(Name="Date")]
public DateTime Description { get; set; }
[Required, StringLength(255)]
[Display(Name="Thread")]
public string Thread { get; set;}
[Required, StringLength(50)]
[Display(Name = "Level")]
public string Level { get; set; }
[Required, StringLength(255)]
[Display(Name = "Logger")]
public string Logger { get; set; }
[Required, StringLength(4000)]
[Display(Name = "Message")]
public string Message { get; set; }
[Required, StringLength(2000)]
[Display(Name = "Exception")]
public string Exception { get; set; }
}
I added this to ApplicationDbContext:
public System.Data.Entity.DbSet<Models.Log> Logs { get; set; }
In web.config I added this in the configSections element:
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
And then I created this as a child of the configuration element in web.config:
<log4net debug="true">
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="100" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="Server=windflower.arvixe.com;Initial Catalog=coralys;User Id=coralysdb;Password=CoughUp_23;Application Name=CoralysInternet;" />
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception)" />
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="AdoNetAppender" />
</root>
But even with the log.Debug entries nothing is appended. I tried setting the buffer to 5 as a test but no result. I then added a method to flush the buffers as well, no result. And the level is set to maximum (DEBUG).
What else am I missing here?
It finally works. What helped was to enable Internal Debug on log4net and have it log to internal debug to a text file as described in
Log4net with Entity Framework 5 and MVC4
Having done that it turned out that the SQL statement was wrong, my log table had a different name and also by mistake I had named the Date column as Description. All those errors appeared in the internal debug.
Having fixed that, it worked.

Write custom xml message to database

I am using log4net AdoNetAppender with C# to log a custom XML message into a database. I have a stored procedure that takes one parameter as a XML format.
Here is a part of my config file:
<appender name="AdoNetAppender" type="log4net.Appender.ADONetAppender">
<bufferSize value="1" />
<threshold value="ALL" />
<reconnectOnError value="true" />
<param name="ConnectionType" value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=xxxdfasdfas" />
<param name="ConnectionString" value="Data Source=myserver;integrated security=false;Initial Catalog=mydatabase; Persist Security Info=True;User ID=me;Password=me;" />
<param name="UseTransactions" value="False" />
<commandText value="dbo.InsertLog " />
<commandType value="StoredProcedure" />
<parameter>
<parameterName value="#LogEntries" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{LogEntries}" />
</layout>
</parameter>
</appender>
With log4net, I should be able to do something like this,
mylogger.Info(FormatToXML(ID,Date,LogLevel,message)); //FormatToXML takes these arguments, and create XMLElement
However, above line doesn't insert anything to the database. I have log4net debugger turned on, but I didn't see any errors/exception.
But, this works,
log4net.GlobalContext.Properties["LogEntries"] = FormatToXML(ID,Date,LogLevel,message);
mylogger.Info("");
I am sure I am doing something wrong where I should be able to just call mylogger.Info(...).
Can anybody see where I am doing wrong?
You're using custom property to get the value in the parameter in layout. Change the layout pattern by simply using the %message.
<parameter>
<parameterName value="#LogEntries" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
Now will work normally with mylogger.Info(...).

Log log4net numeric level value

I would like to log the numeric value corresponding to the log level when using log4net. That is, right now I am logging to database with the following command text:
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception)" />
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
I would like to change the string value of the logging level to the numeric. Is this possible?
I did not test this but the following should work.
You can create your own converter like this:
sealed class NumericLevelPatternConverter : PatternLayoutConverter
{
override protected void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
// maybe you need to call ToString() on the value property
writer.Write( loggingEvent.Level.Value );
}
}
and in the configuration file:
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="levelId" />
<type value="YourNamespace.NumericLevelPatternConverter" />
</converter>
<conversionPattern value="%levelId" />
</layout>

log4net ADO Stored Procedure

I am trying to call an existing Stored Procedure but can't get it to log. Seems to be parameter type conversion problem, but I can't figure it out.
Error on build is:
log4net:ERROR XmlHierarchyConfigurator: Cannot find Property
[conversionPattern] to set object on
[log4net.Layout.RawPropertyLayout]
web.config is:
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
<bufferSize value="1" />
<threshold value="ALL"/>
<param name="ConnectionType" value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<param name="ConnectionString" value="Data Source=central-db.canterbury.ac.uk\devel;Initial Catalog=SourceDB;Persist Security Info=True;/>
<param name="UseTransactions" value="False" />
<commandText value="dbo.usperrLogError" />
<commandType value="StoredProcedure" />
<parameter>
<parameterName value="#ApplicationId"/>
<dbType value="String"/>
<size value="2" />
<layout type="log4net.Layout.RawPropertyLayout">
<key value="EventGuid" />
<conversionPattern value="%property{APP-ID}"/>
</layout>
</parameter>
//
<parameter>
<parameterName value="#EventGuid"/>
<dbType value="String"/>
<size value="50" />
<layout type="log4net.Layout.RawPropertyLayout">
<key value="EventGuid" />
<conversionPattern value="%property{GUID}"/>
</layout>
</parameter>
Am setting Properties like this:
log4net.ThreadContext.Properties["GUID"] = eventGuid.ToString();
Following the log4net debug error there is an additional error here:
A first chance exception of type 'System.ArgumentNullException' occurred in mscorlib.dll
log4net:ERROR [AdoNetAppender] Failed in DoAppend
System.ArgumentNullException: Key cannot be null.
Parameter name: key
at System.Collections.Hashtable.get_Item(Object key)
at log4net.Util.PropertiesDictionary.get_Item(String key) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Util\PropertiesDictionary.cs:line 114
at log4net.Core.LoggingEvent.LookupProperty(String key) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Core\LoggingEvent.cs:line 1404
at log4net.Layout.RawPropertyLayout.Format(LoggingEvent loggingEvent) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Layout\RawPropertyLayout.cs:line 84
at log4net.Appender.AdoNetAppenderParameter.FormatValue(IDbCommand command, LoggingEvent loggingEvent) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Appender\AdoNetAppender.cs:line 1117
at log4net.Appender.AdoNetAppender.SendBuffer(IDbTransaction dbTran, LoggingEvent[] events) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Appender\AdoNetAppender.cs:line 560
at log4net.Appender.AdoNetAppender.SendBuffer(LoggingEvent[] events) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Appender\AdoNetAppender.cs:line 501
at log4net.Appender.BufferingAppenderSkeleton.Append(LoggingEvent loggingEvent) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Appender\BufferingAppenderSkeleton.cs:line 463
at log4net.Appender.AppenderSkeleton.DoAppend(LoggingEvent loggingEvent) in c:\work\svn_root\apache\log4net\tags\log4net-1.2.10-rc2\build\package\log4net-1.2.10\src\Appender\AppenderSkeleton.cs:line 316
A first chance exception of type 'System.ArgumentNullException' occurred in mscorlib.dll
log4net:ERROR [AdoNetAppender] Failed in DoAppend
System.ArgumentNullException: Key cannot be null.
Clearly I am not using RawPropertyLayout correctly but can't find good examples!
I do something like you, but I use the log4net.Layout.PatternLayout like this:
<parameter>
<parameterName value="#ProjectParam1"/>
<dbType value="String"/>
<size value="254" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{OrderNumber}" />
</layout>
</parameter>
If I understand the log4net.Layout.RawPropertyLayout correctly, you have to use it as follows:
<parameterName value="#EventGuid"/>
<dbType value="String"/>
<size value="50" />
<layout type="log4net.Layout.RawPropertyLayout">
<param name="Key" value="GUID" />
</layout>
</parameter>

how to insert into database from stored procedure in log4net?

I have to log thread context properties like this:
string logFilePath = AppDomain.CurrentDomain.BaseDirectory + "log4netconfig.xml";
FileInfo finfo = new FileInfo(logFilePath);
log4net.Config.XmlConfigurator.ConfigureAndWatch(finfo);
ILog logger = LogManager.GetLogger("Exception.Logging");
log4net.ThreadContext.Properties["MESSAGE"] = exception.Message;
log4net.ThreadContext.Properties["MODULE"] = "module1";
log4net.ThreadContext.Properties["COMPONENT"] = "component1";
logger.Debug("test");
and the configuration file is:
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<logger name="Exception.Logging" level="Debug">
<appender-ref ref="AdoNetAppender"/>
</logger>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<connectionString value="Data Source=xe;User ID=test;Password=test;" />
<connectionType value="System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<bufferSize value="10000"/>
<commandText value="Log_Exception_Pkg.Insert_Log" />
<commandType value="StoredProcedure" />
<parameter>
<parameterName value="#p_Error_Message" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{MESSAGE}"/>
</layout>
</parameter>
<parameter>
<parameterName value="#p_Module" />
<dbType value="String" />
<size value="225" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{MODULE}"/>
</layout>
</parameter>
<parameter>
<parameterName value="#p_Component" />
<dbType value="String" />
<size value="225" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{COMPONENT}"/>
</layout>
</parameter>
</appender>
</log4net>
</configuration>
But it's not inserting them in the database. How can I get that to work?
Simple answer: Because this is an Oracle connection remove the # symbol from the parameter name and it will work.
Sample:
<parameter>
<parameterName value="#p_Module" />
<dbType value="String" />
<size value="225" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{MODULE}"/>
</layout>
</parameter>
I had similar problem, when log4net table was in different schema.
(it surely applies to stored procedure or package too if they are in different schema)
Don't forget to type your schema name before table or stored procedure then.
Sample:
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=4.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
<connectionString ..../>
<commandText value="INSERT INTO schemaName.LOG4NET (LOG_DATE, LOG_LEVEL, LOG_IDENTITY, LOG_MESSAGE, LOG_EXCEPTION) VALUES (:log_date, :log_level, :log_identity, :log_message, :log_exception)" />
....

Resources