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
Related
I need to periodically append text messages to a text file and I'm wanting to piggyback on log4j to make life easy. So I've created a "mylog.properties" file with a DailyRollingFileAppender -- nothing unusual -- and I've put that file in my src/java/resources directory. So now I'm ready to create a logger from this file and start logging with it, something like this:
class MyClass {
private static final Logger myLog = getLoggerConfiguredFromPropertiesFile("mylog.properties");
public void logSomething(String message) {
myLog.info(message);
}
}
So what would be the logic for getLoggerConfiguredFromPropertiesFile?
Thanks,
Alvaro
Doing:
private static final Logger myLog = Logger.getLogger(MyClass.class)
should get the job done. log4j automatically looks for the closest log4j.properties to the class, and if you only have one in the project, it's that one. Also, call your file log4j.properties, not mylog.properties.
I came up with a workaround where I'm using the regular logger:
private static final Logger myLog = LoggerFactory.getLogger(MyClass.class);
And in the log4j.properties, I configure a custom DailyRollingFileAppender that works just for my class, as explained here.
I have a final static logger object, this is created when the main method is first executed. If the log file is not there it is created and then appended to (using the log4j API, appender). However I want to check that the machine that the application is run on has the directory created that the application is due to save into.
The problem is that this folder check/creation needs to happen before the log is created and the log is created on class instantiation. I s there a standard way to deal with this issue, I want to avoid re-placing all the logging statements so keeping the logger static is preferable?
You can use a static initializer to achieve this:
public class Foo {
static {
//check the directory
//initialize the logger
}
}
This static initalizer will run when the class is loaded. So there you can check if the directory exists before you actually create the 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
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".
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.