与当前方式不同,如下所示:
Log.Info("[Ref] Level 1 Starts ...");
我真的希望能够像这样或者用其他方式来定义log4net.ILog。
[LoggingCategory("Ref")]
public class MyClass
{
public void MyMethod()
{
Log.Info("Level 1 Starts ...");
}
}
Log.Info("[Ref] Level 1 Starts ...");
我真的希望能够像这样或者用其他方式来定义log4net.ILog。
[LoggingCategory("Ref")]
public class MyClass
{
public void MyMethod()
{
Log.Info("Level 1 Starts ...");
}
}
public class Typical
{
private static readonly ILog logger =
LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void F()
{
logger.Info("this message will be tagged with the classname");
}
}
像这样基于任意名称检索记录器是完全可接受的:
public class A
{
private static readonly ILog logger = LogManager.GetLogger("REF");
public void F()
{
logger.Info("this message will be tagged with REF");
}
}
public class B
{
private static readonly ILog logger = LogManager.GetLogger("REF");
public void F()
{
logger.Info("this message will be tagged with REF");
}
}
public class C
{
private static readonly ILog logger = LogManager.GetLogger("UMP");
public void F()
{
logger.Info("this message will be tagged with UMP");
}
}
在上面的例子中,类A和B被认为处于同一“类别”,因此它们使用相同名称检索了记录器。而类C处于不同的类别,因此它检索了具有不同名称的记录器。App
App.DataAccess
App.DataAccess.Create
App.DataAccess.Read
App.DataAccess.Update
App.DataAccess.Delete
App.UI
App.UI.Login
App.UI.Query
App.UI.Options
您还可以配置日志记录输出格式,仅记录完全限定的记录器名称的一部分。例如:
%logger:2
获取完全限定名称的最后两部分。例如,如果您的类的完全限定名称为:
NameSpaceA.NameSpaceB.NameSpaceC.Class
那么按照以上格式,将输出以下日志记录器名称:
NameSpaceC.Class
我对语法不是100%确定,因为我没有使用过,并且现在找不到一个好的例子。
这种方法的一个缺点是,您必须定义和记住您的类别,还必须决定每个类的适当类别(如果您想用属性装饰每个类,则也会出现此问题)。 另外,如果您有多个属于同一类别的类,您无法打开或关闭日志记录,或者更改该类别的子集的日志记录级别。
也许在命名空间层次结构内记录单个命名空间会很有用:
也许您可以根据命名空间将类别分组。 因此,您可能希望将类的直接父命名空间记录为其类别。
因此,对于上述完全限定的类名,您可能希望将 "NameSpaceC" 记录为 "category" 或记录器名称。
我不确定你是否可以直接使用 log4net 实现这一点,但是你可以轻松地编写一个 PatternLayoutConverter 来获取 logger 名称并剥离类名以及任何“更高级别”的命名空间。
以下是一个自定义 PatternLayoutConverter 的示例链接。它需要一个参数,在我的情况下,我想要在字典中查找一个值。 在这种情况下,该参数可以表示完全限定的记录器名称末尾的偏移量(与 log4net 内置记录器名称布局对象的参数相同解释),但可以添加其他代码以仅记录该索引处的单个命名空间。
自定义 Log4net 属性 PatternLayoutConverter(带有索引)
同样,对于给出的完全限定类名:
NameSpaceA.NameSpaceB.NameSpaceC.Class
你可以把直接父命名空间称为“类别”(category)。 如果你定义了自定义的PatternLayoutConverter,category
,并且它带有参数,那么你的配置可能是这样的:
%category
默认情况下,它会返回介于最后一个和倒数第二个'.'
字符之间的子字符串。根据参数,它可以返回任何离散的命名空间。
PatternLayoutConverter可能如下所示(未经测试):
class CategoryLookupPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent)
{
//Assumes logger name is fully qualified classname. Need smarter code to handle
//arbitrary logger names.
string [] names = loggingEvent.LoggerName.Split('.');
string cat = names[names.Length - 1];
writer.Write(setting);
}
}
或者,使用Option属性获取第N个(相对于末尾的)命名空间名称:
class CategoryLookupPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent)
{
//Assumes logger name is fully qualified classname. Need smarter code to handle
//arbitrary logger names.
string [] names = loggingEvent.LoggerName.Split('.');
string cat;
if (Option > 0 && Option < names.Length)
{
cat = names[names.Length - Option];
}
else
{
string cat = names[names.Length - 1];
}
writer.Write(setting);
}
}
@Jonathan的想法非常棒,但是为了定义和维护一个新的记录器包装器,需要您花费额外的编码时间(但是很多人都这样做,并不觉得它是一个特别繁琐的负担)。当然,我的自定义PatternLayoutConverter想法也需要您进行自定义编码。
还有一个缺点是,在每个日志调用上调用GetCategory看起来可能会非常昂贵。
Log4NetLogger
- 日志适配器public class Log4NetLogger
{
private readonly ILog _logger;
private readonly string _category;
public Log4NetLogger(Type type)
{
_logger = LogManager.GetLogger(type);
_category = GetCategory();
}
private string GetCategory()
{
var attributes = new StackFrame(2).GetMethod().DeclaringType.GetCustomAttributes(typeof(LoggingCategoryAttribute), false);
if (attributes.Length == 1)
{
var attr = (LoggingCategoryAttribute)attributes[0];
return attr.Category;
}
return string.Empty;
}
public void Debug(string message)
{
if(_logger.IsDebugEnabled) _logger.Debug(string.Format("[{0}] {1}", _category, message));
}
}
LoggingCategoryAttribute
- 适用于类
[AttributeUsage(AttributeTargets.Class)]
public class LoggingCategoryAttribute : Attribute
{
private readonly string _category;
public LoggingCategoryAttribute(string category)
{
_category = category;
}
public string Category { get { return _category; } }
}
LogTester
是一个测试实现。
[LoggingCategory("LT")]
public class LogTester
{
private static readonly Log4NetLogger Logger = new Log4NetLogger(typeof(LogTester));
public void Test()
{
Logger.Debug("This log message should have a prepended category");
}
}