I have this code:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", getText());
}
static String getText() {
// Expensive action using IO
return "";
}
}
In my log4j2.json
, the logger is set to ERROR
.
I want that when it is not needed, getText()
is not called at all. For that, I used the message API and I wrote the following instead:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.Message;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info(new TextMessage());
}
static String getText() {
// Expensive action using IO
return "";
}
static class TextMessage implements Message {
@Override public String getFormat() { return null; }
@Override public String getFormattedMessage() {
return String.format("text: %s", getText());
}
@Override public Object[] getParameters() { return null; }
@Override public Throwable getThrowable() { return null; }
}
}
I have two issues with this code.
- I cannot use the
{}
usually used for the logging. - It is extremely verbose.
I checked in the javadoc for any Message
that I could use in Java 8's lambda expressions (meaning, only one abstract method), but there is none.
I've thought about creating a ToStringable interface to be used as the following.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", new ToStringable() { public String toString() { return getText();}});
}
static String getText() {
// Expensive action using IO
return "";
}
}
interface ToStringable { @Override String toString(); }
This gets the job done, but it's barely readable and I cannot use Java 8's lambda on this (see below, note this code fails to compile).
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", () -> getText());
}
static String getText() {
// Expensive action using IO
return "";
}
}
interface ToStringable {@Override String toString(); }
Finally, only the good old if (logger.isXxxxEnabled()) { logger.xxxx(...) }
solved the issue reliably, but what's the point of using a modern, lazy logger?
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
if (logger.isInfoEnabled()) {
logger.info("Text: {}", getText());
}
}
static String getText() {
// Expensive action using IO
return "";
}
}
So did anyone encounter this issue and if yes, how was it solved?
Final words: the 3 first code snippets are short, self-contained, correct examples. This means that they're only here to show the problem. Don't think outside of the problem please (meaning: don't tell me to be pragmatic and just let go).