log4net MemoryAppender not working

那年仲夏 提交于 2019-12-05 04:26:47

For those that need it, here's how to do it programmatically in C#:

var memoryAppender = new MemoryAppender();
var repository = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
repository.Root.AddAppender(memoryAppender);
var events = memoryAppender.GetEvents();

I used Ralph's code above in my unit testing:

using log4net;
using log4net.Appender;
// ...
internal static MemoryAppender GetMemoLog<T>() where T: class 
{
    var memoLog = new MemoryAppender();
    ILog appendableLog = LogManager.GetLogger(typeof(T).Assembly, typeof(T));
    var repository = (log4net.Repository.Hierarchy.Hierarchy)appendableLog.Logger.Repository;
    repository.Root.AddAppender(memoLog);            
    var logField = typeof(T).GetField("Log", BindingFlags.Static | BindingFlags.NonPublic);
    if (logField != null) logField.SetValue(null, appendableLog);
    return memoLog;
}

This assumes you have a private static Log field on your class:

private static readonly ILog Log = LogManager.GetLogger(typeof(MyClass));

So, in the test, it's just:

var memoLog = GetMemoLog<MyClass>(); 
// followed by test logic, and then... 
var events = memoLog.GetEvents();

The simple sample code you posted works fine for me using log4net 1.2.10.0.

I would recommend downloading the source and stepping through it in a debugger. It may seem a little daunting at first, but you get used to their code pretty quickly and it's not hard to follow. I've done this many times when I had problems with custom constraints and appenders. It really helps solve problems quickly and gives you a much better understanding of how log4net works.

I figured it out. I was using the Compact Framework .dll by mistake. Once I realized that I switched to the .net 2.0 version, which caused a problem with log4net namespace not being found, so I did a search on that and realized I needed to change my .net Framework 4 client Profile to .net Framework 4. I'm now getting the events as expected.

I adapted CZahrobsky's answer. Had to tweak slightly, since my class cannot have static logger by design.

Class under test has the log field declared like:

private ILog Logger = Log4netFactory.GetLogger(typeof(MyClass));

In the GetMemLog logic I have to first create an instance of MyClass and change the logField look up to getField by name 'Logger' and BindingFlags.Instance instead of BindingFlags.Static

//create an instance of the class
var myObject = new MyClass(context);

var memoryLog = new MemoryAppender();
ILog appendableLog = LogManager.GetLogger(typeof(JobQueue).Assembly, typeof(MyClass));
var repository = (log4net.Repository.Hierarchy.Hierarchy)appendableLog.Logger.Repository;
repository.Root.AddAppender(memoryLog);
var logField = typeof(MyClass).GetField("Logger", BindingFlags.NonPublic | BindingFlags.Instance);

if (logField != null)
{
    //set logfield property value for the instance
    logField.SetValue(myObject, appendableLog);
}

Examples on SetValue() for PropertyInfo is here

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!