我正在试图找出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);
}
}
答案 0 :(得分:62)
我想你在这里没有看到树林。 ILog和LogManager是一个轻量级的façade,差不多相当于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();
答案 1 :(得分:2)
我是如何创建自己的接口的,并且有一个使用Log4Net的接口的类实现,并注入了该类。这样你就不会被Log4Net绑定了...你可以为新的记录器创建另一个类并注入该类。
答案 2 :(得分:2)
如果您真的担心有多个记录器,您可以随时声明一个全局记录器,并为满足您的所有记录需求而调用它。这样做的缺点是您失去了识别发出日志的类的内置功能,但您也可以将自己的自定义消息注入日志以识别该类。
这取决于您希望日志记录的强大程度。您也可以简单地将记录器放在主类中,让所有未处理的异常冒泡到它进行记录。
答案 3 :(得分:2)
另一种方法是连接log4net ILog接口容器注册序列,如下所示:(在下面的ASP.NET上下文中使用Castle作为示例)
container.Register(Component.For<ILog>().LifeStyle
.PerWebRequest.UsingFactoryMethod(() => LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType)));
只需构造函数即可在需要时注入ILog。