Frage

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?

War es hilfreich?

Lösung

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top