39
votes

This might be a very easy question for some, but personally I find Log4j config to be nightmarishly difficult and that learning to perform brain surgery might be less challenging.

I am trying to lave multiple loggers logging into different files. Here is what I have in my log4j.properties file:

# Root logger option
log4j.rootLogger=INFO, file, admin

# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=/home/nick/logging/file.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

log4j.appender.admin=org.apache.log4j.RollingFileAppender
log4j.appender.admin.File=/home/nick/logging/admin.log
log4j.appender.admin.MaxFileSize=1MB
log4j.appender.admin.MaxBackupIndex=1
log4j.appender.admin.layout=org.apache.log4j.PatternLayout
log4j.appender.admin.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

And here is my (very simple) Java app used to test the config:

public static void main(String[] args) throws Exception {

    Properties resource = new Properties();
    InputStream in = new FileInputStream("/home/nick/logging/log4j.properties");
    resource.load(in);
    PropertyConfigurator.configure(resource);

    Logger admin = Logger.getLogger("admin");
    Logger file = Logger.getLogger("file");

    admin.info("hello admin");
    file.info("hello file");
}

I have 2 problems:

One problem I always get an exception in the line PropertyConfigurator.configure(resource);:

java.io.FileNotFoundException: /home/nick/logging (Is a directory)
 at java.io.FileOutputStream.open(Native Method)
 at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
 at java.io.FileOutputStream.<init>(FileOutputStream.java:136)
 at org.apache.log4j.FileAppender.setFile(FileAppender.java:289)
 at org.apache.log4j.RollingFileAppender.setFile(RollingFileAppender.java:167)
 at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:163)
 at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:256)

The 2nd problem is that both messages are written to both logs. Here is the actual result:

File admin:log:

2014-04-27 11:55:30 INFO  admin - hello admin
2014-04-27 11:55:30 INFO  file - hello file

File file.log:

2014-04-27 11:55:30 INFO  admin - hello admin
2014-04-27 11:55:30 INFO  file - hello file

Here is the required result:

File admin:log:

2014-04-27 11:55:30 INFO  admin - hello admin

File file.log:

2014-04-27 11:55:30 INFO  file - hello file

What is causing the exception, and how can I achieve the required result?

4
Try with relative path new FileInputStream("home/nick/logging/log4j.properties");. remove first / to make it relative path.Braj
one of the simplest solution is explained heresns

4 Answers

111
votes

Log4J makes a distinction between loggers, which are responsible for generating log messages, and appenders, which are responsible for sending those messages somewhere (a file, the console, a database, etc.). Loggers form a hierarchy, the root logger is the parent of the logger named admin, which is the parent of admin.component1, etc., and you can attach appenders to any logger in the hierarchy. By default a logger will send messages to all appenders that are attached directly to it, or to any of its ancestors in the hierarchy (this is why loggers are conventionally named like Java classes, e.g. you can control logging for com.example.Class1 and com.example.subpkg.AnotherClass by configuring the com.example logger).

Loggers and appenders form separate namespaces and this is the source of your confusion - the logger named admin and the appender named admin are two separate entities.

The configuration you have given in the question defines one logger (the root logger) which sends all the messages it generates to two separate appenders, one for each of the two files. Your code then requests two different loggers and generates one log message with each logger. Both these loggers inherit the appender configuration from the root logger, so they both send their messages to both of the configured appenders.

enter image description here

Instead of attaching the two appenders to the root logger, you should attach the file appender to the file logger and the admin appender to the admin logger:

log4j.rootLogger=INFO
log4j.logger.file=INFO, file
log4j.logger.admin=INFO, admin

This way the file logger will send messages only to file.log, the admin logger only to admin.log, and all messages from other loggers will be silently discarded, as there are no appenders attached to the root.

enter image description here


The additivity flag is the exception to this rule - setting a logger's additivity to false essentially disconnects the arrow from a logger up to its parent, so messages generated by that logger (or flowing into it from one of its children) will not go any further up the tree, they will only go to appenders attached directly to the logger in question.

22
votes

To answer my own question, this is what I needed:

log4j.logger.file=DEBUG, fileAppender
log4j.logger.admin=DEBUG, adminAppender

log4j.additivity.file=false
log4j.additivity.admin=false

log4j.appender.fileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.fileAppender.File=/home/nick/logging/file.log
log4j.appender.fileAppender.MaxFileSize=1MB
log4j.appender.fileAppender.MaxBackupIndex=1
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

log4j.appender.adminAppender=org.apache.log4j.RollingFileAppender
log4j.appender.adminAppender.File=/home/nick/logging/admin.log
log4j.appender.adminAppender.MaxFileSize=1MB
log4j.appender.adminAppender.MaxBackupIndex=1
log4j.appender.adminAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.adminAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
5
votes

You don't need to load the properties file. Just place it inside the src folder that will automatically added in class path.

Sample code:

public static void main(String[] args) throws Exception {

   Logger admin = Logger.getLogger("admin");
   Logger file = Logger.getLogger("file");

   admin.info("hello admin");
   file.info("hello file");
}
-1
votes

First: log4j recommands to use xml format file for properties.

Second: its better to load the properties file in the classloader.

Third: there is inheritance in logger, but you can cut it with additivity property see log4j.properties file - multiple loggers in same class