Programmatically adding and removing log appenders in log4net
Solution 1
I have been using the BasicConfigurator configured with a MemoryAppender. This appender lets you get to the in-memory messages logged during your test.
Solution 2
Using the BasicConfigurator is fine for unit testing (what the OP asked for, but not what's in the subject line). The other answers grab output for a specific logger.
I wanted it all (this was a 'self test' page within a website). In the end I did basically the following:
var root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root;
var attachable = root as IAppenderAttachable;
var appender = new log4net.Appender.MemoryAppender();
if(attachable!=null)
attachable.AddAppender(appender);
// do stuff
var loggingEvents = appender.GetEvents();
foreach (var loggingEvent in loggingEvents)
loggingEvent.WriteRenderedMessage(writer);
if(attachable!=null)
attachable.RemoveAppender(appender);
...but wrapped up as a Disposable as per @Pawel's approach
UPDATE: Pawel's answer was deleted, so I am adding his link here: Programmatically check Log4Net log.
Solution 3
The following code was originally found on the apache mailing list archives and should solve the problem of adding and removing log4net appenders in code
/// <summary>
/// dataLog
/// </summary>
protected static readonly IDeviceCommunicationsLog dataLog =
DeviceCommunicationsLogManager.GetLogger("LIS3.Data");
Each connection adds and removes a file appender programmatically:
/// <summary>
/// add connection specific appender
/// </summary>
void AddAppender()
{
// check if logging is endabled
if( this.IsLoggingEnabled() )
{
try
{
// get the interface
IAppenderAttachable connectionAppender = (IAppenderAttachable)this.DataLog.Logger;
// need some application configuration settings
NameValueCollection appSettings = ConfigurationSettings.AppSettings;
// get the layout string
string log4netLayoutString = appSettings["log4net.LIS3.LayoutString"];
if( log4netLayoutString == null )
{
// use default setting
log4netLayoutString = "%d [%x]%n %m%n %P MessageData}%n%n";
}
// get logging path
string log4netPath = appSettings["log4net.Path"];
if( log4netPath == null )
{
// use default path
log4netPath = ".\\";
}
// create the appender
this.rollingFileAppender = new RollingFileAppender();
// setup the appender
this.rollingFileAppender.MaxFileSize = 10000000;
this.rollingFileAppender.MaxSizeRollBackups = 2;
this.rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Size;
this.rollingFileAppender.StaticLogFileName = true;
string appenderPath = LogSourceName + ".log";
// log source name may have a colon - if soreplace with underscore
appenderPath = appenderPath.Replace( ':', '_' );
// now add to log4net path
appenderPath = Path.Combine( log4netPath, appenderPath );
// update file property of appender
this.rollingFileAppender.File = appenderPath;
// add the layout
PatternLayout patternLayout = new PatternLayout( log4netLayoutString );
this.rollingFileAppender.Layout = patternLayout;
// add the filter for the log source
NDCFilter sourceFilter = new NDCFilter();
sourceFilter.StringToMatch = this.LogSourceName;
this.rollingFileAppender.AddFilter( sourceFilter);
// now add the deny all filter to end of the chain
DenyAllFilter denyAllFilter = new DenyAllFilter();
this.rollingFileAppender.AddFilter( denyAllFilter );
// activate the options
this.rollingFileAppender.ActivateOptions();
// add the appender
connectionAppender.AddAppender( this.rollingFileAppender );
}
catch( Exception x )
{
this.ErrorLog.Error( "Error creating LIS3 data log appender for " + LogSourceName, x );
}
}
}
/// <summary>
/// remove connection specific appender
/// </summary>
void RemoveAppender()
{
// check if we have one
if( this.rollingFileAppender != null )
{
// cast to required interface
IAppenderAttachable connectionAppender = (IAppenderAttachable)this.DataLog.Logger;
// remove the appendier
connectionAppender.RemoveAppender( rollingFileAppender );
// set to null
this.rollingFileAppender = null;
}
}
Solution 4
How about:
((log4net.Repository.Hierarchy.Logger) theLogger.Logger).RemoveAppender("SomeAppender");
same for add.
Related videos on Youtube
Pete
I have worked professionally with software development since 1997. Since year 2000 I have worked as an independent contractor, helping various business in developing their internal and external IT systems. Since 2002 I have worked almost exclusively with the .NET framework. Of notable work can be mentioned IT-Jobbank, Denmark's largest online job board for IT professionals, where I was the lead developer and architect. SOreadytohelp
Updated on July 09, 2022Comments
-
Pete almost 2 years
I have a component that uses log4net. I want to create unit tests, that validate that certain error conditions result in the correct logging.
I was thinking that the best way to do this is to create an ILogAppender implementation, for example a mock. I would then add the log appender to log4net during test setup, inspect what was written during test validation, and remove it again during test teardown.
Is this possible?
-
Pete over 14 yearsI finally got to implementing this, and it solves the problem very nicely
-
Aasmund Eldhuset about 13 years+1; saved me from making a stub implementation of
ILog
and injecting it into all of my classes :-) -
Mark W over 8 yearsDo you know how to make the add actually work? I've written a unit test to test the implementation of a custom appender I created, but unfortunately the Add method of Logger is a lie, because the ILog implementation that LogManager.GetLogger(string) returns has a read only collection of appenders. It ends up silently consuming the exception it throws internally, and never really adds the appender.
-
Vivelin almost 8 yearsNote that if you do not use the BasicConfigurator or XmlConfigurator anywhere, you need to set Hierarchy.Configured to true to make log4net actually do anything.