34

I'm trying to improve my optimization skills in Java. In order to achieve that, I've got an old program I made and I'm trying my best to make it better. In this program I'm using SL4J for logging. To get the logger I did:

private static final Logger logger = LoggerFactory.getLogger(this.getClass().getName());

At the time I wrote the code, I thought this was the best option, because I remove a reference to the class name(which may be refactored). But now I'm not so sure anymore...

private static final Logger logger = LoggerFactory.getLogger(ClassName.class);

On the other side, keeps the reference to the class name, but it removes one method call. This may not be a big improvement in performance for one class, but when you have lots of class, this may be something.

So my question is:

Which approach is better? Using the class name or getting it through reflection?

Please, motivate your answer with pro and cons. Thank you.

Aurasphere
  • 3,841
  • 12
  • 44
  • 71

7 Answers7

24

Late entry!

As I am likely to be searching for this in the future.

There is a way to create copy/paste friendly Logger instances (granted this is almost never a good reason to do something!) by using Java 7's MethodHandles class.

private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
Mark McLaren
  • 11,470
  • 2
  • 48
  • 79
18

I'll share my opinion here. I would say that this is the case that you shouldn't be bothered from the performance point of view. Probably in the code there are parts that can be optimized much more than this thing :)

Now, regarding your question. Take a look on LoggerFactory's code

Note that getLogger(Class<?> name) just calls the overloaded method:

Logger logger = getLogger(clazz.getName());

And makes some additional calculations. So the method with String is obviously slightly faster.

In general the pattern is to maintain the Logger reference as a static field in the class, something like this:

public class SomeClass {
   private static final Logger LOG =   LoggerFactory.getLogger(SomeClass.class);
}

In this case you can't really use this.getClass() because this doesn't actually exists (you're running in a static context).

From my experience its better to use the ClassName.getClass() as a parameter unless you really want to use the same logger from different classes. In such a case you better use some logical constant that denotes the logger.

For example, let's say you're trying to use 3 different classes to access the database. So you create logger 'DB', assign a file appender that will write to database.log and you want to reuse the same logger among these 3 different classes.

So you should use the following code:

public class SomeClass {
   private static final Logger LOG =   LoggerFactory.getLogger("DB");
}

Hope this helps

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • 1
    Hate this boilerplate garbage that gets copy-pasted all the time. They should just build this properly into Java, add an argument option to disable it, and let us be done with it forever. – Manius Sep 23 '22 at 16:34
  • @Manius - you can use lombok's annotation `@Slf4j` to eliminate boilerplate. It has nothing to do with the question though – Mark Bramnik Sep 23 '22 at 17:49
  • Yeah I'm aware, but Lombok comes with its own baggage so I tend to use it sparingly. Now that you mention it, that particular Lombok feature should probably be pulled into Java. I do consider this tangentally related to the question though: a main reason to use this.getClass() is to make this stupid boilerplate code less annoying! – Manius Sep 24 '22 at 23:14
9

What I usually do is

private static final Logger logger = LoggerFactory.getLogger(ClassName.class);

However, the idiom

protected final Logger log = LoggerFactory.getLogger(getClass());

is equally common. In this question you can find more info about these conventions.

Community
  • 1
  • 1
francesco foresti
  • 2,004
  • 20
  • 24
  • 2
    The benefits of the first is that it only happens once, the second happens every time the object is created. – OldCurmudgeon Nov 18 '15 at 11:49
  • 4
    The benefit of using getClass() is that if you log in an abstract class, the subclasses that use it will not make references to the name of the abstract class – Adam Hughes Jan 04 '17 at 16:13
8

I prefer

Logger logger = LoggerFactory.getLogger(ClassName.class);

Because

this.getClass() 

Can be override by one of class children and you will see child class name in log. Sometimes it can be confusing because log actually is performed in parent class

D. Rakov
  • 318
  • 3
  • 14
1

When in static context you can't use LoggerFactory.getLogger(getClass()) OR LoggerFactory.getLogger(this.getClass().getName())

And then you have to use LoggerFactory.getLogger(ClassName.class)

Anyways I prefer Lombok's @Log4j2 , less code and does the job : https://projectlombok.org/api/lombok/extern/log4j/Log4j2.html

Rabhi salim
  • 486
  • 5
  • 17
0

If you don't want to write the class name every time you declare a logger, you can use the following utility method:

    public static org.slf4j.Logger getLogger() {
        final Throwable t = new Throwable();
        t.fillInStackTrace();
        return LoggerFactory.getLogger(t.getStackTrace()[1].getClassName());
    }

The method can be used tis way:

private static final Logger LOG = TheClassContainingTheMethod.getLogger();

With such an approach, the logger declaration is always the same for all the classes.

baronKarza
  • 513
  • 6
  • 23
-3

Use this

private final Logger logger = LoggerFactory.getLogger(this.getClass()); 

}
// logic
try
{
// todo
}

catch (NullPointerException e) {
        logger.error("Error:-" + e.getMessage());
          return ResponseUtil.errorResponse(e.getMessage());
        }

        catch (Exception e) {
            logger.error("Error:-" + e.getMessage());
            return ResponseUtil.errorResponse(e.getMessage());
        }
Vishal Chhodwani
  • 2,567
  • 5
  • 27
  • 40
Nikhil
  • 23
  • 1
  • 6