简体   繁体   中英

Logging of method execution time

In java/groovy application I am using org.slf4j.Logger I like to log method execution time and proposing to use following code

def startTime
LOGGER.isDebugEnabled() {
    startTime = System.currentTimeMillis()
}

doSomething()

LOGGER.debug("Execution took {}ms", (System.currentTimeMillis() - startTime))

I think this code is 'ugly'. Can anyone suggest something more elegant ?

You can probably use this class to calculate elapsed time.

public class StopWatch {

    /* Private Instance Variables */
    /** Stores the start time when an object of the StopWatch class is initialized. */
    private long startTime;

    /**
     * Custom constructor which initializes the {@link #startTime} parameter.
     */
    public StopWatch() {
        startTime = System.currentTimeMillis();
    }

    /**
     * Gets the elapsed time (in seconds) since the time the object of StopWatch was initialized.
     * 
     * @return Elapsed time in seconds.
     */
    public double getElapsedTime() {
        long endTime = System.currentTimeMillis();
        return (double) (endTime - startTime) / (1000);
    }
}

And use it like this:

public class SWTest {

    public static void main(String[] args) {
        StopWatch stopWatch = new StopWatch();

        doSomething();

        LOGGER.debug("Execution took in seconds: ", (stopWatch.getElapsedTime());
    }
}

If you want to make the code look less ugly:

Change

def startTime
LOGGER.isDebugEnabled() {
    startTime = System.currentTimeMillis()
}

to

def startTime = System.currentTimeMillis()

I am not a fan of isDebugEnabled for these one liners. You will not see any performance difference without it.

The current suggestions don't seem to be taking advantage of the fact that the OP is using Groovy .

Here's my take on it:

class CodeTimer {

    /**
     * Time how long it takes to run a piece of code
     *
     * @param closure code to execute and time
     * @return time elapsed in nano seconds
     */
    static final long time(closure) {
        long startTime = System.nanoTime()

        closure()

        return System.nanoTime() - startTime
    }
}

Usage example:

def duration = CodeTimer.time({
    sql.executeUpdate(QUERY)
})

log.debug("Execution took ${duration}ns")

You can also use AOP and Java annotations, to make your code cleaner. I would recommend to use @Loggable annotation and an AspectJ aspect from jcabi-aspects (I'm a developer):

@Loggable(Loggable.DEBUG)
public String load(URL url) {
  // do something
}

All calls to this method will be logged, with all parameters and execution time, through SLF4J.

When measuring a difference between 2 points in time, you should use System.nanoTime(), the millis variant should be used when you are actually interested in measuring the time (from the epoch value) but not when you want to measure a difference in time as precisely as possible.

Also see http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()

Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds.

If you used spring:

StopWatch watch = new StopWatch();
    watch.start();
    for(int i=0; i < 1000000; i++){
        Object obj = new Object();
    }    
    watch.stop();

    System.out.println("Total execution time to create 1000K objects in Java using StopWatch in millis: "                + watch.getTotalTimeMillis());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM