0

I am using logback but, rather than having the logger class called directly, I would like to have a custom class/wrapper class which logs the data. (This is required by the usecase). I would like to print the source class names which are calling this wrapper class rather than the wrapper class. I tried logging with this class but its always printing the className of the wrapper class.

class MyAppLogTest {

 public static void main(String args[]) {

    String msg="Some Msg";
    ApplicationLogger.logData( "MyAppLogTest", "main",msg);
    }
}


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ApplicationLogger {

private static Logger logger = null;

    static {
        logger = (Logger) LoggerFactory.getLogger(ApplicationLogger.class);

    }

 public static void logData(final String clazz, final String method,final String msg) { 
        logger.info(msg);
    }
}

Regards

DwB
  • 37,124
  • 11
  • 56
  • 82
oxygenan
  • 1,023
  • 2
  • 12
  • 21
  • You said you tried to logging with `this` class, which class do you mean by `this`? You have to include your code in the question. It makes it more clear what are you asking for. – zaerymoghaddam Dec 14 '17 at 14:40
  • 1
    Can I ask you what's underlying problem are you trying to solve by using this wrapper? Because you're (sort of) re-inventing the wheel. The logger itself provides the same services for you configurable via a simple property file. Maybe by knowing the underlying problem I would be able to give you a better answer – zaerymoghaddam Dec 14 '17 at 15:38
  • Thanks @zaerymoghaddam , though it looks like kind of reinventing , we have some customization within this wrapper class(couldnt include the complete code) , and also we want to avoid the direct interaction of the classes with logging API. – oxygenan Dec 14 '17 at 17:21
  • What's your runtime environment? Is it OK for you to use the CDI API to inject the logger into your classes? – zaerymoghaddam Dec 14 '17 at 17:31
  • Its Java 8 , Spring boot – oxygenan Dec 15 '17 at 06:23

2 Answers2

1

Not a great solution, but you can pull the calling class from the stack and use in the log message.

To do this, you can do something like this:

    final StringBuilder returnValue = new StringBuilder();
    final Throwable throwable = new Throwable();

    try
    {
        final StackTraceElement[] elements = throwable.getStackTrace();
        final String methodName;

        if ((elements != null) &&
            (elements.length > 2))
        {
            methodName = elements[2].getMethodName();

            returnValue.append(methodName);
            returnValue.append("()");
        }
    }
    catch (Exception ignoredException)
    {
        // use some default value.
    }

    return returnValue;

The index of the desired class may not be 2 for you.

DwB
  • 37,124
  • 11
  • 56
  • 82
  • But this may work if its an exception but it should cover non-exception scenarios as well. I need to log "MyAppLogTest " as the class name when am printing it from the ApplicationLogger class . That way I would be able to log the source class name which is invoking my ApplicatonLogger – oxygenan Dec 15 '17 at 06:26
  • Oops, I re read the code , my bad. But wouldnt it be a overhead to create Throwable for each request especially if the volume is high – oxygenan Dec 18 '17 at 09:25
  • the statement "I want classname automatically in logs" is the same as saying "I don't mind some extra overhead". – DwB Dec 18 '17 at 14:27
0

I'm not sure if there is a nice and straightforward way to access the name of the method that called the logger. But I think a solution to access the class name of the caller could be something like this (I didn't have time to run it, but I think it would work):

class MyAppLogTest {
    //    An static instance of your custom logger initialized with
    //    the class that would call it
    private static ApplicationLogger applicationLogger = new ApplicationLogger(MyAppLogTest.class);

    public static void main(String args[]) {
        String msg="Some Msg";
        applicationLogger.logData("main", msg);
    }
}


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ApplicationLogger {

    private static Logger logger;
    private Class callingClass;

    public ApplicationLogger(Class callingClass) {
        this.callingClass = callingClass;
        this.logger = (Logger) LoggerFactory.getLogger(callingClass);
    }
}

public static void logData(final String method, final String msg) { 
    logger.info(method + "-" + msg);
}

}

If it's really important to have also access to the method name, you can add another property of type Method to your ApplicationLogger class and initialize it in constructor. Then you can instantiate the logger per method (which could easily become a performance bottleneck) and passing your current method as that parameter.

Also I think it worth to take a look at Aspect Oriented Programming techniques/libraries. Maybe you could find another solution based on AOP for your original problem.

zaerymoghaddam
  • 3,037
  • 1
  • 27
  • 33