我有兴趣了解更多关于人们如何将日志注入依赖注入平台的信息。虽然下面的链接和我的例子都提到了 log4net 和 Unity,但我不一定要使用它们中的任何一个。对于依赖注入/IOC,我可能会使用 MEF,因为这是该项目(大型)其余部分正在制定的标准。
我是依赖注入/国际奥委会的新成员,也是 C # 和 C # 的新成员。NET (只用 C #/编写了很少的生产代码。NET).我对各种各样的日志记录解决方案做了大量的调查,所以我认为我已经对它们的特性集有了一个很好的处理。我只是不够熟悉注入一个依赖项的实际机制(或者,也许更“正确”的是,注入一个依赖项的抽象版本)。
我看过其他关于日志和/或依赖注入的帖子,比如: 依赖注入和日志接口
我的问题与“如何使用 ioc 工具 yyy 注入日志平台 xxx?”相反,我感兴趣的是人们如何处理包装日志平台(通常是这样,但并不总是推荐)和配置(例如 app.config)。例如,以 log4net 为例,我可以配置(在 app.config 中)一些日志记录器,然后按照标准方法获得这些日志记录器(不需要依赖注入) ,如下所示:
private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
或者,如果我的日志记录器不是以类命名的,而是以函数区域命名的,我可以这样做:
private static readonly ILog logger = LogManager.GetLogger("Login");
private static readonly ILog logger = LogManager.GetLogger("Query");
private static readonly ILog logger = LogManager.GetLogger("Report");
所以,我想我的“要求”应该是这样的:
我希望将我的产品源与日志平台上的直接依赖隔离开来。
我希望能够通过某种依赖注入(可能是 MEF)直接或间接地解析一个特定的命名 logger 实例(可能在所有具有相同命名实例的请求者之间共享相同的实例)。
我不知道这是否是一个硬性要求,但是我希望能够根据需要获得一个命名日志记录器(与类日志记录器不同)。例如,我可能根据类名为类创建一个日志记录器,但是有一个方法需要特别繁重的诊断,我想单独控制它。换句话说,我可能希望一个类“依赖”两个独立的日志记录器实例。
我们从1号开始。我已经读了很多文章,主要是关于 stackoverflow 的,关于包装是否是一个好主意。查看上面的“最佳实践”链接,并转到 Jeffrey Hantin的评论,了解为什么包装 log4net 不好。如果你做了包装(如果你能有效地包装) ,你会为了注入/去除直接依赖而严格地包装吗?或者您还会尝试抽象出 log4net app.config 的部分或全部信息吗?
假设我想使用 System。我可能希望实现一个基于接口的日志记录器(甚至可能使用“常见的”ILogger/ILog 接口) ,它可能基于 TraceSource,这样我就可以注入它。你会实现接口,比如说通过 TraceSource,然后使用 System 吗。诊断 app.config 信息如何?
就像这样:
public class MyLogger : ILogger
{
private TraceSource ts;
public MyLogger(string name)
{
ts = new TraceSource(name);
}
public void ILogger.Log(string msg)
{
ts.TraceEvent(msg);
}
}
像这样使用它:
private static readonly ILogger logger = new MyLogger("stackoverflow");
logger.Info("Hello world!")
继续讨论第二个问题... 如何解析一个特定的命名日志记录器实例?我是否应该只利用我选择的日志平台的 app.config 信息(即根据 app.config 中的命名方案解析日志记录器) ?因此,在 log4net 的情况下,我是否可以选择“注入”LogManager (注意,我知道这是不可能的,因为它是一个静态对象) ?我可以包装 LogManager (称为 MyLogManager) ,给它一个 ILogManager 接口,然后解析 MyLogManager.ILogManager 接口。我的其他对象可以依赖于 ILogManager (从实现它的程序集导出)。现在我可以有这样的物体:
public class MyClass
{
private ILogger logger;
public MyClass([Import(typeof(ILogManager))] logManager)
{
logger = logManager.GetLogger("MyClass");
}
}
任何时候调用 ILogManager,它都会直接委托给 log4net 的 LogManager。或者,被包装的 LogManager 可以获取它基于 app.config 获取的 ILogger 实例,并将它们添加到(a?)按名称命名的 MEF 容器。稍后,当请求同名的日志记录器时,将查询已包装的 LogManager 以获取该名称。如果 ILogger 在那里,则按照这种方式进行解析。如果 MEF 可以做到这一点,这样做有什么好处吗?
在这种情况下,实际上,只有 ILogManager 是“注入的”,它可以像 log4net 通常所做的那样分发 ILogger 实例。这种类型的注入(本质上是一个工厂)与注入命名的日志记录器实例相比如何?这确实允许更容易地利用 log4net 的(或其他日志平台) app.config 文件。
我知道我可以像下面这样从 MEF 容器中获取命名实例:
var container = new CompositionContainer(<catalogs and other stuff>);
ILogger logger = container.GetExportedValue<ILogger>("ThisLogger");
但是如何将命名实例放入容器中呢?我知道基于属性的模型,在这个模型中我可以有不同的 ILogger 实现,每个实现都被命名(通过 MEF 属性) ,但是这并没有真正帮助到我。有没有一种方法可以创建 app.config (或其中的一个部分)这样的东西,它可以按名称列出日志记录器(所有相同的实现)并且 MEF 可以读取?是否应该有一个中央“管理器”(比如 MyLogManager)通过底层 app.config 解析命名日志记录器,然后将解析后的日志记录器插入到 MEF 容器中?通过这种方式,可以让其他人访问同一个 MEF 容器(尽管 MyLogManager 不知道如何使用 log4net 的 app.config 信息,这个容器似乎不能直接解析任何命名的 logger)。
已经很久了。我希望它是连贯的。请随意分享关于如何依赖注入日志平台的任何特定信息(我们最有可能考虑 log4net、 NLog 或者在 System 上构建的其他东西(希望是瘦的)。(诊断)到您的应用程序中。
您是否注入了“ Manager”并让它返回日志记录器实例?
您是否在自己的配置部分或 DI 平台的配置部分中添加了一些自己的配置信息,以使直接注入日志记录器实例变得更加容易/可行(即将依赖关系设置为 ILogger 而不是 ILogManager)。
如果有一个静态或全局容器,其中既有 ILogManager 接口,也有一组命名的 ILogger 实例。因此,与传统意义上的注入(通过构造函数、属性或成员数据)不同,日志依赖关系是根据需要显式解决的。这是依赖注入的好方法还是坏方法。
我把它标记为一个社区维基,因为它看起来不像一个有明确答案的问题。如果有人不这么认为,请随意改变。
谢谢你的帮助!