【问题标题】:Using annotations for trace logging使用注释进行跟踪记录
【发布时间】:2011-04-09 12:06:09
【问题描述】:

我一直在与一家公司的代码库合作,该公司的政策是编写大量跟踪日志记录。所以几乎每个方法都有一段这样开头的代码:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void";
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
}

并像这样结束(在finally-clause 中或在方法的末尾:

if(logger.isTraceEnabled()) { 
    logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD)); 
}

实际上还有更多代码,但这是基本思想。 这使代码变得混乱,其他编码人员不断地用他们自己的解释来搞乱它,这些解释不使用特定的 CompanyMessages-class 来格式化要由监视工具读取的消息。所以我正在寻找一种方法来摆脱上面的 all 代码,只提供所有需要跟踪记录的方法,并带有如下注释:@LogBefore('logLevel')@LogAfter('logLevel')

我选择这个解决方案的原因是为了让其他开发人员不必学习任何新东西,只需使用注释而不是代码。我在一个服务器环境中工作,我们在其中部署了数百个 Web 应用程序和数十个开发人员。所以我一直在寻找一种在 Web 应用程序中实现这一点的方法,而无需大量额外的编码或额外的大型库。这意味着我正在寻找一个小型、稳定的 AOP 实现,使用类似于我建议的注释,易于在每个 Web 应用程序中配置。性能也很重要。用 AOP 实现这个的最简单的例子是什么?

编辑:我确实找到了我正在寻找的something very similar,但这有几个问题。必须配置所有需要记录的类,这将比仅使用注释更占用资源。弹簧配置&lt;aop:aspectj-autoproxy/&gt; 会解决这个问题吗?

【问题讨论】:

    标签: java logging annotations trace aspects


    【解决方案1】:

    看起来面向方面的编程 (AOP) 确实可以帮助您解决这个问题。它非常擅长解决这些跨领域问题,例如日志记录和跟踪,并且支持您需要的注释。

    看看AspectJ 或 Spring AOP。

    这将涉及对 AOP 原则和您选择的 API 的一些学习,但绝对值得付出努力。尤其是日志记录和跟踪是您将遇到的第一批 AOP 教程之一,无需深入了解即可轻松完成。

    【讨论】:

      【解决方案2】:

      注解和AOP点都是有效的。使用注释来提醒 AOP 框架有关日志记录。

      我要做的另一件事是修复您的记录器。

      你有:

      String LOG_METHOD = "nameOfMethod(String,List<Long>):void"
      if(logger.isTraceEnabled()) { 
          Object[] params = new Object[] { string, list };
          logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params) ); 
      }
      

      相反,考虑这样的事情:

      logger.trace(this, LOG_METHOD, string, list);
      

      你可以这样实现它:

      public void trace(Object obj, Object args...) {
          if (parentLogger.isTraceEnabled()) {
              logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args);
          }
      }
      

      大多数日志记录实用程序是在我们在 Java 中使用可变参数之前编写的,因此我们仍然可以看到您所编写的内容。

      我们仍然希望保护能够防止在未启用日志时调用日志,但这样做的主要动机是因为过去大多数人都会做你所做的事情,或者更糟:

      logger.trace("My message: " + string + " with list " + list);
      

      无论是否启用跟踪,哪个都有一个昂贵的表达式。

      但通过利用可变参数,您可以两者兼得。只需使用 MessageFormat 之类的东西(您可能已经在这样做了),您就可以轻松获得:

      logger.trace("My message: {0} with list {1}", string, list);
      

      在禁用跟踪的情况下,这是一个传递 3 个指针的廉价方法调用。因此,保护​​它并使代码混乱的动机要少得多。

      大多数现代记录器都不能很好地覆盖,因此您通常必须封装它而不是简单地扩展它。

      它并不能直接解决您的问题,而是动态生成跟踪信息。但这是一个简单的中间立场,可以轻松地逐步清理现有代码库。

      此外,还有 2 个其他选项。

      一个,是使用一个后处理器来运行您的代码并将登录添加到它不存在的地方。这为您节省了手动输入的负担,但它确实使代码混乱(因为它仍然存在于任何地方)。

      二,是在编译时使用注解处理器。这是更复杂的。但它所做的是在编译期间,它会在编译时使用信息贯穿并扩充您的类。好消息是你的代码是干净的(也许是为了注释),而且所有的工作都是在编译时完成的。没有运行时影响,也没有对象工厂的花哨类加载器。构建完成后,您可以将处理器扔掉,在运行时根本不需要它。

      有一个项目利用了这一点,我不知道他的名字。它会在编译时自动将 setter/getter 添加到您的代码中。我听说过它的好消息。

      AOP 框架可能会在编译时为您执行此操作,我对它们还不够熟悉,但无论哪种方式,该技术都值得探索。

      不过,至少要包装您的记录器。它是增量式的、安全的,并且会逐渐清理您的代码并帮助您在注释通常不适合您的情况下进行日志记录。

      【讨论】:

        【解决方案3】:

        我不认为注释是解决方案。注释一个类或实例意味着在运行时给类额外的信息,它本身并没有做任何事情。您需要一些代码来处理带有注释的类,并在运行时根据这些注释在每个方法之前和之后添加代码。

        所以没有办法添加注释并准备好了,你的类开始记录他们的方法。

        解决方案应该是 AOP——这正是 AOP 最初发明的问题。在每个方法上定义类/方法/动作,你的问题就解决了。

        好吧,也许你可以让它在运行时使用注释和修改类,但你最终会得到自制的 AOP :-)

        【讨论】:

        • 谢谢,这让我意识到我对注释工作的看法是有缺陷的。
        • 希望至少有一个 AOP 示例,即使很简单
        猜你喜欢
        • 2013-06-21
        • 2011-04-06
        • 2022-12-21
        • 1970-01-01
        • 1970-01-01
        • 2021-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多