Log4j

java-logging

Articles
Using log4j inside our code
The configuration file
Sample 1

log4jna

What are the 3 main types of components or concepts in log4j?

  1. loggers: Responsible for capturing logging information.
  2. appenders: Responsible for publishing logging information to various preferred destinations.
  3. layouts: Responsible to format logging information in different styles (text, xml, html, json, etc)

These three types of components work together to enable developers to log messages according to message type and level, and to control at runtime how these messages are formatted and where they are reported.

What is a logger?

The object which performs the logging. This can be a Java built-in class, or it can be your custom code. Loggers are named using dot or package notation. A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger. The logger named "com.foo" is a parent of the logger named "com.foo.Bar".

What is a parent logger and what is a child logger?

Lo4j uses logger hierarchy to support flexible logging requirements. Sometimes, flexibility make things complicated, but flexibility is sometime desired / required in real world scenarios. Loggers are named using dot or package notation. A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger. The logger named "com.foo" is a parent of the logger named "com.foo.Bar". Similarly, "java" is a parent of "java.util" and an ancestor of "java.util.Vector". This naming scheme should be familiar to most developers. Example regarding flexibility: There may be a practical requirement that the "com.foo" logger must log to a location, and the "com.foo.Bar" must log to another location (in addition to the location logged by "com.foo") so that the people who are responsible for monitoring "com.foo.Bar" can focus on data that are relevant to them.

As a side note, log4j child loggers link only to their existing ancestors. In particular, the logger named com.foo.Bar is linked directly to the root logger, thereby circumventing the unused com or com.foo loggers. This significantly increases performance and reduces log4j's memory footprint.

Can each part of the application use a different logger?

Yes. Each part of the application can use a different logger. In fact, if we want to, we can get a logger for each package, and each class using the getLogger method mentioned elsewhere on this page. If we want to obtain the logger for the package, we just have to specify the name of the package. If we want to get the logger for the class, we specify the name of the class. If the logger that we want have not been created, Java will create it. This way, each class and each package can have their own logger. The logger for the class is consider as the child logger of the logger for the package.

What is an appender?

Log4j allows logging requests to print to multiple destinations. In log4j speak, an output destination is called an appender.

What is the role of appender?

An appender represent a destination for the log messages. A logger can have multiple appenders. In other words, the logger can send log messages to multiple destinations.

Can a logger have multiple appenders?

Yes.

How can we add appenders to a logger?

The addAppender method adds an appender to a given logger. Each enabled logging request for a given logger will be forwarded to all the appenders in that logger as well as the appenders higher in the hierarchy. In other words, appenders are inherited additively from the logger hierarchy. For example, if a console appender is added to the root logger, then all enabled logging requests will at least print on the console. If in addition a file appender is added to a logger, say C, then enabled logging requests for C and C's children will print on a file and on the console. It is possible to override this default behavior so that appender accumulation is no longer additive by setting the additivity flag to false.

The rules governing appender additivity are summarized below:

The output of a log statement of logger C will go to all the appenders in C and its ancestors. This is the meaning of the term "appender additivity".

However, if an ancestor of logger C, say P, has the additivity flag set to false, then C's output will be directed to all the appenders in C and its ancestors upto and including P but not the appenders in any of the ancestors of P.

Loggers have their additivity flag set to true by default.

What are the available appenders?

  1. AppenderSkeleton
  2. AsyncAppender
  3. ConsoleAppender
  4. DailyRollingFileAppender
  5. ExternallyRolledFileAppender
  6. FileAppender
  7. JDBCAppender
  8. JMSAppender
  9. LF5Appender
  10. NTEventLogAppender (Windows Event Log)
  11. NullAppender
  12. RollingFileAppender
  13. SMTPAppender
  14. SocketAppender
  15. SocketHubAppender
  16. SyslogAppender
  17. TelnetAppender
  18. WriterAppender

What is a layout?

A layout is responsible for formatting the log message. It is also known as formatter. More often than not, users wish to customize not only the output destination but also the output format. This is accomplished by associating a layout with an appender. The layout is responsible for formatting the logging request according to the user's wishes, whereas an appender takes care of sending the formatted output to its destination.

The PatternLayout, part of the standard log4j distribution, lets the user specify the output format according to conversion patterns similar to the C language printf function.

What are the available log levels?

  1. TRACE,
  2. DEBUG,
  3. INFO,
  4. WARN,
  5. ERROR
  6. FATAL

This is listed in the severity order, with TRACE being at the top and least severe, and FATAL being at the bottom and most severe. When we are debugging a problem, we want to lower the severity to TRACE (increase the verbosity). This is very verbose, which may help or make it harder to see what is going on. Too much logging can really hurt performance, or even take down your infrastructure. Make sure that we can the log level back to a reasonable level, perhaps WARN, when we are done with debugging.

What is special about the "root" logger?

The root logger resides at the top of the logger hierarchy. It is exceptional in two ways:

  1. it always exists
  2. it cannot be retrieved by name

What can we use the root logger for?

The root logger is the only logger that we really need. It is the default logger. However, using the root logger all the time might not be appropriate because it may creates a lot more noise / traffic / load especially in a container environment that host many applications. In such cases, each application should perhaps define its own root logger and child loggers.

What are the purposes of the root logger?

I think that other loggers inherit various things from the root logger. I think that in your code, when you try to obtain a logger but that logger was not defined, log4j returns the root logger or a copy of it.

Can we assign a log level to a logger?

Yes. When we assign a log level to a logger, all log message with a log level less severe than the log level assigned to the logger will be ignore.

What happens when we assign a log level to a logger?

When we assign a log level to a logger, all log message with a log level less severe than the log level assigned to the logger will be ignore.

What happen if a logger is not assigned a default log level?

If a given logger is not assigned a level, then it inherits one from its closest ancestor with an assigned level. This is known as log level inheritance. More formally: The inherited level for a given logger C, is equal to the first non-null level in the logger hierarchy, starting at C and proceeding upwards in the hierarchy towards the root logger.

What is the log level assigned to the root logger by default?

By default, the root logger is assigned to Level.DEBUG.

How can we start the builtin log4j socket server?

C:\Khai\log4jtest>java -cp c:\Khai\log4jtest\log4j-1.2.17.jar org.apache.log4j.net.SimpleSocketServer 4712 log4j-server.properties

The content of the log4j-server.properties:

log4j.rootLogger=DEBUG, file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=server_logfile.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] [%t] [%m]%n

Alternatively, if we wish to have the message displayed on the console, the content of log4j-server.properties can be:

log4j.rootLogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d] [%t] [%m]%n

Notice that the first log message is not displayed, but the subsequent messages seems to be displayed in the console file. Furthermore, in the log4j.properties file on the client side, we must use IP address instead of 'localhost' even though the log4j socket server is run on the same machine.

A sample log4j client:

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class log4jClient {
    //static Logger logger = Logger.getLogger(log4jClient.class.getName());
    static Logger logger = Logger.getRootLogger();
    public static void main(String[] args) {
        logger.info("Yo!  This is log4j in action.");
    }
}

and the log4j.properties file on the client side:

log4j.rootLogger=DEBUG, server
log4j.appender.server=org.apache.log4j.net.SocketAppender
log4j.appender.server.Port=4712
log4j.appender.server.RemoteHost=127.0.0.1
log4j.appender.server.ReconnectionDelay=10000

To compile the above client:

c:\Khai\log4jtest>c:\bea\jdk1.7.0_45\bin\javac.exe log4jClient.java 
    -cp c:\Khai\log4jtest\log4j-1.2.17.jar

To run the above client:

c:\Khai\log4jtest>c:\bea\jdk1.7.0_45\bin\java.exe -cp ".;c:\Khai\log4jtest\log4j-1.2.17.jar" log4jClient

Do we have to recompile code if we need to change logging behavior?

In most cases, we do not need to recompile code if we need to change logging behavior. To obtain these different logging behaviors we did not need to recompile code. We could just as easily have logged to a UNIX Syslog daemon, redirected all com.foo output to an NT Event logger, or forwarded logging events to a remote log4j server, which would log according to local server policy, for example by forwarding the log event to a second log4j server.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License