Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove debug statements from production code in Java

Is it possible for the compiler to remove statements used for debugging purposes (such as logging) from production code? The debug statements would need to be marked somehow, maybe using annotations.

It's easy to set a property (debug = true) and check it at each debug statement, but this can reduce performance. It would be nice if the compiler would simply make the debug statements vanish.

like image 792
Jonathan Avatar asked Aug 28 '08 11:08

Jonathan


2 Answers

Two recommendations.

First: for real logging, use a modern logging package like log4j or java's own built in logging. Don't worry about performance so much, the logging level check is on the order of nanoseconds. (it's an integer comparison).

And if you have more than a single log statement, guard the whole block:

(log4j, for example:)

if (logger.isDebugEnabled()) {

  // perform expensive operations
  // build string to log

  logger.debug("....");
}

This gives you the added ability control logging at runtime. Having to restart and run a debug build can be very inconvenient.

Second:

You may find assertions are more what you need. An assertion is a statement which evaluates to a boolean result, with an optional message:

 assert (sky.state != FALLING) : "The sky is falling!";

Whenever the assertion results in a false, the assertion fails and an AssertionError is thrown containing your message (this is an unchecked exception, intended to exit the application).

The neat thing is, these are treated special by the JVM and can toggled at runtime down to the class level, using a VM parameter (no recompile needed). If not enabled, there is zero overhead.

like image 193
Mark Renouf Avatar answered Sep 30 '22 18:09

Mark Renouf


public abstract class Config
{
    public static final boolean ENABLELOGGING = true;
}

import static Config.*;

public class MyClass
{
    public myMethod()
    {
        System.out.println("Hello, non-logging world");

        if (ENABLELOGGING)
        {
            log("Hello, logging world.");
        }
    }
}

The compiler will remove the code block with "Hello, logging world." in it if ENABLE_LOGGING is set to true because it's a static final value. If you use an obfuscator such as proguard, then the Config class will vanish too.

An obfuscator would also allow things like this instead:

public class MyClass
{
    public myMethod()
    {
        System.out.println("Hello, non-logging world");

        Log.log("Hello, logging world.");
    }
}

import static Config.*;

public abstract class Log
{
    public static void log(String s)
    {
        if (ENABLELOGGING)
        {
            log(s);
        }
    }
}

The method Log#log would reduce to nothing in the compiler, and be removed by the obfuscator, along with any calls to that method and eventually even the Log class would itself be removed.

like image 44
izb Avatar answered Sep 30 '22 19:09

izb