Tips for creating a Logger instance, which are also described in the SLF4J FAQ. Here's a story and a solution to Logger's declaration.
A common bug with Logger is the wrong Logger name. This tends to happen if you copy the Logger declaration from another source.
Example of specifying the wrong Logger name
public class MyClass {
private static final Logger LOGGER = LoggerFactory.getLogger(User.class); //bug!Keep copying from the code of the User class
//...
}
By using MethodHandle [^ mh] introduced from Java7, you can get the calling Class object statically. (Use the static method [^ mhs] of the MethodHandles class (return method [^ mhs-lookup]) ← Note that it is not the MethodHandle class [^ mh])
Get Class object
Class<?> clazz = MethodHandles.lookup().lookupClass();
An idiom for generating a Logger using this is posted in the SLF4J FAQ [^ slf4j]. In this case, you can copy and use it as it is (without rewriting the Logger name of the argument).
Logger generation idiom
import java.lang.invoke.MethodHandles;
public class MyClass {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
//...
}
If it is your own Logger class, you can prevent the wrong Logger name from being specified by limiting the argument type of the factory method as follows. I wrote about my own Logger class earlier. → Use LocationAwareLogger for your own Logger
Factory method argument MethodHandles.Look up only
import java.lang.invoke.MethodHandles;
public class MyLocationAwareLogger {
// (Omitting parts unrelated to this topic)
//Constructor private
private MyLocationAwareLogger(org.slf4j.spi.LocationAwareLogger logger) {
this.logger = logger;
}
//Factory method(Only this method is exposed)
public static MyLocationAwareLogger getLogger(MethodHandles.Lookup lookup) {
return getLogger(lookup.lookupClass());
}
//Factory methods other than the above are private
private static MyLocationAwareLogger getLogger(Class<?> clazz) {
org.slf4j.spi.LocationAwareLogger logger = (org.slf4j.spi.LocationAwareLogger) LoggerFactory.getLogger(clazz);
return new MyLocationAwareLogger(logger);
}
// (Omitting parts unrelated to this topic)
}
Logger generation
private static final MyLocationAwareLogger LOGGER = MyLocationAwareLogger.getLogger(java.lang.invoke.MethodHandles.lookup());
//The following will result in a compilation error
// private static final MyLocationAwareLogger LOGGER_NG1 = MyLocationAwareLogger.getLogger(User.class);
// private static final MyLocationAwareLogger LOGGER_NG2 = MyLocationAwareLogger.getLogger("User");
Although it is only a Logger name, if an incorrect value is specified, it will have a tremendous adverse effect on defect investigation. I think there are many people who have been fooled by the Logger name and end up investigating endlessly unrelated parts of the bug. It's an easy tip to introduce, so please try it.
Recommended Posts