如何使用 log4net 依赖注入

我正在尝试用一个依赖注入框架找出 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);
}
}
17805 次浏览

我如何做到这一点是创建我自己的接口,并有一个类实现该接口,使用 Log4Net,并注入该类。这样,您就不必绑定到 Log4Net... ... 您只需为一个新的日志记录器创建另一个类并注入该类。

我觉得你在这里看到的不是树木而是森林。ILog 和 LogManager 是一个轻量级的外观,几乎与 Apache commons-log 等价,并且实际上不会将您的代码与 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();

如果您确实关心拥有多个日志记录器,那么您总是可以声明一个全局日志记录器,并根据所有日志记录需要调用它。这样做的缺点是,您将失去内置的识别发出日志的类的能力,但是您也可以将自己的自定义消息注入到日志中以识别该类。

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

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

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

只需要构造函数注入 ILog 就可以了。