Is there a correct way to pass arguments in slf4j?
Im using slf4j for tracing the information. My code is
private static final Logger log = LoggerFactory.getLogger(ObjectTest.class);
log.trace("Time taken to store " + count
+ " objects of size " + size + " is " + (time) + " msecs");
log.trace("Time taken to store {} objects of size {} is {} msecs",
new Object[] { count, size, time });
log.trace("Time taken to store {} objects of size {} is {} msecs",
count, size, time);
Which would be the preferred mechanism to log traces.
3 is the best.
3 and 2 generate the same (or nearly the same) bytecode, but 3 is easier to type and is shorter, so 3 is better than 2.
If trace is not enabled, 1 must perform string concatenation ("Time taken to store " + count + ....) which is somewhat expensive, while 2 does the string concatenation only if trace is enabled, which is why 3 is better than 1.
3 is best except that it is not supported in SLF4J 1.6.x. For three or more arguments you need the second form. The third form only works with one or two arguments (but not three or more).
As of SLF4J 1.7, the third form is now supported for 3 or more arguments as well. The java compiler silently transforms invocations with 3 or more arguments to the second form, passing an Object[] to the printing method. This is an implementation detail of varargs in Java and allows SLF4J 1.7 to be 100% compatible with SLF4J 1.6.
The 3rd variant is the best one.
In fact 1st case is a string concatenation via StringBuilder.
The 2nd and 3rd cases are the same. They need to box integer values to Integer (or other Object) and then to create an array to pack them.
The simple test on my machine say that the 3rd variant is better in about 8 times in case if no logging executed (56ns vs 459ns).
public class LogTest {
private static final Logger logger = LoggerFactory.getLogger(LogTest.class);
public static void main(String[] args) {
int size = 100_000_000;
long start = System.nanoTime();
for (int i = 0; i < size; i++) {
logger.trace("1 {} 2 {} 3 {}", i, i, i);
}
System.out.println((System.nanoTime() - start) / size);
start = System.nanoTime();
for (int i = 0; i < size; i++) {
logger.trace("1 " + i + " 2 " + i + " 3 " + i);
}
System.out.println((System.nanoTime() - start) / size);
}
}