I’m trying to learn more about the Spring Framework (without using SpringBoot) and currently i already have a basic RestController
setup with embedded Tomcat server (version 10
).
Everything works fine but i would like to customize the Catalina’s Log
object so i could do stuff like JSON serializing of console logs.
I’m coming from a Nest.JS background and there it is very easy. Just register a new Logger with Nest and that’s it. I was hoping i could do something similar.
Apparently, Catalina uses a kind of wrapper around java.util.logging
with it’s LogFactory
. When creating the singleton for this class, it verifies if there is any service that implements the Log
interface and uses that. If not, then it uses a default implementation (which is what im trying to override)
private LogFactory() {
FileSystems.getDefault();
// Look via a ServiceLoader for a Log implementation that has a
// constructor taking the String name.
ServiceLoader<Log> logLoader = ServiceLoader.load(Log.class);
Constructor<? extends Log> m=null;
for (Log log: logLoader) {
Class<? extends Log> c=log.getClass();
try {
m=c.getConstructor(String.class);
break;
}
catch (NoSuchMethodException | SecurityException e) {
throw new Error(e);
}
}
discoveredLogConstructor=m;
}
I have implemented this Log interface (it is only a test class), but i cannot find out how i would make this ServiceLoader
use it.
class CatalinaLogger implements Log {
private Logger logger;
private String name;
public CatalinaLogger(String name) {
this.name = name;
this.logger = Logger.getLogger(name);
}
@Override
public boolean isDebugEnabled() {
return true;
}
@Override
public boolean isErrorEnabled() {
return true;
}
@Override
public boolean isFatalEnabled() {
return true;
}
@Override
public boolean isInfoEnabled() {
return true;
}
@Override
public boolean isTraceEnabled() {
return true;
}
@Override
public boolean isWarnEnabled() {
return true;
}
@Override
public void trace(Object message) {
logger.log(Level.FINER, String.valueOf(message));
}
@Override
public void trace(Object message, Throwable t) {
logger.log(Level.FINER, String.valueOf(message));
}
@Override
public void debug(Object message) {
logger.log(Level.FINE, String.valueOf(message));
}
@Override
public void debug(Object message, Throwable t) {
logger.log(Level.FINE, String.valueOf(message));
}
@Override
public void info(Object message) {
logger.log(Level.INFO, String.valueOf(message));
}
@Override
public void info(Object message, Throwable t) {
logger.log(Level.INFO, String.valueOf(message));
}
@Override
public void warn(Object message) {
logger.log(Level.WARNING, String.valueOf(message));
}
@Override
public void warn(Object message, Throwable t) {
logger.log(Level.WARNING, String.valueOf(message));
}
@Override
public void error(Object message) {
logger.log(Level.SEVERE, String.valueOf(message));
}
@Override
public void error(Object message, Throwable t) {
logger.log(Level.SEVERE, String.valueOf(message));
}
@Override
public void fatal(Object message) {
logger.log(Level.SEVERE, String.valueOf(message));
}
@Override
public void fatal(Object message, Throwable t) {
logger.log(Level.SEVERE, String.valueOf(message));
}
}
Is my understanding of this problem correct? Either way, how could i solve this problem?