我有兴趣了解有关人们如何使用依赖项注入平台注入日志的更多信息。尽管下面的链接和我的示例引用了log4net和Unity,但我不一定要使用这两个。对于依赖项注入/ IOC,我可能会使用MEF,因为这是其余项目(大型)正在建立的标准。
我对依赖关系注入/ ioc非常陌生,对C#和.NET也很陌生(在VC6和VB6大约十年后,在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)直接或间接解析特定的命名记录器实例(可能在同一命名实例的所有请求者之间共享同一实例)。
我不知道这是否很难,但是我希望能够按需获取命名记录器(与类记录器不同)。例如,我可能会基于类名称为我的类创建一个记录器,但是一种方法需要特别繁重的诊断,而我想单独进行控制。换句话说,我可能希望单个类“依赖”两个单独的记录器实例。
让我们从数字1开始。我已经阅读了很多文章,主要是关于stackoverflow的,关于包装是否是个好主意。请参阅上面的“最佳实践”链接,并转到jeffrey hantin的注释中,以获取有关包装log4net的原因的观点。如果您进行了包裹(如果可以有效包裹),您是否将包裹严格地用于注射/去除直接依赖?还是您还会尝试抽象出部分或全部log4net app.config信息?
假设我要使用System.Diagnostics,可能要实现一个基于接口的记录器(甚至使用“通用的” ILogger / ILog接口),并且可能基于TraceSource,以便可以注入它。您是否会实现接口(例如通过TraceSource),并仅按原样使用System.Diagnostics 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上有依赖关系(以MEF的说法导入)(从实现它的程序集导出)。现在我可以有这样的对象:
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信息的情况下,
这已经很长了。我希望它是连贯的。请随时分享有关您的依赖项如何向应用程序中注入日志记录平台(我们很可能考虑使用log4net,NLog或基于System.Diagnostics构建的某些东西(希望是瘦的))的任何特定信息。
您是否注入了“管理器”并使它返回记录器实例?
您是否在自己的config部分或DI平台的config部分中添加了一些自己的配置信息,以使其更容易/可以直接注入记录器实例(即,使依赖项位于ILogger而非ILogManager上)。
如果拥有一个静态或全局容器,该容器中包含ILogManager接口或其中包含一组命名的ILogger实例,该怎么办?因此,不是按常规意义(通过构造函数,属性或成员数据)进行注入,而是根据需要显式解决了日志依赖项。这是依赖注入的好方法还是坏方法。
我将其标记为社区Wiki,因为它似乎不是一个有明确答案的问题。如果有人有其他感觉,请随时进行更改。
谢谢你的帮助!
x.Request.ParentContext.Plan.Type.FullName
获得具体的类名而不是接口名。