如何按名称空间对 log4net 中的日志消息进行分组?
我正在尝试实现自己的 log4net 附加程序,它将按名称空间将消息分组。 问题是,我无法按照我的意愿让 log4net 记录位置信息。
class Program
{
protected static IWindsorContainer container;
static void Main(string[] args)
{
container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));
// add facilities
container.AddFacility("logging.facility", new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
container.Register(Component.For<ParentClass>().ImplementedBy<ParentClass>());
container.Register(Component.For<ChildClass>().ImplementedBy<ChildClass>());
var parentClass = container.Resolve<ParentClass>();
var childClass = container.Resolve<ChildClass>();
parentClass.Init();
childClass.Init();
}
}
public class ParentClass
{
private readonly ILogger logger;
private ILog localLogger;
public ParentClass(ILogger logger)
{
this.logger = logger;
localLogger = LogManager.GetLogger(GetType());
logger.Info("ctor ioc logger, type: {0}",GetType().Name);
localLogger.Info(string.Format("ctor local logger, type: {0}", GetType().Name));
}
public void Init()
{
logger.Info("init ioc logger, type: {0}", GetType().Name);
localLogger.Info(string.Format("init local logger, type: {0}", GetType().Name));
}
}
public class ChildClass : ParentClass
{
public ChildClass(ILogger logger) : base(logger)
{
}
}
输出的
2011-03-28 09:58:55 INFO 10 ParentClass - ctor ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor local logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - init ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - init local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - init ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - init local logger, type: ChildClass
问题是,log4net 类名始终输出为基类名(ParentClass)。我最初认为,这可能是温莎城堡,导致了这样的问题,但结果显示,即使我手动创建记录器实例,它仍然记录基类名称。可能有人知道,如何强制 log4net 写入实际实例类名?
更新
这里使用了 log4net 配置:
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="c:\temp\testlog.log" />
<appendToFile value="true" />
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%utcdate{yyyy-MM-dd HH:mm:ss} %level %thread %C{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="RollingFile" />
</root>
上面的输出是我得到的,我期望得到的是:
2011-03-28 09:58:55 INFO 10 ParentClass - ctor ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ChildClass - ctor ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ChildClass - ctor local logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - init ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - init local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ChildClass - init ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ChildClass - init local logger, type: ChildClass
更新 2
如果有人需要这样的东西,这里是工作附加器实现:
public class GroupStringListAppender : log4net.Appender.AppenderSkeleton
{
private readonly int listLength = 30;
private readonly Func<string, string> pathFuction;
private readonly Dictionary<string, List<string>> messagesDictionary = new Dictionary<string, List<string>>();
public GroupStringListAppender(int listLength, Func<string, string> pathFuction)
{
this.listLength = listLength;
this.pathFuction = pathFuction;
}
public List<string> GetMessages(string path)
{
return messagesDictionary[path];
}
protected override void Append(LoggingEvent loggingEvent)
{
var msg = loggingEvent.RenderedMessage;
var path = pathFuction.Invoke(loggingEvent.LoggerName);
if (!messagesDictionary.ContainsKey(path))
{
messagesDictionary.Add(path, new List<string>());
OnNewPathCreated(path);
}
var list = messagesDictionary[path];
while (list.Count - listLength > 0)
{
list.RemoveAt(0);
}
list.Add(msg);
OnAppended(path, list);
}
public event AppendedEventHandler Appended;
public void OnAppended(string path, List<string> list)
{
AppendedEventHandler handler = Appended;
if (handler != null) handler(this, new LoggerMessageAppendedEventArgs(path, list));
}
public event NewPathCreatedHandler NewPathCreated;
public void OnNewPathCreated(string path)
{
var handler = NewPathCreated;
if (handler != null) handler(this, new NewPathCreatedHandlerArgs(path));
}
}
public delegate void NewPathCreatedHandler(object sender, NewPathCreatedHandlerArgs args);
public class NewPathCreatedHandlerArgs : EventArgs
{
public string Path { get; set; }
public NewPathCreatedHandlerArgs(string path)
{
Path = path;
}
}
public class LoggerMessageAppendedEventArgs : EventArgs
{
public string Path { get; set; }
public List<string> List { get; set; }
public LoggerMessageAppendedEventArgs(string path, List<string> list)
{
Path = path;
List = list;
}
}
public delegate void AppendedEventHandler(object sender, LoggerMessageAppendedEventArgs e);
I'm trying to implement own log4net appender, that would group messages by namespace into groups.
Problem is, that i can't get log4net to log LocationInformation, as i would like.
class Program
{
protected static IWindsorContainer container;
static void Main(string[] args)
{
container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));
// add facilities
container.AddFacility("logging.facility", new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
container.Register(Component.For<ParentClass>().ImplementedBy<ParentClass>());
container.Register(Component.For<ChildClass>().ImplementedBy<ChildClass>());
var parentClass = container.Resolve<ParentClass>();
var childClass = container.Resolve<ChildClass>();
parentClass.Init();
childClass.Init();
}
}
public class ParentClass
{
private readonly ILogger logger;
private ILog localLogger;
public ParentClass(ILogger logger)
{
this.logger = logger;
localLogger = LogManager.GetLogger(GetType());
logger.Info("ctor ioc logger, type: {0}",GetType().Name);
localLogger.Info(string.Format("ctor local logger, type: {0}", GetType().Name));
}
public void Init()
{
logger.Info("init ioc logger, type: {0}", GetType().Name);
localLogger.Info(string.Format("init local logger, type: {0}", GetType().Name));
}
}
public class ChildClass : ParentClass
{
public ChildClass(ILogger logger) : base(logger)
{
}
}
output is
2011-03-28 09:58:55 INFO 10 ParentClass - ctor ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor local logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - init ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - init local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - init ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - init local logger, type: ChildClass
problem is, that log4net class name always outputs as base class name (ParentClass). I've thought initially, that may be castle windsor, that is causing such problem, but as results show, even if i create logger instance manually, it still logs base class name. May be anyone has idea, how to force log4net write actual instance class name?
update
here goes log4net config used:
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="c:\temp\testlog.log" />
<appendToFile value="true" />
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%utcdate{yyyy-MM-dd HH:mm:ss} %level %thread %C{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="RollingFile" />
</root>
output above is what i get, what i expect to get is:
2011-03-28 09:58:55 INFO 10 ParentClass - ctor ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - ctor local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ChildClass - ctor ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ChildClass - ctor local logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ParentClass - init ioc logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ParentClass - init local logger, type: ParentClass
2011-03-28 09:58:55 INFO 10 ChildClass - init ioc logger, type: ChildClass
2011-03-28 09:58:55 INFO 10 ChildClass - init local logger, type: ChildClass
update 2
in case anybody needs such thing, here is working appender implementation:
public class GroupStringListAppender : log4net.Appender.AppenderSkeleton
{
private readonly int listLength = 30;
private readonly Func<string, string> pathFuction;
private readonly Dictionary<string, List<string>> messagesDictionary = new Dictionary<string, List<string>>();
public GroupStringListAppender(int listLength, Func<string, string> pathFuction)
{
this.listLength = listLength;
this.pathFuction = pathFuction;
}
public List<string> GetMessages(string path)
{
return messagesDictionary[path];
}
protected override void Append(LoggingEvent loggingEvent)
{
var msg = loggingEvent.RenderedMessage;
var path = pathFuction.Invoke(loggingEvent.LoggerName);
if (!messagesDictionary.ContainsKey(path))
{
messagesDictionary.Add(path, new List<string>());
OnNewPathCreated(path);
}
var list = messagesDictionary[path];
while (list.Count - listLength > 0)
{
list.RemoveAt(0);
}
list.Add(msg);
OnAppended(path, list);
}
public event AppendedEventHandler Appended;
public void OnAppended(string path, List<string> list)
{
AppendedEventHandler handler = Appended;
if (handler != null) handler(this, new LoggerMessageAppendedEventArgs(path, list));
}
public event NewPathCreatedHandler NewPathCreated;
public void OnNewPathCreated(string path)
{
var handler = NewPathCreated;
if (handler != null) handler(this, new NewPathCreatedHandlerArgs(path));
}
}
public delegate void NewPathCreatedHandler(object sender, NewPathCreatedHandlerArgs args);
public class NewPathCreatedHandlerArgs : EventArgs
{
public string Path { get; set; }
public NewPathCreatedHandlerArgs(string path)
{
Path = path;
}
}
public class LoggerMessageAppendedEventArgs : EventArgs
{
public string Path { get; set; }
public List<string> List { get; set; }
public LoggerMessageAppendedEventArgs(string path, List<string> list)
{
Path = path;
List = list;
}
}
public delegate void AppendedEventHandler(object sender, LoggerMessageAppendedEventArgs e);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过使用
%logger
而不是%C{1}
,您至少会获得本地记录器所需的结果。我认为对于国际奥委会你需要做更多的事情。必须对此进行更多调查...
By using
%logger
instead of%C{1}
you will get the desired result at least for the local logger.I think for IoC you need to do a little more. Have to investigate more on this...