简体   繁体   English

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

[英]Java: Is it possible to automatically add log statements to methods?

Most of the methods in my application are written like this: 我的应用程序中的大多数方法都是这样编写的:

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.");
}

I wish I could simply annotate my method and have the log statements be automagically generated instead: 我希望我可以简单地注释我的方法,并自动生成日志语句:

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

Any ideas on how to proceed with this approach ? 关于如何进行这种方法的任何想法? Is there any known solution ? 有没有已知的解决方案?

Someone suggested AOP for this. 有人为此建议了AOP The problem is that with AspectJ or Spring AOP I would have to describe all the methods which ammounts to as much code as the log calls in the method itself. 问题是,使用AspectJ或Spring AOP,我必须描述所有方法,这些方法与方法本身中的日志调用一样多。

AspectJ and Spring AOP support something like: AspectJSpring AOP支持如下:

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

which will cover all methods in all sub-packages of project . 这将涵盖project所有子包中的所有方法。 So no need to define all methods one by one. 因此无需逐个定义所有方法。

As has been suggested to you, AOP fits well to serve this requirement. 正如您所建议的那样,AOP非常适合满足此要求。 Not sure what you meant by "having to describe all methods". 不确定你的意思是“必须描述所有方法”。 From what I know there are ways to use wildcards to specify methods to which aspects apply, which could ease your work of "describing"..this is true at least in the case of Spring AOP..not sure about others. 据我所知,有一些方法可以使用通配符来指定方面适用的方法,这可以简化你的“描述”工作......至少在Spring AOP的情况下这是真的。不确定其他方面。

And yes, CGLIB suggested by Maurice is another good candidate for your consideration. 是的,Maurice建议的CGLIB是另一个值得您考虑的好候选人。 Never used it though. 从来没有用过它。

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

Perf4j supports getting timing information for methods using annotations. Perf4j支持使用注释获取方法的计时信息。 See here in their developer guide. 这里在他们的开发人员指南。

AspectJ has the concept of a join point , which is like a wildcard that can specify any methods that match that wildcard (you can specify particular methods in a class or any class that matches the wildcard). AspectJ具有连接点的概念,它类似于通配符,可以指定与该通配符匹配的任何方法(您可以在类或任何与通配符匹配的类中指定特定方法)。 Then you can create an aspect which contains before advice and after advice , which are methods that run before and after the method matched by the join point. 然后,您可以创建一个包含在通知之前通知 之后方面 ,这些方法是在连接点匹配的方法之前和之后运行的方法。 You can generate your log methods this way. 您可以通过这种方式生成日志方法。

While this is not an actual practical answer to your question just yet (some good answers have been with respect to AOP), I believe the concept of ARM in Java 7 should be a viable option for implementing something like this on a small scale. 虽然这对你的问题还不是一个实际的实际答案(对AOP有一些好的答案),但我相信Java 7中的ARM概念应该是一个可行的选择,可以在小范围内实现这样的事情。

You could define a utility logging class and a factory to produce that class, something like the following: 您可以定义实用程序日志记录类和生成该类的工厂,如下所示:

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);
    }
}

Now with that boilerplate out of the way (essentially an encapsulation of your logging behaviour), it could be called as follows: 现在使用该样板(基本上是对日志记录行为的封装),可以按如下方式调用它:

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

      /* method body */

   }
}

The first log method would be called at the entrance to the try block, and the start time recorded. 将在try块的入口处调用第一个log方法,并记录开始时间。 When the try block was exited, the resource (the Timer in this case) would automatically be "closed", which would cause the final time to be calculated and logged. 当退出try块时,资源(在这种情况下为Timer )将自动“关闭”,这将导致计算和记录最终时间。 Note as well that because this is a try block, the end logging will happen regardless of whether an exception is thrown or not. 还要注意,因为这是一个try块,无论是否抛出异常,都会发生结束日志记录。 Your original code should probably use a try-finally block to ensure that the logging is actually completed. 您的原始代码应该使用try-finally块来确保实际完成日志记录。

Obviously this still requires you to put some logging code at each site, so is not really a replacement for clever pointcuts and AOP, even once Java 7 is released. 显然,这仍然需要你在每个站点放置一些日志代码,所以即使Java 7发布,也不能真正取代聪明的切入点和AOP。 However, if you find yourself dropping the logging in every now and then into perhaps a handful of methods, this pattern is a good way to abstract out the logging concerns and allow you to reuse it with the minimum of boilerplate. 但是,如果您发现自己不时地将日志记录丢弃到可能的少数方法中,则此模式是一种很好的方法来抽象出日志记录问题并允许您以最少的样板文件重用它。

Try @Loggable annotation from jcabi-aspects (powered by AspectJ): 尝试从jcabi-aspects @Loggable注释(由AspectJ提供支持):

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

It logs through SLF4J , which you can redirect to your own logging facility like, say, log4j. 它通过SLF4J进行日志记录,您可以将其重定向到您自己的日志记录工具,例如log4j。

You should use an aspect to this requirement. 您应该使用此要求的一个方面。 This requirement is a crosscuting concern (a concern that "cuts" between many classes). 这个要求是一个交叉问题(在许多类之间“削减”的担忧)。

To capture the methods that you want match you should create a pointcut that matches one or more join points. 要捕获您想要匹配的方法,您应该创建一个与一个或多个连接点匹配的切入点。 A join point is something that can be executed on your code (a method for example). 连接点可以在您的代码上执行(例如,方法)。

Look at this simple examples about tracing and logging and at this link about wildcards and pointcuts . 查看有关跟踪和日志记录的简单示例 ,以及有关通配符和切入点的链接

Comment out the logging or profiling calls with a unique search term: 使用唯一搜索词注释掉日志记录或分析调用:

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."); }

}

When you search and replace: 当您搜索并替换时:

Search for: " //log-call-123: " 搜索:“ //log-call-123:

Replace with: " /* log-call-123 */ " 替换为:“ /* log-call-123 */

Do the reverse search and replace when you want to turn off extra logging or profiling calls. 如果要关闭额外的日志记录或分析调用,请执行反向搜索和替换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 SLF4J/Java 日志记录:是否可以自动添加日志 arguments? - SLF4J/Java logging: Is it possible to add log arguments automatically? Vim和Java:自动添加java import语句 - Vim & Java: add java import statements automatically 如何自动记录Java中方法的进入/退出? - How to automatically log the entry/exit of methods in Java? 是否可以在不破坏 Java 的情况下向 Comparable 添加默认方法? - Would it be possible to add default methods to Comparable without breaking Java? 是否可以向 OpenAPI 添加方法? - Is it possible to add methods to OpenAPI? 在 IntelliJ for Java 中自动将花括号添加到单行 if/for/while 等语句中 - Automatically add curly braces to single line if/for/while etc statements in IntelliJ for java 是否可以在Java中扩展方法? - Is it possible to extend Methods in Java? Java是否会异步地自动调用这些方法? - Will Java asyncronously call these methods automatically? 为什么这些陈述相等? Java中的堆栈方法 - Why are these statements equal? Stack methods in java Java并避免使用相似方法的对象的if语句 - Java and avoid if statements for objects with similar methods
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM