LoggerFactory.getLogger(ClassName.class) vs LoggerFactory.getLogger(this.getClass().getName()) - java

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.

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());

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

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.

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

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

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.

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());
}

Related

How to use the same logger in multiple java projects

I am looking for a solution to the following system setup.
We have a Java NetBeans project that handle the Oracle database with all the entities and the required functionality for a database layer (we cannot replace it with hibernate). This project is used by other Java NetBeans projects in order to read and write to the database.
I would like to be able to set up the Logger (we use the standard java.util.logging.Logger) in the DB project to depend from the one of the application using it. This is required so that all my logging is in a single file and it makes sense to read it; the chain of events is impossible to understand in a log split in multiple files.
I have a simple solution, that I do not like, which is to inject the logger in every class of my db project. This makes all my constructors more complex and I will need to modify a lot of code if I was to use it for every entity (it is useful to log what the db layer is actually doing). I would like a solution where I pass a simple parameter to the whole db project so that all my usual static final logger could write in the right place.
Here is an example just to clarify what I would like to get
In the Db Project:
public class Table{
private final static Logger logger = Logger.XXXXXXX; <--the method I need to accomplish my goal
}
In the application Project
public class TableInteractor{
private Table table;
private static final Logger logger = Logger.getLogger("MyApplication");
}
The solution I mentioned would need something like this
public class Table{
private final static Logger logger;
public Table(Logger logger){
this.logger = logger;
}
}
and
public class TableInteractor{
private Table table;
private static final Logger logger = Logger.getLogger("MyApplication");
...
table = new Table(logger);
}
Is there any way to pass "MyApplication" to the Db Project so that the Logger in there are instantiated in the same way as those in the application?
If you need more information on my setup in order to give me an answer I can add more information.
EDIT:
I just noticed that a logger has a method called setParent(Logger l)
If I create a logger in the DB project, can I pass the application logger into the DB layer and set it as the parent of the DB logger?
As an alternative I was thinking of passing the file handler of the application logger into the db logger and use it so that the same logging file is used by both projects.
Any suggestion on which one is the best solution?
Common pattern is to use one logger per class using class name when calling their factory method. That creates a hierarchy of loggers and you can customize what logger logs at what level and what handler is used to process log records. Of course it is possible to send output form more loggers into one file. Most of that is of course written in Java logging overview - http://docs.oracle.com/javase/6/docs/technotes/guides/logging/overview.html

log class and method name in Log4j logger

I need to get class and method names to Log4j logger. What is the best way of doing that? Also I would like to create one instance of logger for whole application - it is quite boring to declare logger in each class. What is the way to solve these problems.
You can use %C and %M placeholders in your PatternLayout. Please be advised, their use is not recommended for performance reasons.
There are several ideas on how to avoid declaring loggers for each class. For example, if creating a common base class is a viable option, you can declare a protected final logger like this:
abstract class Base {
protected final Logger logger = Logger.getLogger(getClass());
}
class Concrete extends Base {
public void testLogger() {
logger.info("It works!");
}
}
Or, you may try injecting loggers with a dependency injection framework such as Weld.
Actually, creating one Logger for whole application, is not a good idea at all. It's easy to mess up loggers, levels of logging, configuration, etc.
But, if you still want it, you could create a logger instance in main method, and pass it for each of the class (e.g. using setLogger() in every class you use or passing as argument to class constructor). But again, is 100% bad idea to do this.
make your Logger Instance static
Every class has its own Logger => Logger.getLogger(xyz.class)
Use 2. than you can configure log4j

How to inject logger using Google Guice

Usually I define logger like this:
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
But when using #Inject we must use non-static and non-final field, like:
#Inject
private Logger logger;
i.e. logger will be created in each instance of this class, also logger is mutable. May be exist some way to make logger static? Also how I can bind logger to certain class (I use send the class object when creating logger object from factory LoggerFactory.getLogger(MyClass.class);, how to create logger in same way using injecting ? )?
Please check the Custom Injections on Guice wiki, there is a complete Log4J example.
EDIT: You can use either a static field or a final field for your logger, but not a static final one. This is a Java limitation.
Also be wary that:
Injecting final fields is not recommended because the injected value may not be visible to other threads.
Haven't tested that but the code in the article should work fine for static fields, although you could improve it by getting rid of MembersInjector and doing all of it in the TypeListener (since a static field needs to be set only once).
Using requestStaticInjection() will force you to list all your classes in a module file - not a good idea, as you will soon forget to add one.
OTOH if you just want to support JUL you might be better of using the built-in support (as mentioned by Jeff, I assumed you didn't want a general answer, since you didn't mention JUL specifically in your question).
When designing your application for dependency injection, typically the best practice is to avoid static fields and methods as much as possible. This is so that your dependencies are clearer, and so it's easier to replace your real dependencies with other instances during tests and as your application evolves. The ideal behavior, therefore, is to avoid static methods and fields (including loggers) as much as possible.
Guice, however, does allow for marking fields static, and requesting injection of static fields when the Injector is created. The fields will need to remain mutable--final doesn't mean "final except for Guice".
public class YourClass {
#Inject static Logger logger;
/* ... */
}
public class YourModule extends AbstractModule {
#Override public void configure() {
/* YourClass.logger will work once you create your Injector. */
requestStaticInjection(YourClass.class);
}
}
Guice automatically provides java.util.logger.Logger instances for you with the class name embedded into it, but that's only because of a special case coded into Guice. If you want a special logger, as in this SO question, you'll need to investigate the Custom Injections to which Jakub linked--but if the whole goal is to centralize logger creation so you can control it in one place, you can just refactor that into a static factory outside of Guice too.
#LogToFile
public class YourClass {
private static final Logger logger = YourLoggerFactory.create(YourClass.class);
/* ... */
}
public class YourLoggerFactory {
private YourLoggerFactory { /* do not instantiate */ }
public Logger create(Class<?> clazz) {
if (clazz.getAnnotation(LogToFile.class) != null) {
return someImplementation(new File(...));
} else {
return someOtherImplementation();
}
}
}

Logger related question in java

From java.util.logging.Logger:
Logger names can be arbitrary strings, but they should normally be based on the package name or class name of the logged component, such as java.net or javax.swing
Could anyone explain this sentence to me ?
Logger names can be arbitrary strings, but they should normally be based on the package name or class name of the logged component, such as java.net or javax.swing"
"Logger names can be arbitrary strings ...":
public class Foo {
private static final Logger logger = Logger.getLogger("specify logger name here - you can use any logger name you want, even supercalifragilisticexpialidocious");
}
Any code that wants the same logger instance just has to specify the same logger name (good luck spelling "supercalifragilisticexpialidocious" the same way twice).
However, you might want to share loggers more easily, get a handle to a specific class' logger for configuration, or have a hierachical relationship between loggers (e.g. organize loggers to into parents and children). Classes and packages are already organized hierarchically, so they recommend that logger names:
"... should normally be based on the package name or class name of the logged component ..."
package com.example.stackoverflow;
public class Foo {
private static final Logger logger = Logger.getLogger("com.example.stackoverflow.Foo");
}
Now I can easily get a handle to any logger for any class from anywhere (I just need to know its fully qualified class name). Also, now the the Logger framework can see which loggers are related to which, e.g. that the logger for "com.example.stackoverflow" is the parent of the logger for "com.example.stackoverflow.Foo".
But what if the package name changes or your class name changes? This code below does exactly the same thing as the code above, but in a less redundant and more maintainable manner:
package com.example.stackoverflow;
public class Foo {
private static final Logger logger = Logger.getLogger(Foo.class.getName());
}
Now if the package changes, the logger name is handled automatically. If the class is renamed in an IDE, the IDE will likely notice the Foo.class literal in the getLogger call above and update the Foo.class literal accordingly.
It is a way to create a hierarchical set of loggers that allows you to easily identify where each log entry came from. This is a typical scenario
public class MyClass
{
private static Logger sLog = Logger.getLogger(MyClass.class.getName());
}
I believe it relates the name you pass to the constructor when you initialise the logger. It is suggesting a structure name (string) being passed that relates to the actual class you are logging from. Generally you can get this from the class itself
For example
import java.util.logging.Logger;
...
private final static Logger LOGGER = Logger.getLogger(MyClass.class.getName());
Here, MyClass.class.getName() is returning the full class name to be used as the logger name.
A logger usually writes the "logger name" you give it, to the log file. In order to avoid having confusing logger names in one log file, each component should use a unique name. A unique name is the class name of the class doing the logging. This allows you to easily use tools later to extract the log messages for a single class, if desired.
We may think the name as "from which class or package the log is generated".

Best Practice of Using org.apache.commons.logging.LogFactory.getLog

May I know what is the best practice of using org.apache.commons.logging.LogFactory.getLog?
For me, I use it the following way :
public class A
{
private static final Log log = LogFactory.getLog(A.class);
}
public class B
{
private static final Log log = LogFactory.getLog(B.class);
}
So, if I have 100 of classes, 100 of static log object will be created?
Or is it best to do it this way?
public class A
{
private static final Log log = LogFactory.getLog(Main.class);
}
public class B
{
private static final Log log = LogFactory.getLog(Main.class);
}
All the 100 classes are referring to a same single same log?
Thank you.
Please remember the 'static problem', which most of java developer ignore and which affect log4j, java.util.Logger, and SLF4J as well. You can read about it in the Apache Commons Wiki. As reported, if you're developing a library, planning to release it in a container (such as a j2ee container), shared among many application, is better use something like
private transient final Log logger = LogFactory.getLog( this.getClass() );
The first option - have a logger per class (or functionality). As most logging systems - log4j, logback, java util logging, etc. have the notion of logger hierarchy, you can match that to your package hierarchy and have finer control of which functionality you want to be logged at which level. For example:
com.example=WARN # global setting
com.example.web=INFO # increase logging for the web controllers
com.example.dao=DEBUG # trying to track bugs in the database layer
In the vast majority of cases, your way is the way to go.
The main advantage is that there is a logger (or category, or whatever) for each class that can be configured individually, like
log4j.logger.org.springframework.transaction=DEBUG
(assuming log4j) which will set the log level just for that class or package. If you use only one logger, you cannot do that.

Categories