gpt4 book ai didi

c# - 使用log4net记录.NET项目的ClassName和MethodName

转载 作者:太空狗 更新时间:2023-10-29 17:39:41 25 4
gpt4 key购买 nike

我一直在寻找一种记录类名和方法名的方法,作为我的记录基础结构的一部分。显然,我想使其易于使用且运行时快速。我已经阅读了很多有关记录类名和方法名的文章,但是我遇到了两个主题。

  • 该log4net使用内部抛出异常来生成堆栈框架,如果通常将其用于所有日志记录,则它会变得昂贵。
  • 困惑。那里有很多文献。我已经尝试了很多,但是还没有找到有用的东西。

  • 如果您想逗我一下,我想重设。

    我在项目中创建了一个像这样的类
    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;
    }
    }
    }

    (如果这段代码看起来很熟悉,那是因为它是从示例中借来的!)

    无论如何,在我的整个项目中,我都使用如下代码来记录日志:
            Log.Info(typeof(Program).Name, "System Start");

    好吧,这种作品。最重要的是,我得到了类名,但没有方法名。更重要的是,我正在用这种“typeof”垃圾来污染我的代码。如果我在文件等之间复制并粘贴一小段代码,则日志记录框架将说谎!

    我尝试使用PatternLayout(%C {1}。{M})玩,但是没有用(所有操作都是在日志中写入“Log.Info”,因为所有内容都通过Log.X静态方法进行路由) !)。此外,这应该很慢。

    那么,考虑到我的设置以及对简单快速的渴望,最好的方法是什么?

    提前感谢您的帮助。

    最佳答案

    log4net(和NLog)都公开了一种日志记录方法,可以“包装”他们的记录器,并且仍然可以获取正确的调用站点信息。本质上,需要告知log4net(或NLog)记录器类型,该类型在记录代码和应用程​​序代码之间形成“边界”。我认为他们将其称为“记录器类型”或类似名称。当库获取调用站点信息时,它们将在调用堆栈中导航,直到MethodBase.DeclaringType等于(或可能是AssignableFrom)“记录器类型”。下一个堆栈帧将是应用程序调用代码。

    这是一个如何在包装器中通过NLog进行记录的示例(log4net会类似-在log4net文档中查找ILogger(而非ILog)接口(interface):

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

    _logger.Log(declaringType, logEvent);

    其中declaringType是一个设置如下的成员变量:
      private readonly static Type declaringType = typeof(AbstractLogger);

    而“AbstractLogger”是您的记录器包装器的类型。在您的情况下,它可能看起来像这样:
      private readonly static Type declaringType = typeof(Log);

    如果NLog需要获取调用站点信息(由于布局中有调用站点运算符(operator)),它将在堆栈中向上导航,直到当前框架的MethodBase.DeclaringType等于(或AssignableFrom)declaringType。堆栈中的下一帧将是实际的调用站点。

    这是一些适用于“包装”的log4net记录器的代码。它使用log4net ILogger接口(interface),并传递“包装”记录器的类型以保留调用站点信息。您不必使用此方法填写事件类/结构:
      _logger.Log(declaringType, level, message, exception);

    同样,“declaringType”是包装器的类型。 _logger是log4net记录器,Level是log4net.LogLevel值,message是消息,exception是异常(exception)(如果有的话,否则为null)。

    至于用Typeof(whatever)污染您的调用站点,我想如果您要使用单个静态“Log”对象,您就会陷入困境。另外,在“Log”对象的日志记录方法内部,您可以像本文中接受的答案一样获得调用方法。

    How can I find the method that called the current method?

    该链接显示了如何获取紧接的前一个调用者。如果您需要获得调用日志记录功能的方法,但是您的工作已经完成了两层,那么您将需要向上堆叠一些帧,而不只是一帧。

    综合所有这些,您将编写类似于以下内容的Debug方法(同样,这是使用NLog的方式,因为这就是我的眼前的东西):
    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上可能找不到很多建议编写这样的日志记录包装函数的人(该函数显式获取每次日志调用的调用方法)。我也不能说我会推荐它,但是它或多或少地回答了您提出的问题。如果要使用静态“Log”对象,则要么必须在每个日志记录调用站点显式传递Type(以获取正确的类记录器),要么必须在日志记录调用中添加代码以导航到自己整理并找出这些信息。我认为这些选择都不是特别有吸引力。

    现在,说完所有这些,您可以考虑直接使用log4net或NLog,而不是添加此复杂的(且不一定可靠)代码来获取调用站点信息。正如Matthew指出的那样,NLog提供了一种获取当前类记录器的简便方法。要使用log4net获取当前类(class)的记录器,您可以在每个类(class)中执行以下操作:
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger( 
    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    与NLog的这种方式:
      private static readonly NLog.logger log = NLog.LogManager.GetCurrentClassLogger();

    这是很常见的用法。

    如果不想依赖于特定的日志记录实现,则可以使用可用的日志记录抽象之一,例如 Common.Logging (NET)Simple Logging Facade (SLF)

    即使您不使用这些抽象之一,也请下载Common.Logging的源代码,并查看log4net的抽象。它将确切显示如何包装log4net记录器,以便保留调用站点信息(并可供布局运算符(operator)使用)。

    关于c# - 使用log4net记录.NET项目的ClassName和MethodName,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3770905/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com