Log4net won't Register in database using AdoNetAppender MVC - sql

I'm new in log4net logger and I'm trying to create logger using AdoNetAppender to save the logs to a database.
When I use the Simple Layout
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
and for saving to the database:
<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>
It successfully saves to the database; the issue is that i need to register more details (location, method, line) but it fail to save that in the database.
For that I used the following configuration:
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger %location
%method %line - %message %newline" />
</layout>
And for database inserting:
<commandText value="INSERT INTO Log( [Date],[Thread],[Level],[Logger],
[Locaotion],[Method],[Line],[Message],[Exception])
VALUES (#log_date, #thread, #log_level,
#logger,#location #method, #line, #message, #exception)" />
<parameter>
<parameterName value="#location" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%location" />
</layout>
</parameter>
<parameter>
<parameterName value="#method" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%method" />
</layout>
</parameter>
<parameter>
<parameterName value="#line" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%line" />
</layout>
</parameter>
My C# code :
private static ILog log = LogManager.GetLogger(typeof(HomeController));
//private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
How can I save the full error details in the database?

I get the error i was forget a (,) in database inserting code ans i add Application_Error in global
conversionPattern Code:
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%location] [%method] [%line] - %message %newline" />
</layout>
database inserting code :
<commandText value="INSERT INTO Log( [Date],[Thread],[Level],[Logger],[Location],[Method],[Line],[Message],[Exception])
VALUES (#log_date, #thread, #log_level, #logger, #location, #method, #line, #message, #exception)" />
and for global code :
private static readonly ILog log = LogManager.GetLogger(typeof(MvcApplication));
private void Application_Error(Object sender, EventArgs e)
{
var ex = Server.GetLastError().GetBaseException();
log.Error("App_Error", ex);
}

Related

log4net adonetappender variable is null

After googling this for what seems like forever, I have resorted to asking the question here.
I have added a custom field and variable to the log4net adonetappender. However, after re-working it and trying all practically every suggestion found in the first 4 pages of google, the variable still comes out null.
Any ideas why this happening and any suggestions to help?
Output
RowId Username DateOfActivity Thread Level Logger Message Exception
16 (null) 2015-08-27 18:53:40.607 124732 DEBUG LogToDatabaseTest.Form1 Retrieving info for ID
App.Config
<parameter>
<parameterName value="#username"/>
<dbType value="String" />
<size value="100" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{username}"/>
</layout>
</parameter>
<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="4000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
C# code to set the variable
private void simpleButton1_Click(object sender, EventArgs e)
{
ThreadContext.Properties["username"] = SystemInformation.UserName;
log4net.Config.XmlConfigurator.Configure();//(Watch = false)
try
{
long_ID = Int64.Parse(textEdit1.Text);
}
catch (FormatException fe)
{
XtraMessageBox.Show("ID inputted is not a number! Please enter a valid ID", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
log.Error(String.Format("Retrieving Info for ID: {0}", textEdit1.Text), fe);
return;
}
}
The above was working, it was an error in my programming logic. The variable was not set when the logged events were hit.

Log4Net Logging Variables

Is it possible for log4net to log custom variables, or am I limited to the "pre-configured" variables? e.g.
%appdomain: the friendly name of the appdomain from which the log entry was made
%date: the local datetime when the log entry was made
%exception: a formatted form of the exception object in the log entry, if the entry contains an exception; otherwise, this format
expression adds nothing to the log entry
etc
I need to log session information, from ActionExecutedContext for example. if that's relevant I call log4net from a Global Exception filter.
Is it possible, if so, how?
The currently configured appender, using only aforementioned "pre-configured" variables:
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
<bufferSize value="1" />
<connectionType value="LALALA DELETED" />
<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>
In log4net a layout can contain many patterns, ie. classes that can output one specific information when encountering their string declaration in the layout.
For example %logger in the layout will resolve to the LoggerPatternConverter class, which outputs the logger name when encountered.
There is a global instantation of all the available patterns in the PatternLayout class:
PatternLayout.s_globalRulesRegistry = new Hashtable(45);
PatternLayout.s_globalRulesRegistry.Add("literal", typeof(LiteralPatternConverter));
PatternLayout.s_globalRulesRegistry.Add("newline", typeof(NewLinePatternConverter));
PatternLayout.s_globalRulesRegistry.Add("n", typeof(NewLinePatternConverter));
PatternLayout.s_globalRulesRegistry.Add("c", typeof(LoggerPatternConverter));
but you can add some custom patterns to your layout through the configuration. Just create your own pattern layout converter:
public class ZoinxPatternlayoutConverter: PatternLayoutConverter
{
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
writer.Write("Zoinx at {0:d}", DateTime.Now);
}
}
And add it to your layout:
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message %zoinx %newline" />
<converter>
<name value="zoinx"/>
<type value="App.ZoinxPatternLayoutConverter, App" />
</converter>
</layout>
</appender>
Of course in your case this may be a bit much and you would perhaps benefit from deriving from a Layout directly if you only ever use one property in each layout, such as the RawTimeStampLayout you have in your config. Alternatively you could inherit the PatternLayout to register all the patterns you're interested in once and for all and use them across your configuration.

Log4net does not log to SQL Server 2008 R2 from VS studio 2010

I am trying to Log to SQL Server using Log4net in a WCF Service.I am using Windows authentication and connection to db is fine.
Below are the config File and code.
The File Log is happening correctly.
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
</configSections>
<log4net debug ="true">
<root>
<level value="ALL" />
<appender-ref ref="AdoNetAppender_SqlServer" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=V01KUMAVX\\SQLEXPRESS;initial catalog=dbLog;integrated security=SSPI;" />
<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>
</log4net>
</configuration>
and the code :
public class Service1 : IService1
{
private static readonly log4net.ILog log;
static Service1()
{
log4net.Config.XmlConfigurator.Configure();
log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
public string GetData(int value)
{
log4net.Config.XmlConfigurator.Configure();
log.Debug(string.Format("You entered: {0}", value));
if (!log4net.LogManager.GetRepository().Configured)
{
// log4net not configured
foreach (log4net.Util.LogLog message in log4net.LogManager.GetRepository().ConfigurationMessages)
{
// evaluate configuration message
}
}
return string.Format("You entered: {0}", value);
}
}
How to Log the Log4net Silent errors and how to view them ?
Your Appender names don't match:
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
vs.
<appender-ref ref="AdoNetAppender_SqlServer" />
Change them both to be "AdoNetAppender" or "AdoNetAppender_SqlServer" so that they match (doesn't matter which).

ASP.NET MVC with Castle Logging and log4net woes

In my installer, I have
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<LoggingFacility>(f => f.UseLog4Net("log4net.config"));
}
My log4net config file (which gets deployed to the bin directory of my ASP.NET MVC app) is:
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="100" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=GCO06773\SQLEXPRESS;initial catalog=GEMS;integrated security=false;persist security info=True;User ID=<<userid removed>>;Password=<<password removed>>#" />
<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="INFO" />
<appender-ref ref="AdoNetAppender" />
</root>
</log4net>
I have a controller that's instantiated via Castle.Windsor The relevant code is:
public ILogger Logger { get; set; }
public ActionResult Index()
{
Logger.Info("Info");
Logger.Debug("Debug");
Logger.Error("Error");
Logger.Fatal("Fatal");
Logger.Warn("Warn");
return View();
}
The Logger is a valid castle logger and when I delve into it in the watch window, it appears that there are no appenders associated with the underlying log4net logger, except for the root appender.
According to procmon, the log4net.config file is actually being accessed at some point, so I'm assuming it's being read. I get no errors in the IIS log, no errors in the event log and no exceptions or errors that I can detect. I'm stumped.
UPDATE 1:
Forgot to mention, I added this:
<add key="log4net.Config" value="log4net.config"/>
to the web.config, but it didn't seem to change anything.
UPDATE 2:
I'm using Log4Net 1.2.10.0 with public key token: 1b44e1d426115821 (this matters with Castle Logging which is why I mention it).
The log4net.config file should be in root of your web, not in bin directory.

log4net custom properties not working

I'm trying to implement a custom log4net logger/logmanager so that I can add a new level. I also want to have the schema of the target table (I'm using an AdoNetAppender and SQL Server 2008) to have some optional fields; for instance, the level I'm adding is used to track usage, and one of the fields needs to be a Duration (to tell us how long something took). However, other levels (INFO, DEBUG, FATAL, etc.) will not have any value for Duration. So I need to be able to insert into the table with not all fields having values--preferably without having to reimplement all of the standard levels logging to pass a null value for the irrelevant fields. Ideally, log4net would automatically pass NULL for property values that it cannot find for a particular logging event.
The code in my custom logger is as follows:
public void Usage(TimeSpan? duration, DateTime? startTime, DateTime? endTime, string message)
{
if (IsUsageEnabled)
{
LoggingEvent loggingEvent = new LoggingEvent(GetType(), Logger.Repository, Logger.Name, _currentUsageLevel,
message, null);
if (startTime.HasValue)
{
loggingEvent.Properties["StartTime"] = startTime.Value;
}
else
{
loggingEvent.Properties["StartTime"] = DBNull.Value;
}
if (endTime.HasValue)
{
loggingEvent.Properties["EndTime"] = endTime.Value;
}
else
{
loggingEvent.Properties["EndTime"] = DBNull.Value;
}
if (duration.HasValue)
{
loggingEvent.Properties["Duration"] = duration.Value.TotalMilliseconds;
}
else
{
loggingEvent.Properties["Duration"] = DBNull.Value;
}
Logger.Log(loggingEvent);
}
}
(the assignments to DBNull.Value were added in hopes that that would help log4net pass nulls when the value was not passed, but I hope they can be removed).
The appender config is as follows:
<appender name="SQLAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="my connection string (which actually gets replaced at runtime with a connection string retrieved from a config database)" />
<commandText value="INSERT INTO MyTable ([Date],[Thread],[Level],[Logger],[Message],[Exception], [Login], [StartTime], [EndTime], [Duration]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception, #login, #start_time, #end_time, #duration)" />
<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="4000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
<parameter>
<parameterName value="#login" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{CurrentLogin}" />
</layout>
</parameter>
<parameter>
<parameterName value="#start_time" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout"
value="%property{StartTime}" />
</parameter>
<parameter>
<parameterName value="#end_time" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{EndTime}" />
</layout>
</parameter><parameter>
<parameterName value="#duration" />
<dbType value="Double" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Duration}" />
</layout>
</parameter>
</appender>
When I try to log something with my custom level, it works ONLY if I pass in duration, starttime and endtime. For anything else--including default levels--it seems to fail silently, with no clues in the output window (although logging with default levels throws exceptions saying it can't convert String to DateTime or Double).
Any reason that anyone can see why this would fail silently like this?
I finally figured it out, after tracing through some log4net source. The problem was that I was using a PatternLayout for rendering the custom parameters. This layout coerces null to the string "(null)", which causes problems if you're trying to insert it into, say, a nullable datetime field in the table. The solution is simple: instead of using the PatternLayout layout, use log4net.Layout.RawPropertyLayout. This will pass a null property as null, which is what you want.