如何将Log4net与依赖注入一起使用


78

我试图找出依赖注入框架对log4net的正确模式和用法。

Log4Net使用ILog界面,但需要我打电话

LogManager.GetLogger(Reflection.MethodBase.GetCurrentMethod().DeclaringType)

在每个需要记录信息的类或方法中。这似乎违反了IoC原则,使我不得不使用Log4Net。

我应该以某种方式在某处放置另一层抽象吗?

另外,我需要这样记录自定义属性,例如当前用户名:

log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;

我如何封装它,这样我就不必记住每次都要做,而仍然保持当前正在记录的方法。我应该做这样的事情还是我完全错过了分数?

public static class Logger
{
    public static void LogException(Type declaringType, string message, Exception ex)
    {
        log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;
        ILog log = LogManager.GetLogger(declaringType);
        log.Error(message, ex);
    }
}

1
更有趣的问题是您使用的是哪个DI容器?
CodeMonkeyKing

Answers:


61

我认为您在这里看不到森林。ILog和LogManager是轻量级的外观,几乎等同于Apache commons-logging的1:1,并且实际上并未将您的代码耦合到其余的log4net。

<rant>
我还发现,几乎总是有人在log4net周围创建MyCompanyLogger包装器时,他们会很想念这一点,并且会失去框架的重要和有用的功能,会丢掉有用的信息,甚至使用简化的ILog界面也会失去性能提升,或以上所有内容。换句话说,包装log4net以避免与之耦合是一种反模式
</rant>

如果您需要注入它,请通过属性来访问记录器实例以启用注入功能,但可以通过老式方式创建默认实例。

至于在每条日志消息中包括上下文状态,您需要添加一个全局属性,该属性ToString()可以解析您要查找的内容。例如,对于当前堆大小:

public class TotalMemoryProperty
{
    public override string ToString()
    {
        return GC.GetTotalMemory(false).ToString();
    }
}

然后在启动过程中将其插入:

GlobalContext.Properties["TotalMemory"] = new TotalMemoryProperty();

7
你的怒气在这里不合常理。这个家伙在问如何将ILog实例注入到容器内部的对象中。这样做有很多原因。
CodeMonkeyKing

1
@CodeMonkeyKing:蚂蚁针对他建议的在log4net和他的代码之间创建抽象层的方法,特别是在问题末尾的示例代码块。
Jeffrey Hantin

4
@JeffreyHantin在您看来,这可能是一种反模式,但是我发现那里的观点与编写代码的工程师一样多。我的观点当然是:)
CodeMonkeyKing

1
我知道这是一篇过时的文章,但是请您解释一下为什么这样的包装是“不好的”吗?ILog和LogManager驻留在log4net命名空间中,通过在我的代码中使用这些类型,这是否使我与log4net耦合?我在这里想念什么?
Andrew Stephens 2014年

1
包装log4net是一个好习惯。问题不在于包装库,而是表现不佳。
Dan

2

我的方法是创建自己的接口,并让一个类实现使用Log4Net的接口,并注入该类。这样,您就不受Log4Net的束缚了……您可以为新的记录器创建另一个类并注入该类。


2

如果您确实担心要使用多个记录器,则始终可以声明一个全局记录器,并为您的所有记录需求调用该记录器。不利的一面是,您失去了识别发出日志的类的内置功能,但是您也可以将自己的自定义消息注入日志中以识别类。

这取决于您希望日志记录的健壮性。您也可以简单地将记录器放在主类上,并让所有未处理的异常冒泡到它进行记录。


但是可以肯定的是,您通常不仅希望记录异常,还希望记录更多日志?
2010年

您是否在这里建议使用Singleton模式?我希望不是。
Nate Zaugg

2

这样做的另一种方式是连接log4net ILog接口容器注册序列,如下所示:(在下面的ASP.NET上下文中使用Castle作为示例)

container.Register(Component.For<ILog>().LifeStyle
    .PerWebRequest.UsingFactoryMethod(() => LogManager.GetLogger(
    MethodBase.GetCurrentMethod().DeclaringType)));

并在需要时仅构造器注入ILog。


此作品更好,我想,当你实现类权记录器正在构建:Component.For<ILog>().UsingFactoryMethod((kernel, model, cc) => LogManager.GetLogger(cc.Handler.ComponentModel.Implementation))
马克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.