具有通用 class 和精度参数的 Log4Net 错误转换模式
Log4Net incorrect conversion pattern with generic class and precision argumen
C# 日志记录框架 log4net 在带有精度参数的转换模式(例如 %logger{1}
)中使用时,似乎无法正确处理所有记录器和附加程序中的通用 class 名称。因为我根本找不到任何相关的问题/问题,所以我决定 post 详细说明该问题,希望有人知道修复/解决方法。
例如,具有上述对话模式的通用 class DiskSaviourHook<T>
应该产生 DiskSaviourHook
,但输出 0, Culture=neutral, PublicKeyToken=null]]
(这显然是错误的)。经过进一步调查,我发现这是因为 log4net 解析器在与 {1}
精度参数一起使用时只查找最后一个点。
更具体地说,记录器名称 Sigma.Core.Training.Hooks.Saviors.DiskSaviorHook'1[[Sigma.Core.Architecture.INetwork, Sigma.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
被视为与任何其他记录器名称一样,尽管它是通用的并且比平常有更多的点(版本的最后一个点像实际的最后一个点一样处理) class)。此问题是否有任何已知的修复/解决方法?
转换模式工作正常。在 log4net 中,记录器名称是分层的,层次结构的级别由句点分隔。这 碰巧 与 classes 在名称空间中的命名方式非常一致,因此使用 class 名称作为记录器名称是一种普遍的做法(从而使它变得容易为整个命名空间配置日志记录)。如此广泛以至于 log4net 对其有重载:LogManager.GetLogger(Type)
被实现为 LogManager.GetLogger(Assembly.GetCallingAssembly(), Type.FullName)
.
不幸的是,这不适用于泛型。通用类型有一个 FullName
,其中包含其类型参数,这打破了 log4net 使用的层次结构。当然,您仍然可以有一个名为 Sigma.Core.Training.Hooks.Saviors.DiskSaviorHook'1[[Sigma.Core.Architecture.INetwork, Sigma.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
的记录器,但就 log4net 而言,它有一个特别难看的层次结构,其中包括 DiskSaviorHook'1[[Sigma
等组件。层次结构纯粹是语法上的,而不是基于解析实际的 class 名称。实际上,使用 class 记录器名称只是一种约定,尽管它很有用。
如果我是 log4net 开发人员并且不关心向后兼容性,我会将 LogManager.GetLogger(Type)
实现为 LogManager.GetLogger(Assembly.GetCallingAssembly(), Type.Namespace + Type.Name)
,这不会遇到此问题。但是我不是,我也懒得开issue
对于客户端代码,有一个简单的解决方法。像这样替换代码:
static ILog log = LogManager.GetLogger(typeof(DiskSaviourHook<T>));
与此:
static ILog log = LogManager.GetLogger(typeof(DiskSaviourHook<>));
或者这个:
static ILog log = LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType
);
后者在文档中被作为样板文件提到,以获得 class 名称但未提及它,它也将 "the right thing" 用于泛型。 (我仍然更喜欢简单地输入 class 自己的名字而不是反思。)
C# 日志记录框架 log4net 在带有精度参数的转换模式(例如 %logger{1}
)中使用时,似乎无法正确处理所有记录器和附加程序中的通用 class 名称。因为我根本找不到任何相关的问题/问题,所以我决定 post 详细说明该问题,希望有人知道修复/解决方法。
例如,具有上述对话模式的通用 class DiskSaviourHook<T>
应该产生 DiskSaviourHook
,但输出 0, Culture=neutral, PublicKeyToken=null]]
(这显然是错误的)。经过进一步调查,我发现这是因为 log4net 解析器在与 {1}
精度参数一起使用时只查找最后一个点。
更具体地说,记录器名称 Sigma.Core.Training.Hooks.Saviors.DiskSaviorHook'1[[Sigma.Core.Architecture.INetwork, Sigma.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
被视为与任何其他记录器名称一样,尽管它是通用的并且比平常有更多的点(版本的最后一个点像实际的最后一个点一样处理) class)。此问题是否有任何已知的修复/解决方法?
转换模式工作正常。在 log4net 中,记录器名称是分层的,层次结构的级别由句点分隔。这 碰巧 与 classes 在名称空间中的命名方式非常一致,因此使用 class 名称作为记录器名称是一种普遍的做法(从而使它变得容易为整个命名空间配置日志记录)。如此广泛以至于 log4net 对其有重载:LogManager.GetLogger(Type)
被实现为 LogManager.GetLogger(Assembly.GetCallingAssembly(), Type.FullName)
.
不幸的是,这不适用于泛型。通用类型有一个 FullName
,其中包含其类型参数,这打破了 log4net 使用的层次结构。当然,您仍然可以有一个名为 Sigma.Core.Training.Hooks.Saviors.DiskSaviorHook'1[[Sigma.Core.Architecture.INetwork, Sigma.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
的记录器,但就 log4net 而言,它有一个特别难看的层次结构,其中包括 DiskSaviorHook'1[[Sigma
等组件。层次结构纯粹是语法上的,而不是基于解析实际的 class 名称。实际上,使用 class 记录器名称只是一种约定,尽管它很有用。
如果我是 log4net 开发人员并且不关心向后兼容性,我会将 LogManager.GetLogger(Type)
实现为 LogManager.GetLogger(Assembly.GetCallingAssembly(), Type.Namespace + Type.Name)
,这不会遇到此问题。但是我不是,我也懒得开issue
对于客户端代码,有一个简单的解决方法。像这样替换代码:
static ILog log = LogManager.GetLogger(typeof(DiskSaviourHook<T>));
与此:
static ILog log = LogManager.GetLogger(typeof(DiskSaviourHook<>));
或者这个:
static ILog log = LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType
);
后者在文档中被作为样板文件提到,以获得 class 名称但未提及它,它也将 "the right thing" 用于泛型。 (我仍然更喜欢简单地输入 class 自己的名字而不是反思。)