Domanda

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?

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top