Java:是否可以自动向方法添加日志语句?

时间:2010-01-18 13:01:34

标签: java logging aop

我的应用程序中的大多数方法都是这样编写的:

public void m() {
    long t1 = System.currentTimeMillis();
    log.info("begin - m()");

    /* method body */

    long t2 = System.currentTimeMillis();
    log.info("end - m(), took " + (t2 - t1) + "ms.");
}

我希望我可以简单地注释我的方法,并自动生成日志语句:

@Log("executionTime")
public void m() {
    /* method body */
}

有关如何继续这种方法的任何想法?有没有已知的解决方案?

有人为此建议AOP。问题是,使用AspectJ或Spring AOP,我必须描述所有方法,这些方法与方法本身中的日志调用一样多。

9 个答案:

答案 0 :(得分:14)

AspectJSpring AOP支持以下内容:

execution(* com.company.project..*.*(..))

将涵盖project的所有子包中的所有方法。所以不需要逐个定义所有方法。

答案 1 :(得分:3)

正如您所建议的那样,AOP非常适合满足此要求。不确定你的意思是“必须描述所有方法”。据我所知,有一些方法可以使用通配符来指定方面适用的方法,这可以简化你的“描述”工作......至少在Spring AOP的情况下这是真的。不确定其他方面。

是的,Maurice建议的CGLIB是另一个值得您考虑的好候选人。从来没有用过它。

答案 2 :(得分:2)

CGLIB允许您在运行时修改方法代码

答案 3 :(得分:1)

Perf4j支持使用注释获取方法的计时信息。请参阅开发者指南中的here

答案 4 :(得分:1)

AspectJ具有连接点的概念,它类似于通配符,可以指定与该通配符匹配的任何方法(您可以在类或任何与通配符匹配的类中指定特定方法) 。然后,您可以创建一个方面,其中包含之前的建议之后的建议,它们是在连接点匹配的方法之前和之后运行的方法。您可以通过这种方式生成日志方法。

答案 5 :(得分:1)

虽然这对你的问题还不是一个实际的实际答案(对AOP有一些好的答案),但我相信Java 7中ARM的概念应该是实现类似事情的可行选择。这是一个小规模的。

您可以定义一个实用程序日志记录类和一个生成该类的工厂,如下所示:

public class TimerFactory
{
    private static final Logger log = ...; // Obtain however

    static class Timer implements Disposable<RuntimeException>
    {
        private final long startTime;
        private final String name;

        private Timer(String name)
        {
           this.name = name;
           startTime= System.currentTimeMillis();
           log.info("begin - " + name);
        }

        public void close()
        {
           final long t2 = System.currentTimeMillis();
           log.info("end - " + name + ", took " + (t2 - t1) + "ms.");
        }
    }

    public static Timer getTimer(String name)
    {
       return new Timer(name);
    }
}

现在使用该样板(基本上是对日志记录行为的封装),可以按如下方式调用它:

public void m() {
   try (TimerFactory.getTimer("m()")) {

      /* method body */

   }
}

将在try块的入口处调用第一个log方法,并记录开始时间。退出try块时,资源(在这种情况下为Timer)将自动“关闭”,这将导致计算和记录最终时间。还要注意,因为这是一个try块,无论是否抛出异常,都会发生结束日志记录。您的原始代码应该使用try-finally块来确保实际完成日志记录。

显然,这仍然需要你在每个站点放置一些日志代码,所以即使Java 7发布,也不能真正取代聪明的切入点和AOP。但是,如果您发现自己不时地将日志记录丢弃到一些方法中,那么这种模式是一种很好的方法来抽象出日志记录问题,并允许您以最少的样板重用它。

答案 6 :(得分:0)

您应该使用此要求的一个方面。这个要求是一个交叉问题(在许多类之间“削减”的担忧)。

要捕获您想要匹配的方法,您应该创建一个与一个或多个连接点匹配的切入点。连接点可以在您的代码上执行(例如,方法)。

查看有关跟踪和记录的this simple examples以及this link about wildcards and pointcuts

答案 7 :(得分:0)

@Loggable(由AspectJ提供支持)尝试jcabi-aspects注释:

@Loggable(Loggable.DEBUG)
public String load(URL url) {
  return url.openConnection().getContent();
}

它会记录SLF4J,您可以将其重定向到您自己的日志记录工具,例如log4j。

答案 8 :(得分:-1)

使用唯一搜索字词注释掉日志记录或分析调用:

void myfunc() {

  //log-call-123: try { long log_t1 = System.currentTimeMillis();        
  //log-call-123: log.info("begin - myfunc()"); {

  ...
  normal method code
  ...

  //log-call-123: } } finally { long log_t2 = System.currentTimeMillis();         
  //log-call-123: log.info("end - myfunc(), took " + (log_t2 - log_t1) + "ms."); }

}

搜索和替换时:

搜索:“//log-call-123:

替换为:“/* log-call-123 */

如果要关闭额外的日志记录或分析调用,请执行反向搜索和替换。