Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid creating unused String instances when logging in Java

I define a Util class to log using log4j, and a method is like below:

public static void info(String msg) {
    if (logger.isInfoEnabled())
        logger.info(msg);
}

But if the log level is set to "Error" (and thus logger.isInfoEnabled() is false), and I use the below to log, will the two String instances be created?

LogUtil.info("String instance" + stringParam);

even though these two String instances may be collected by gc, construct a instance will be still costs.

I guess if I check the log level before calling logger.info(msg) may help , but this may the code not clean, that's the reason why I define Util class.

How can I to write a clean code that if I do not set the level to info, it will neither log anything nor create the String instance?

like image 639
JaskeyLam Avatar asked Feb 06 '26 17:02

JaskeyLam


2 Answers

Don't define the Util class and you can avoid some of the string creation overhead.

Quite apart from anything else you're isInfoEnabled check is completely pointless as logger itself will do the check.

Use:

logger.log(Level.INFO, "Message {0} with {1}", new Object[] { param1, param2 });

And you will avoid most of the string creation overhead as it will only toString() param1 and param2 and construct the final message if the INFO level is turned on.

There is the cost of allocating the new Object[] array but that is tiny

like image 81
Tim B Avatar answered Feb 09 '26 09:02

Tim B


I'm afraid your util class is completely useless, as the logger already does the log level check internally. The idea of doing these checks manually outside is to reduce the overhead caused by unnecessary code that prepares the log message (mostly String concatenation) even if then it is not logged due to the current log level:

Suppose you want to log the user input - which is a Date object. Here, date-to-string conversion and string concatenation is done even if the log level is lower than info:

logger.info("user input: " + dateFormatter.format(userInput));

So the solution is to check the log level first:

if (logger.isInfoEnabled()) {
    logger.info("user input: " + dateFormatter.format(userInput));
}

But if you now move the check into a utililty method that gets the full message as parameter, you'll end up having the same problem than above!


Others already explained in their answers how to use the extended log methods to let the logger internally do the formatting:

logger.log(Level.INFO, "Current user input: {0}", userInput);

But also here, if the parameter has to be specially formatted first, it does not solve the overhead problem. Again, you'll have to do an additional log-level check first.


Since Java 8, you could write a utility-method that can be used effeciently and smartly by using lambda expressions:

public static void info(Supplier<String> messageSupplier) {
    if (logger.isInfoEnabled()) logger.info(messageSupplier.get());
}

Usage:

LoggerUtil.info(() -> "user input: " + dateFormatter.format(userInput));

Here, the lambda expression will only be executed if info logging is enabled!

like image 23
isnot2bad Avatar answered Feb 09 '26 08:02

isnot2bad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!