记录类名和使用log4net的一个.NET项目方法名 [英] Logging ClassName and MethodName using log4net for a .NET project

查看:1108
本文介绍了记录类名和使用log4net的一个.NET项目方法名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找一种方式来记录类名和方法名作为我的日志基础设施的一部分。很显然,我想,使其易于使用和快速的在运行时。我已经做了很多的阅读日志类名和方​​法名,但我已经在2个主题运行。

I have been looking for a way to log class names and method names as part of my logging infrastructure. Obviously I'd like to make it simple to use and fast at runtime. I've done a lot of reading about logging class names and method names, but I've run across 2 themes.


  1. 这log4net的用途内部抛出异常,产生一个堆栈帧,如果您使用的一般为所有日志记录,获取昂贵的。

  2. 混乱。有很多文献在那里。我已经尝试了一堆它并没有得到有用的东西。

如果你的幽默我要第二个,我想重置。

If you humor me for a second, I'd like to reset.

我创造了这样一类在我的项目

I created a class like this in my project

public static class Log {
    private static Dictionary<Type, ILog> _loggers = new Dictionary<Type, ILog>();
    private static bool _logInitialized = false;
    private static object _lock = new object();

    public static string SerializeException(Exception e) {
        return SerializeException(e, string.Empty);
    }

    private static string SerializeException(Exception e, string exceptionMessage) {
        if (e == null) return string.Empty;

        exceptionMessage = string.Format(
            "{0}{1}{2}\n{3}",
            exceptionMessage,
            (exceptionMessage == string.Empty) ? string.Empty : "\n\n",
            e.Message,
            e.StackTrace);

        if (e.InnerException != null)
            exceptionMessage = SerializeException(e.InnerException, exceptionMessage);

        return exceptionMessage;
    }

    private static ILog getLogger(Type source) {
        lock (_lock) {
            if (_loggers.ContainsKey(source)) {
                return _loggers[source];
            }

            ILog logger = log4net.LogManager.GetLogger(source);
            _loggers.Add(source, logger);
            return logger;
        }
    }

    public static void Debug(object source, object message) {
        Debug(source.GetType(), message);
    }

    public static void Debug(Type source, object message) {
        getLogger(source).Debug(message);
    }

    public static void Info(object source, object message) {
        Info(source.GetType(), message);
    }

    public static void Info(Type source, object message) {
        getLogger(source).Info(message);
    }



...

...

    private static void initialize() {
        XmlConfigurator.Configure(); 
    }

    public static void EnsureInitialized() {
        if (!_logInitialized) {
            initialize();
            _logInitialized = true;
        }
    }
}



(如果此代码看起来很熟悉这是因为它是从实例借来的)

(If this code looks familiar it's because it is borrowed from the examples!)

在任何情况下,在整个项目中,我用这样的行记录:

In any case, throughout my project I use lines like this to log:

        Log.Info(typeof(Program).Name, "System Start");



那么,这类作品。最重要的是,我得到的类名,但没有方法名。少,重要的是,我在我的污染代码这个typeof运算垃圾。如果我复制和粘贴的文件之间的代码片段等日志框架会说谎!

Well, this kind of works. Most importantly, I get the class name but no method name. Less, importantly, I am polluting my code with this "typeof" junk. If I copy and paste a snippet of code between files, etc. the logging framework will be lying!

我试着用的PatternLayout玩(%C {1}。{中号}),但没有工作(它所作的只是写Log.Info的日志 - 因为一切都通过Log.X静态方法路由)!此外,这应该是缓慢的。

I tried playing with the PatternLayout (%C{1}.{M}) but that didn't work (all it did was write "Log.Info" to the log--because everything is routing through the Log.X static methods!). Besides, that's supposed to be slow.

那么,什么是最好的方式,因为我的设置,我的愿望是简单而快速的?

So, what is the best way, given my setup and my desire to be simple and fast?

欣赏预先任何帮助。

推荐答案

log4net的(和NLOG)都暴露测井方法,使得它可以包装自己伐木者,仍然可以得到正确的调用站点的信息。从本质上讲,log4net的(或NLOG)记录器需要被告知,形成日志代码和应用程​​序代码之间的边界的类型。我认为他们把这称为记录式或类似的东西。当库获取通话网站的信息,他们导航调用堆栈,直到MethodBase.DeclaringType等于(或者AssignableFrom)中的记录类型。 。下栈帧将在应用程序中调用代码

log4net (and NLog) both expose a logging method that makes it possible to "wrap" their loggers and still get correct the call site information. Essentially, the log4net (or NLog) logger needs to be told the Type that forms the "boundary" between logging code and application code. I think they call this the "logger type" or something similar. When the libraries get the call site information, they navigate up the call stack until the MethodBase.DeclaringType is equal (or maybe AssignableFrom) the "logger type". The next stack frame will be the application calling code.

下面是如何通过NLOG从包装内登录(log4net的将是类似的例子 - 请在log4net的文档对于ILogger(不ILog的)接口:

Here is an example of how to log via NLog from within a wrapper (log4net would be similar - look in log4net docs for ILogger (not ILog) interface:

  LogEventInfo logEvent = new LogEventInfo(level, _logger.Name, null, "{0}", new object[] { message }, exception);

  _logger.Log(declaringType, logEvent);

在哪里declaringType是设置这样的一个成员变量:

Where declaringType is a member variable that was set something like this:

  private readonly static Type declaringType = typeof(AbstractLogger);

和AbstractLogger是你的记录器的包装类型在你情况下,它可能会是这样的:

And "AbstractLogger" is the type of your logger wrapper. In your case, it would probably look like this:

  private readonly static Type declaringType = typeof(Log);

如果NLOG需要得到调用的位置信息(因为在布局调用现场操作人员),它将导航堆栈,直到对于当前帧中的MethodBase.DeclaringType等于(或AssignableFrom)declaringType。在堆栈中的下一个帧将是实际的调用点。

If NLog needs to get the call site info (because of call site operators in the layout), it will navigate up the stack until the MethodBase.DeclaringType for the current frame is equal (or AssignableFrom) declaringType. The next frame in the stack will be the actual call site.

下面是一些代码,会与一个包装的log4net记录器记录工作。它使用的log4net ILogger接口并传递包装记录器的类型保存调用位置的信息。您不必填写事件类/结构此方法:

Here is some code that will work for logging with a "wrapped" log4net logger. It uses the log4net ILogger interface and passes the type of the "wrapping" logger to preserve the call site information. You don't have to fill in an event class/structure with this method:

  _logger.Log(declaringType, level, message, exception);

再次declaringType是你的包装类型。 _logger是log4net的记录器,级别是log4net.LogLevel值,消息是消息,例外是例外(如果有的话,否则返回null)。

Again, "declaringType" is the type of your wrapper. _logger is the log4net logger, Level is the log4net.LogLevel value, message is the message, exception is the exception (if any, null otherwise).

至于污染用typeof(不管)你的电话的网站,我觉得你被卡住,如果你想使用一个单一的静态日志对象。或者,在日志对象的测井方法里面,你可以得到喜欢接受的答案调用的方法在这个岗位

As far as polluting your call sites with Typeof(whatever), I think you are stuck with that if you want to use a single static "Log" object. Alternatively, inside of the "Log" object's logging methods, you could get the calling method like the accepted answer in this post

我怎么能找到调用当前方法的方法?

这链接显示如何获得前一个调用者。如果你需要得到调用记录功能的方法,但你的工作正在做几个层次更深,你将需要去堆栈帧,而不是仅仅一帧的一些数字。

That link shows how to get the immediately preceding caller. If you needed to get the method that called the logging function, but your work is being done a couple of layers deeper, you will need to go up the stack some number of frames rather than just one frame.

考虑这一切在一起,你会写你的调试方法是这样的(再次,这是NLOG方面,因为这是我在我的前面):

Taking all of this together, you would write your Debug method something like this (again, this is in terms of NLog because that is what I have in front of me):

public static void Debug(object message)
{
  MethodBase mb = GetCallingMethod();
  Type t = mb.DeclaringType;
  LogEventInfo logEvent = new LogEventInfo(LogLevel.Debug, t.Name, null, "{0}", new object [] message, null);
  ILogger logger = getLogger(t) As ILogger;
  logger.Log(declaringType, logEvent)
}

请注意,你可能不会找到这里StackOverflow的很多人,将建议写这样的日志包装函数(即明确获取调用方法永远记录通话)。我不能说我要么推荐它,但它确实或多或少地回答你问的问题。如果你想用一个静态的日志的对象,那么你将必须显式传递类型在每个日志调用网站(以获得正确的类记录器),或者你将不得不添加日志记录调用的内部代码导航堆栈,并找出这些信息为自己。我不认为任何这些选项是特别有吸引力的。

Note that you probably won't find many people here on StackOverflow that would recommend writing a logging wrapper function like this (that explicitly gets the calling method for ever log call). I can't say that I would recommend it either, but it does more or less answer the question that you asked. If you want to use a static "Log" object, then you will either have to explicitly pass the Type at each logging call site (to get the correct class logger) or you will have to add code inside of the logging call to navigate the stack and figure out that information for yourself. I don't think that either of those options are particularly attractive.

现在,说了这一切,你可以考虑使用两种或log4net的直接NLOG而不是增加这用于获取呼叫站点信息复杂(不一定可靠)码。马修指出,NLOG提供了一种简单的方式来获得当前类的记录器。要获得使用log4net的当前类的记录,你会在每一个类做到这一点:

Now, having said all of that, you might consider using either log4net or NLog directly rather than adding this complicated (and not necessarily reliable) code for getting the call site information. As Matthew points out, NLog provides an easy way to get the logger for the current class. To get the logger for the current class using log4net, you would do this in every class:

private static readonly log4net.ILog log = log4net.LogManager.GetLogger( 
        System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 



VS这种方式与NLOG:

vs this way with NLog:

  private static readonly NLog.logger log = NLog.LogManager.GetCurrentClassLogger();

这是一个很常见的用法。

That is a pretty common usage.

如果你不希望依赖于特定的日志记录实现,你可以使用可用的日志抽象,例如 Common.Logging之一(NET) 简单的日志门面(SLF)

If you don't want to be dependent on a particular logging implementation, you could use one of the logging abstractions available such as Common.Logging (NET) or Simple Logging Facade (SLF).

即使您不使用这些抽象之一,下载源Common.Logging,并期待在抽象的log4net的。它究竟将如何展现包扎log4net的记录使得调用站点信息将保留(并提供给运营商布局)。

Even if you don't use one of these abstractions, download the source for Common.Logging and look at the abstraction for log4net. It will show exactly how to wrap a log4net logger such that the call site information is preserved (and available to the layout operators).

这篇关于记录类名和使用log4net的一个.NET项目方法名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆