0

I have created a class named "A" and it has its reference class "B". I want to get all the logger message as String including reference class "B" using console appender. Note - B class as third party class which cannot update it.

For eg:

Class A {

    public static void main(String[] args) {
        final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(A.getClassName());
        logger.setLevel(level);
        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel(Level.ALL);
        handler.setFormatter(new SimpleFormatter() {
            @Override public String format(LogRecord record) {
                return "Test---" + record.getMessage();
            }
        });
        logger.addHandler(handler);
        launch();
    }

    public static void launch() {

        B s = new B();
        s.getData();
        logger.info("A log");
    }
}

Class B {
    final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(A.getClassName());

    getData() {
        logger.info("B log");
    }

}

Current Output:

B log
Test---A log

Expected Output:

Test---B log
Test---A log

2 Answers 2

1

Using reflection you can modify its behavior:

import java.lang.reflect.Field;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class A {

    final static java.util.logging.Logger logger = Logger.getLogger(A.class.getName());

    public static void logFormater() {
        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel(Level.ALL);
        handler.setFormatter(new SimpleFormatter() {
            @Override
            public String format(LogRecord record) {
                return "Test---" + record.getMessage();
            }
        });
        logger.addHandler(handler);
    }

    public static void main(String[] args) {
        logFormater();
        launch();
    }

    public static void launch() {
        try {
            B bClass= new B();
            //using reflection get logger field of B class
            Field aField= bClass.getClass().getDeclaredField("logger");
            aField.setAccessible(true);
            //inject new behavior here
            aField.set(bClass, logger);
            
            bClass.getData();
            logger.info("A log");
        } catch (Exception ex) {
            //error msg
        }
    }
}

class B {
    final java.util.logging.Logger logger = Logger.getLogger(B.class.getName());

    void getData() {
        logger.info("B log");
    }
}

Console output:

Test---B logFeb 21, 2021 9:40:54 PM com.kawser.stackoverflow.problem.solution.B getData
INFO: B log
Test---A logFeb 21, 2021 9:40:54 PM com.kawser.stackoverflow.problem.solution.A launch
INFO: A log
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the details. I am not sure what is the field they might used in the B class since its third party class and i'am getting the below error Caused by: java.lang.NoSuchFieldException: logger. Even when i tried to get all the fields using reflection, it returns empty array
If you don't mind, can share your library/ 3rd party class. I will try to figure out this issue.
<dependency> <groupId>org.mule.services</groupId> <artifactId>mule-service-weave</artifactId> <version>2.3.0</version> <classifier>mule-service</classifier> </dependency>. Logger Class is "Feb 21, 2021 11:16:13 AM org.mule.weave.v2.model.service.DefaultLoggingService$ logInfo"
Thanks, let me check.
B.logger was made final exactly because the library author did not want to allow users to change it. Overriding this via reflection breaks encapsulation and the Java guarantees. B author could change B.logger at any point and it will break your program. Make sure you factor in this risk.
|
1

Remove all handlers from the root logger and attach your consolehander to the root logger. By default all log message travel up to the root logger handlers.

Class A {
        private static final java.util.logging.Logger root = java.util.logging.Logger.getLogger("");

        private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(A.class.getName());

    public static void main(String[] args) {
        LogManager.getManager().reset();

        logger.setLevel(level);

        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel(Level.ALL);
        handler.setFormatter(new SimpleFormatter() {
            @Override public String format(LogRecord record) {
                return "Test---" + formatMessage(record);
            }
        });
        root.addHandler(handler);
        launch();
    }

    public static void launch() {

        B s = new B();
        s.getData();
        logger.info("A log");
    }
}

Class B {
    final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(B.class.getName());

    getData() {
        logger.info("B log");
    }

}

1 Comment

Thanks It worked. I am able to get the logger as String

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.