依赖注入和命名记录器

2024-03-09

我有兴趣了解更多有关人们如何使用依赖注入平台注入日志记录的信息。尽管下面的链接和我的示例引用了 log4net 和 Unity,但我不一定会使用其中任何一个。对于依赖注入/IOC,我可能会使用 MEF,因为这是项目(大型)其余部分所采用的标准。

我对依赖注入/ioc 非常陌生,对 C# 和 .NET 也很陌生(在过去 10 年左右的 VC6 和 VB6 之后,我在 C#/.NET 中编写了很少的生产代码)。我对现有的各种日志记录解决方案进行了大量调查,因此我认为我对它们的功能集有很好的掌握。我只是不太熟悉注入一个依赖项的实际机制(或者,也许更“正确”,获取注入一个依赖项的抽象版本)。

我看过其他与日志记录和/或依赖项注入相关的帖子,例如:依赖注入和日志记录接口 https://stackoverflow.com/questions/522370/dependency-injection-and-logging-interfaces

记录最佳实践 https://stackoverflow.com/questions/576185/logging-best-practices

Log4Net Wrapper 类会是什么样子? https://stackoverflow.com/questions/166438/what-would-a-log4net-wrapper-class-look-like

再次关于 log4net 和 Unity IOC 配置 https://stackoverflow.com/questions/1320844/again-about-log4net-and-unity-ioc-config

我的问题与“如何使用 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");

所以,我想我的“要求”会是这样的:

  1. 我想使我的产品来源免受对日志平台的直接依赖。

  2. 我希望能够通过某种依赖注入(可能是 MEF)直接或间接地解析特定的命名记录器实例(可能在同一命名实例的所有请求者之间共享同一实例)。

  3. 我不知道我是否会将此称为硬要求,但我希望能够按需获取命名记录器(与类记录器不同)。例如,我可能根据类名称为我的类创建一个记录器,但一种方法需要特别繁重的诊断,我想单独控制这些诊断。换句话说,我可能希望单个类“依赖”两个单独的记录器实例。

让我们从第一点开始。我读过很多文章,主要是在 stackoverflow 上,关于换行是否是一个好主意。请参阅上面的“最佳实践”链接并转到杰弗里·汉丁 https://stackoverflow.com/users/55637/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 实例,并按名称将它们添加到(?)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 构建的其他东西(希望是薄的))依赖注入到您的应用程序中的任何具体信息。

您是否注入了“管理器”并让它返回记录器实例?

您是否在自己的配置部分或 DI 平台的配置部分中添加了一些自己的配置信息,以便更容易/可能直接注入记录器实例(即使您的依赖项位于 ILogger 而不是 ILogManager)。

拥有一个静态或全局容器,其中包含 ILogManager 接口或一组命名的 ILogger 实例怎么样?因此,日志依赖项不是传统意义上的注入(通过构造函数、属性或成员数据),而是根据需要显式解决。这是依赖注入的好还是坏方法?

我将其标记为社区维基,因为它看起来不像是一个有明确答案的问题。如果有人有其他感觉,请随意更改。

谢谢你的帮助!


我使用 Ninject 来解析记录器实例的当前类名,如下所示:

kernel.Bind<ILogger>().To<NLogLogger>()
  .WithConstructorArgument("currentClassName", x => x.Request.ParentContext.Request.Service.FullName);

NLog 实现的构造函数可能如下所示:

public NLogLogger(string currentClassName)
{
  _logger = LogManager.GetLogger(currentClassName);
}

我想,这种方法也应该适用于其他 IOC 容器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

依赖注入和命名记录器 的相关文章

随机推荐

  • 选择列值已更改的行

    假设我有下表 Value Time 0 15 06 2012 8 03 43 PM 1 15 06 2012 8 03 43 PM 1 15 06 2012 8 03 48 PM 1 15 06 2012 8 03 53 PM 1 15 0
  • 为什么这些 Tomcat 服务器的 JVM 每小时执行一次 Full GC?

    我们运行许多 Tomcat 服务器 并观察到完整的垃圾收集 GC 通常每小时执行一次 特别是当内存使用率相对较低时 精确时间似乎与应用程序服务器启动的时间有关 如果服务器在 01 13 启动 则在 02 13 完成一次 Full GC 下一
  • 如何插入只有默认值的记录?

    如果我有一个包含所有默认列的 SQL 表 例如 标识列 任意数量的所有列都具有默认值 那么插入没有给出显式值的行的 SQL 语句是什么 insert MyTable doh no fields values doh no values 有什
  • 通过嵌入式服务器测试 Solr

    我正在为我的 solr indexer 应用程序编写一些测试 遵循测试最佳实践 我想编写独立的代码 只需加载schema xml and solrconfig xml并为索引搜索测试创建临时数据树 由于应用程序大部分是用java编写的 我正
  • 通过REST API查询HealthKit数据

    是否可以像查询常规 API 经用户同意 一样从 Healthkit 获取数据并将其存储在我的 web 应用程序中 就像是 healthkit com api v1 user GetWeight 如果是 我在哪里可以找到可用方法的列表 如果没
  • D3.js:使用鼠标滚轮滚动缩放 x 轴和数据

    我搜索了其他相关问题 但无论是因为我是 D3 新手 还是作为一名编码员生疏 我无法弄清楚这一点 我有一个图表 我希望能够通过仅在 a 轴和数据上滚动鼠标滚轮来放大 现在 我的整个图表在鼠标滚轮的滚动上进行缩放 而不是仅在 x 轴上进行缩放
  • 使用异步控制器的强类型 RedirectToAction (Futures)

    有了这个代码 它给了我一个警告 Because this call is not awaited execution of the current method continues before the call is completed
  • 如何实现自定义“fmt::Debug”特征?

    我想你会做这样的事情 extern crate uuid use uuid Uuid use std fmt Formatter use std fmt Debug derive Debug struct BlahLF id Uuid im
  • Spring 的 Joda Time 日期时间格式无效

    我有一个项目已经使用 Jackson Hibernate4Module 进行对象映射 现在 我想在项目中使用 Joda Time 并添加了 joda time joda time hibernate jackson datatype jod
  • 无法在 iTunes Connect 中上传我的应用程序的屏幕截图 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 由于更新 我尝试更改应用程序的屏幕截图 但苹果给了我错误 发生网络超时错误 请稍后再试 有什么帮助吗 请将浏览器切换到其他浏览器 然后是
  • Android Studio 键盘快捷键控制

    谁能给我一些 Android Studio 键盘快捷键所有控件的建议或链接 Move to File gt Settings gt Keymap并改变Keymaps设置到eclipse 这样就可以像在eclipse中一样使用快捷键了
  • Mathematica“AppendTo”函数问题

    我是 Mathematica 的新手 在向数据表添加列时遇到了重大故障 我在 Vista 中运行 Mathematica 7 我在RFD上花了很多时间才来这里问 我有一个包含三列五行的数据表 mydata 我正在尝试将两个包含五个元素的列表
  • 数组切片返回 [object Object] 而不是值

    我试图获取特定 div 被删除时的位置 在一些帮助下 我整理了下面的代码 我在最后一点添加了尝试获取特定值 但它只是返回 object Object 而不是 0 0 或 0 120 之类的东西 那么问题是如何从数组中获取实际值 Here h
  • Chart.js 时间序列跳过几天

    我有一个非常简单的条形图 其中每个数据点由日期 天 和数字组成 也许唯一的特点是并非涵盖每个日期 即有些日子没有数据点 绘制图表时 仅显示那些具有与其关联的数据点的日期 所有其他日期都被简单地省略 因此 x 轴分布不均匀并且会跳过值 如何确
  • 为什么用于 XML 文件分析的 PowerShell 工作流明显慢于非工作流脚本

    我正在编写一个 PowerShell 程序来分析 1900 多个大型 XML 配置文件 50000 多行 1 5Mb 的内容 为了进行测试 我将 36 个测试文件移动到我的 PC Win 10 PS 5 1 32GB RAM 并编写快速脚本
  • Microsoft(SQL)服务器许可[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我们正在规划一个浏览器应用程序 xbap 它将与 WCF 服务进行交互 这些 WCF 服务从 SQL 数据库获取信息 我们的每个客户在此服
  • 在 Visual Studio 中调试 x64 Azure Functions

    我正在通过 Visual Studio 编写 C Azure 函数 该函数通过博客存储触发 并且使用 x64 C DLL 处理 blob 问题是随 Visual Studio 安装的默认 Azure 函数工具仅具有 x86 版本的函数 ex
  • Fluent NHibernate join 不使用主键

    我试图从连接表中获取单个属性 其中主表中的非 PK 连接到外部表的 PK 下面是一个过于简单化我想要完成的事情的例子 我不想提及外国实体 Tables CREATE TABLE Status Id int Body text Categor
  • 我们可以将TFS 2015直接迁移到Azure DevOps吗?

    我计划转向 Azure DevOps 目前我们内部有 TFS2015 根据这篇文章 我们必须先迁移到 TFS 2018 然后才能迁移到 Azure DevOps 我们不能从 TFS 2015 迁移到 Azure DevOps 吗 根据本文
  • 依赖注入和命名记录器

    我有兴趣了解更多有关人们如何使用依赖注入平台注入日志记录的信息 尽管下面的链接和我的示例引用了 log4net 和 Unity 但我不一定会使用其中任何一个 对于依赖注入 IOC 我可能会使用 MEF 因为这是项目 大型 其余部分所采用的标