How to use custom log4j.properties file for private logging? - java

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.

Related

How do I programmatically create a folder that is to hold a final static log file, in Java

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.

Two logs for one class

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.

Log4j For Each Class in Project

I have a project containing classes.
I would like to do logging per class instead of wrapping them up altogether in a single log file. I am using Java.
Like for example I have
foo.bar.class1
foo.bar.class2
How can I achieve log file per class?
So that I could have a log file named "class1.log" and "class2.log" containing their own respective log data. What should I do in log4j.properties or on classes?
Any help would be appreciated, thanks.
I'm not sure you can do this in log4j.xml or log4j.properties. So what you can actually do is this (untested, but should work in this fashion):
static {
Logger LOG = LoggerFactory.getLogger(MyClass.class);
try {
((FileAppender)LOG.getAppender()).setFile("class-" + MyClass.name());
} catch (...) {}
}

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

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