Reputation: 8421
I have a situation where multiple handlers are being set into a single logger. Each Handler replaces sensitive information from being logged.
Please see the below SSCCE
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class TestLogging {
public static void main(String[] args) {
Logger logger=Logger.getLogger(A.class.getName());
logger.addHandler(new ConsoleHandler(){
{
setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("method","replacing method");
}
});
}
});
logger.addHandler(new ConsoleHandler(){
{
setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("Logging","replacing logging");
}
});
}
});
logger.setUseParentHandlers(false);
A a =new A();
a.method();
}
public static class A{
private static final Logger LOGGER=Logger.getLogger(A.class.getName());
public void method(){
LOGGER.info("\nLogging from inside method");
}
}
}
I would like the output to be "replacing logging from inside replacing method", but instead I get an output like this
Logging from inside replacing method
replacing logging from inside method
How do I merge both these handlers into one, if I find another has already been set?
Upvotes: 1
Views: 1636
Reputation: 11443
By design handlers are not supposed to be chained or merged, as their main purpose is to perform the final LogRecord handling, like writing into file. I suggest to change the approach a bit and merge formatters instead of handlers. Please take a look at the following example:
public class TestLogging {
public static void main(String[] args) {
Logger logger = Logger.getLogger(A.class.getName());
FormatHandler handler = new FormatHandler();
logger.addHandler(handler);
handler.addFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("method", "replacing method");
}
});
handler.addFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("Logging", "replacing logging");
}
});
logger.setUseParentHandlers(false);
A a = new A();
a.method();
}
public static class FormatHandler extends ConsoleHandler {
private List<Formatter> formatters = new ArrayList<>();
public FormatHandler() {
setFormatter(new CompositeFormatter());
}
public void addFormatter(Formatter f) {
formatters.add(f);
}
class CompositeFormatter extends Formatter {
@Override
public synchronized String format(LogRecord record) {
String modifiedMessage;
for(Formatter formatter : formatters){
modifiedMessage = formatter.format(record);
record.setMessage(modifiedMessage);
}
return record.getMessage();
}
}
}
public static class A {
private static final Logger LOGGER = Logger.getLogger(A.class.getName());
public void method() {
LOGGER.info("\nLogging from inside method");
}
}
}
It performs the output you want.
Upvotes: 1