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.
Related
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());
}
I'm working on jdk 1.6 and I have a class that needs to log to 2 different log files using log4j. I have read many other answers, but I can't get mine to work the way I want it. This is my log4j properties.
log4j.debug=false
log4j.rootLogger=ERROR, appLog
log4j.logger.com.my.apps.idm.transactionalemail=DEBUG, appLog, infoLog
log4j.appender.appLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.appLog.File=/opt/apps/logs/${ni.cluster}/TransactionalEmail/1.0/TransactionalEmail.log
log4j.appender.appLog.DatePattern='.'yyyy-MM-dd
log4j.appender.appLog.layout=org.apache.log4j.PatternLayout
log4j.appender.appLog.layout.ConversionPattern=DATE: %d{DATE}%nPRIORITY: %p%nCATEGORY: %c%nTHREAD: %t%nNDC: %x%nMESSAGE:%m%n%n
log4j.appender.infoLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.infoLog.File=/opt/apps/logs/${ni.cluster}/TransactionalEmail/1.0/Info.log
log4j.appender.infoLog.DatePattern='.'yyyy-MM-dd
log4j.appender.infoLog.layout=org.apache.log4j.PatternLayout
log4j.appender.infoLog.layout.ConversionPattern=DATE: %d{DATE}%nPRIORITY: %p%nCATEGORY: %c%nTHREAD: %t%nNDC: %x%nMESSAGE:%m%n%n
And the way I want this to work is like this
public class MyClass{
private static final LOG = Logger.getLogger("appLog");
private static final INFO_LOG = Logger.getLogger("infoLog");
public void myMethod(){
INFO_LOG.debug("This is info");
LOG.debug("This is debug");
}
}
What happens when I run my app is that the Info.log has the same information as TransactionalEmail.log, and also, the line "This is a test" doesn't show up in either of the log files.
What am I doing wrong?
I would recommend against using multiple logger instances for classes. Utilize log4j's configuration to handle logging events as they are generated. You may want to look at the Routing File Appender to decide how log events are handled. From the link
The RoutingAppender evaluates LogEvents and then routes them to a subordinate Appender. The target Appender may be an appender previously configured and may be referenced by its name or the Appender can be dynamically created as needed. The RoutingAppender should be configured after any Appenders it references to allow it to shut down properly.
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
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
I need to pass some value to enable certain code in may app (in this case is to optionally enable writing some stats to a file in certain conditions, but it might be anything generally).
My java app is installed as a service. So every way I have thought of has some drawbacks:
Add another param to main(): cumbersome as customers already have the tool installed, and the command line would need to be changed every time.
Adding java -DmyEnvVar=A_VALUE to my command line: same as above.
Set an environment variable: service should at least be restarted, and even then you must take care of what user is the service running under etc.
Adding the property in the config file: I prefer not to have this visible on the config file so the user does not see it, it is something for debugging etc.
So I thought maybe there is some way (or hack) to use log4j loggers to pass that value to my code. I have thought of one way already, although is very limited:
Add a dummy class to my codebase com.dummy.DevOptions
public class DevOptions {
public static final Logger logger = Logger.getLogger(DevOptions.class);
In my code, use it like this:
if (DevOptions.logger.isInfoEnabled()){
//do my optional stuff
}
//...
if (DevOptions.logger.isDebugEnabled()){
//do other stuff
}
This allows me to use discriminate among various values, and I could increase the number by adding more loggers to DevOptions. But I wonder whether there is a cleaner way, possibly by configuring the loggers only in log4j.xml??
In log4j you dont need Java classes at all to create loggers (This may come as a surprise). All you need is a package qualified string and not a Java class to create logger category. If I were you I would do the following
PS: Code not guaranteed to compile/run
public class SomeAppCode {
public static final Logger specialLogger = Logger.getLogger("com.mypackage.mysubpackage.speciallogger");
public void someMethod() {
if(specialLogger.isDebugEnabled()) {
//do low level stuff
}
}
}
In your log4j.xml add a category for this string mentioned and if you want you could set "additivity" to be true/false (depending on whether you want to propogate this log message to multiple loggerS)
PS: Note specialLogger is public static and such can be used by 100s of classes like it were their own loggers.
ok I think I found what I needed, wasn't that difficult actually...
public class DevOptions{
public static boolean isEnabled(String myvalue){
Logger logger = Logger.getLogger(myvalue);
return logger.isDebugEnabled();
}
}
public class SomeAppCode {
public void someMethod() {
if(DevOptions.isEnabled("value.A")) {
//do low level stuff
}
}
}
And I can add as many values like value.A in log4j.xml:
<logger name="value.A" additivity="true"><level value="debug" /></logger>
This way I can add as many values as I want by only modifying log4j.xml, no need to add more loggers to DevOptions, only one is sufficient.