Java Logging Techniques Summary(Log4j Example)

1. Three Main Components:

    1) Logger

    2) Appender

    3) Layout

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

    Relationship between these important components

Java Logging Techniques Summary(Log4j Example)

2. Logger may be assigned levels.

    1) TRACE

    2) DEBUG

    3) INFO

    4) WARN

    5) ERROR

    6) FATAL

    If a given logger is not assigned a level, then it inherits one from its closest ancestor with an assigned level.

    Inside it is managed by LoggerManager. Which has a map set the name as key, and the Logger as value.

3. Appender

    1) Log4j allows logging requests to print to multiple destinations.

    2) Main sub class of Appender

        1) ConsoleAppender

        2) FileAppender/RollingFileAppender

        3) JMSAppender

        4) SMTPAppender

        5) JDBCAppender

        6) SocketAppender

    3) A Logger may have multiple Appender.

        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. <Observer Design Pattern>

        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.

4. Layout

    1) More often than not, users wish to customize not only the destination but also the output format.

        This is accomplished by associating a layout with an appender.

    2) The hierarchy of Layout is shown as below.

Java Logging Techniques Summary(Log4j Example)

5. A simple example of using Log4j

    1) pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>edu.xmu.logging</groupId>
	<artifactId>Logging-Log4J</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
		</dependency>
	</dependencies>

</project>

    2) log4j.properties in the class path

# Define the root logger with appender X
log = C:/YangKunLun/logging
log4j.rootLogger = ERROR, FILE

# Define the file appender
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out

# Set the immediate flush to true(default)
log4j.appender.FILE.ImmediateFlush=true

# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug

# Set the append to true, override
log4j.appender.FILE.Append=true

# Set the maxmium file size before rollover
# log4j.appender.FILE.MaxFileSize=5KB

# Set the date pattern
log4j.appender.FILE.DatePattern='.' yyyy-MM-dd-HH-mm

# Set the backup index
# log4j.appender.FILE.MaxBackupIndex=2;

# Define the layout for X appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n 

    3) Log4jExampleTest.java

package edu.xmu.log4j;

import java.util.Date;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.Test;

public class Log4jExampleTest
{
	private static Logger logger = Logger.getLogger("edu.xmu");
	static
	{
		logger.setLevel(Level.INFO);
	}

	@Test
	public void test()
	{
		// Debug < Info < Warn < Error < Fatal
		logger.debug((new Date()) + " [DEBUG] Hello this is an debug message");
		logger.info((new Date()) + " [INFO] Hello this is an info message");
		logger.warn((new Date()) + " [WARN] Hello this is an warn message");
		logger.error((new Date()) + " [ERROR] Hello this is an error message");
		logger.fatal((new Date()) + " [FATAL] Hello this is an fatal message");
	}

}

    4) Log4jExampleTest2.java

package edu.xmu.log4j;

import java.util.Date;

import org.apache.log4j.Appender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import org.junit.Test;

public class Log4jExampleTest2
{
	private static Logger logger = Logger.getLogger("edu.xmu.log4j");

	@Test
	public void test()
	{
		// Log4jExampleTest test = new Log4jExampleTest();
		Layout layout = new SimpleLayout();
		Appender appender = new FileAppender();
		appender.setLayout(layout);
		logger.addAppender(appender);
		
		logger.debug((new Date()) + " [DEBUG] Hello this is an debug message");
		logger.info((new Date()) + " [INFO] Hello this is an info message");
		logger.warn((new Date()) + " [WARN] Hello this is an warn message");
		logger.error((new Date()) + " [ERROR] Hello this is an error message");
		logger.fatal((new Date()) + " [FATAL] Hello this is an fatal message");
	}

}

    Comments:

    1) When we de-comment the comments in Log4jExampleTest2.java, we can find that the level of this logger in this class is no longer that inherits from RootLogger that is ERROR.

        But inherits from "edu.xmu" which is INFO.

6. Configuration file in depth

    1) You may wonder there are so many differents choice for us to choose from. How can we remember all the properties in order to config the configuration file properly?

        Let take a look at a simple configuration file.

# Here we define the root logger for log4j.
# The syntax of defining root logger is : 
# log4j.rootLogger = "RootLevel", "RootAppender1", "RootAppender02"
# Here we using "STDOUT" as micro variables.
log4j.rootLogger = INFO, STDOUT

# Here we specify what the STDOUT is.
# As STDOUT must be an Appender.
# Here we specify that STOUT is the instance of ConsoleAppender
# So every time we encounter log4j.appender.STDOUT, we can use "org.apache.log4j.ConsoleAppender" as replacement.
log4j.appender.STDOUT = org.apache.log4j.ConsoleAppender

# Then we dig into the source code of "org.apache.log4j.ConsoleAppender"
# We can find a method named public void setTarget(String value)
# So we can set as below:
log4j.appender.STDOUT.Target = System.out
# It equals : org.apache.log4j.ConsoleAppender.setTarget("System.out");

    2) Extends

        Let's take a look at the more complex configuration file

       <log4j.logger.edu.xmu is a custom logger that defined in configuration file>

       <When we want to get this custom logger, we just use Logger.getLogger("edu.xmu");>

       Please pay attention that we ignore the prefix of "log4j.logger" when getting the logger.

# Here we define macro named "log" whose value is "c:/..." 
log = C:/YangKunLun/logging

# Here we define the default level for root loggger
# And added two Appenders for this root logger 
log4j.rootLogger = INFO, FILE, STDOUT
log4j.logger.edu.xmu = WARN, FILE, STDOUT
# This has been explained in example above
log4j.appender.STDOUT = org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.Target = System.out

# Here we define the log4j.appender.FILE is an instance of DailyRollingFileAppender
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender

# When we look up the class org.apache.log4j.DailyRollingFileAppender
# We can find a method named setFile(String file)
# This means we want to set the output file as "c:/yangkunlun/logging/log.out"
log4j.appender.FILE.File=${log}/log.out

# We have to define the Layout for each Appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n
log4j.appender.STDOUT.layout = org.apache.log4j.PatternLayout

# Regard configuration file as java code.

7. Code configuration in depth

package edu.xmu.log4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import org.junit.Test;

public class Log4jExampleTest2
{
	private static Logger logger = Logger.getLogger("edu.xmu.log4j");

	@Test
	public void test() throws IOException
	{
		// Log4jExampleTest test = new Log4jExampleTest();
		Layout layout = new SimpleLayout();

		ConsoleAppender consoleAppender = new ConsoleAppender();
		consoleAppender.setName("SYSOUT");
		consoleAppender.setLayout(layout);
		consoleAppender.setWriter(new OutputStreamWriter(System.out));
		consoleAppender.setThreshold(Level.ERROR);

		FileAppender fileAppender = new FileAppender();
		fileAppender.setName("FILE");
		fileAppender.setLayout(layout);
		fileAppender.setAppend(true);
		fileAppender.setImmediateFlush(true);
		fileAppender.setWriter(new FileWriter(new File(
				"C:/YangKunLun/logging/log2.out")));
		fileAppender.setThreshold(Level.DEBUG);

		logger.addAppender(fileAppender);
		logger.addAppender(consoleAppender);
		logger.setLevel(Level.WARN);

		logger.debug((new Date()) + " [DEBUG] Hello this is an debug message");
		logger.info((new Date()) + " [INFO] Hello this is an info message");
		logger.warn((new Date()) + " [WARN] Hello this is an warn message");
		logger.error((new Date()) + " [ERROR] Hello this is an error message");
		logger.fatal((new Date()) + " [FATAL] Hello this is an fatal message");
	}

}

    Comments:

        1) The code above is equivalent to the configuration file in 6-2

        2) Pay attention to that fileAppender.setWriter(new FileWriter(...)) is not fileAppender.setFile("...");

            Pay attention to that console.setWriter(new OutputStreamWriter(...)) is not consoleAppender.setTarget("...");

        3) The relationship of levels of Logger and Appender is like that in JUL. Please refer to previous chapter.

Reference Links:

    1) http://logging.apache.org/log4j/1.2/manual.html

相关推荐