The class helps to determine the exact output log message, taking in account the conversionPattern that log4net uses for layout. Current usage is you have to attach the listener, then call your BL or a wrapper method which your code uses to write to log, then call the GetRenderedMessage()
method. The purpose is to make sure that even if I modify my wrapper method (I have a wrapper method which adds some properties to log4net's ThreadContext.Properties
and also formats the message in a certain way) the rendered log would remain the same. Are there any improvements or suggestions to make it more "friendly" so someone would know how to use it without reading this intro?
using log4net;
using log4net.Appender;
using log4net.Config;
using System;
using System.IO;
using System.Linq;
namespace TestUtils
{
public class Log4netListener
{
MemoryAppender memAppender;
/// <summary>
/// Attaches the listener so it would capture any log messages written.
/// </summary>
/// <param name="appenderName"></param>
public void AttachLogListener(string appenderName)
{
var appender = LogManager.GetRepository().GetAppenders().Where(a => a.Name == appenderName);
var patternLayout = ((log4net.Layout.PatternLayout)((AppenderSkeleton)(appender.First())).Layout);
memAppender = new MemoryAppender();
memAppender.Layout = patternLayout;
BasicConfigurator.Configure(memAppender);
}
/// <summary>
/// Gets the message written to log. Use this method only after AttachLogListener() was called
/// and a message was written to log4net afterwards.
/// </summary>
public string GetRenderedMessage()
{
if (memAppender == null)
{
throw new InvalidOperationException("The listener was not attached. Make sure you call AttachLogListener() before writing to log.");
}
var events = memAppender.GetEvents();
string logMessage = "";
using (StringWriter writer = new StringWriter())
{
foreach (var ev in events)
{
memAppender.Layout.Format(writer, ev);
}
logMessage = writer.ToString();
}
return logMessage;
}
}
}
Usage:
[TestClass]
public class LoggingTests
{
[AssemblyInitialize]
public static void Configure(TestContext tc)
{
XmlConfigurator.Configure(); // must use this line to make log4net work from test if "configSource" is used in app.config
}
[TestMethod]
public void LogLayout()
{
var listener = new Log4netListener();
listener.AttachLogListener("MyLogFileAppender");
// Call business logic here that writes to log...
string logMessage = listener.GetRenderedMessage();
// Assert...
}
}
AttachLogListener
method is not an option? \$\endgroup\$