log4j配置 slf4j的优势

Published: 04 Jul 2016 Category: java

log4j日志在java控制台输出 de 配置

1、log4j输出有2中方式:第一种是将日志信息保存在一个文本当中;第二种是输出到控制台中。
2、在控制台输出log4j日志信息,是开发项目中常用的也是比不可少的也是必须会的一个技术点。
3、2种log4j文件加载方式,以下代码可以直接运用在项目当中。理论东西就不多说了直接看代码。几个步骤就完成。
4、准备log4j.propertes 文件,其目录为 src/log4j.propertes:

log4j.appender.encoding = UTF-8
log4j.rootLogger=INFO,CONSOLE,APPLOG,ERROR,ERRORLOG
#log4j.rootLogger=ERROR,ERRORLOG
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c %x - %m%n
log4j.appender.APPLOG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.APPLOG.Append=true
log4j.appender.APPLOG.DatePattern='_'yyyyMMdd'.log'
log4j.appender.APPLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.APPLOG.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c %x - %m%n
log4j.appender.APPLOG.File=/data1/logs/tomcat/sync/AppAccessLog
log4j.appender.ADMINLOG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ADMINLOG.Append=true
log4j.appender.ADMINLOG.DatePattern='_'yyyyMMdd'.log'
log4j.appender.ADMINLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.ADMINLOG.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c %x - %m%n
log4j.appender.ADMINLOG.File=/data1/logs/tomcat/sync/AdminAccessLog
log4j.appender.ERRORLOG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ERRORLOG.Threshold=ERROR
log4j.appender.ERRORLOG.Append=true
log4j.appender.ERRORLOG.DatePattern='_'yyyyMMdd'.log'
log4j.appender.ERRORLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.ERRORLOG.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c %x - %m%n
log4j.appender.ERRORLOG.File=/data1/logs/tomcat/sync/AppErrorLog
log4j.logger.com.ibatis = DEBUG  
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource = DEBUG  
log4j.logger.com.ibatis.common.jdbc.ScriptRunner = DEBUG  
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate = DEBUG  
log4j.logger.java.sql.Connection = DEBUG  
log4j.logger.java.sql.Statement = DEBUG  
log4j.logger.java.sql.PreparedStatement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG 

5、创建一个servlet来启动日志文件,当启动服务器时进行加载并初始化日志文件:

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
/**
 * log4j控制台文件输出,初始化配置文件
 * @author Administrator
 *
 */
public class Log4jInit extends HttpServlet {

	public void destroy() {
		super.destroy(); 
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {}


	public void doPost(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {}

	public void init() throws ServletException {
		String prefix = getServletContext().getRealPath("/");
		String file = getServletConfig().getInitParameter("log4j"); //是web.xml中的参数
		if (file != null) {
			PropertyConfigurator.configure(prefix + file);
		}
		Logger log = Logger.getLogger(Log4jInit.class);
		log.info("Logg4j日志已经初始化。");
	}
}

6、在web.xml中配置servlet并初始化该servelt文件:

<servlet>
<servlet-name>Log4jInit</servlet-name>
<servlet-class>com.java.log.Log4jInit</servlet-class>
<init-param>
<param-name>log4j</param-name>
<param-value>WEB-INF/classes/log4j-contrl.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Log4jInit</servlet-name>
<url-pattern>/log/logfj</url-pattern>
</servlet-mapping>

7、测试log4j日志(这里测试只能通过web形式访问在能输出日志,在main方法中貌似不行但是可以通过下面介绍的方法(序列9)可以):

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class Log4j extends HttpServlet {
   private static  final transient Logger log = Logger.getLogger(Log4j .class);

	public void destroy() {
		super.destroy();
	}


	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {
		doPost(request, response);
	}


	public void doPost(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {
	        
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		log.info("记录日志信息,将在控制台输出");
		     log.error("可以记录错误信息,输出字体为控制");
		out.flush();
		out.close();
	}

	public void init() throws ServletException {

	}
}

8、输出结果:

2013-05-01 14:08:55 INFO  [http-9090-1] com.java.md.KeyMDF  - 记录日志信息,将在控制台输出
2013-05-01 14:08:55 ERROR [http-9090-1] com.java.md.KeyMDF  - 可以记录错误信息,输出字体为控制

9、第二种方式加载log4j-contrl.propertes文件:

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

public class TestLog4j {
	private static  final transient Logger log = Logger.getLogger(TestLog4j .class);
	public static void main(String[] args)throws InvalidKeyException, IllegalBlockSizeException, NoSuchAlgorithmException, UnsupportedEncodingException, BadPaddingException, NoSuchPaddingException {
		PropertyConfigurator.configure("src/log4j.properties");   
	            log.info("记录日志信息,将在控制台输出");
	   log.error("可以记录错误信息,输出字体为控制");
	}
}

为什么要使用SLF4J而不是Log4J?

SLF4J(Simple logging Facade for Java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),它允许你在后台使用任意一个日志类库。

SLF4J对比Log4J,logback和java.util.Logging的优势

在代码中使用SLF4J写日志语句的主要出发点是使得你的程序独立于任意特定的日志类库,依赖于特定类可能需要不同与你已有的配置,并且导致更多维护的麻烦。

但除此之外,还要一个SLF4J API的特性使得我坚持使用SLF4J而抛弃我长期间钟爱的Lof4j的理由,是被称为占位符(place holder),在代码中表示为“{}”的特性。占位符是一个非常类似于在String的format()方法中的%s,因为它会在运行时被某个提供的实际字符串所替换。这不仅降低了你代码中字符串连接次数,而且还节省了新建的String对象。即使你可能没需要那些对象,但这个依旧成立,取决于你的生产环境的日志级别.

例如在DEBUG或者INFO级别的字符串连接。因为String对象是不可修改的并且它们建立在一个String池中,它们消耗堆内存( heap memory)而且大多数时间他们是不被需要的;

例如当你的应用程序在生产环境以ERROR级别运行时候,一个String使用在DEBUG语句就是不被需要的。通过使用SLF4J,你可以在运行时延迟字符串的建立,这意味着只有需要的String对象才被建立。

而如果你已经使用log4j,那么你已经对于在if条件中使用debug语句这种变通方案十分熟悉了,但SLF4J的占位符就比这个好用得多。

这是你在Log4j中使用的方案,但肯定这一点都不有趣并且降低了代码可读性因为增加了不必要的繁琐重复代码(boiler-plate code):

if (logger.isDebugEnabled()) {
    logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}

另一方面,如果你使用SLF4J的话,你可以得到在极简洁的格式的结果,就像以下展示的一样:

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

在SLF4J,我们不需要字符串连接而且不会导致暂时不需要的字符串消耗。取而代之的,我们在一个以占位符和以参数传递实际值的模板格式下写日志信息。你可能会在想万一我有很个参数怎么办?嗯,那么你可以选择使用变量参数版本的日志方法或者用以Object数组传递。这是一个相当的方便和高效方法的打日志方法。记住,在生产最终日志信息的字符串之前,这个方法会检查一个特定的日志级别是不是打开了,这不仅降低了内存消耗而且预先降低了CPU去处理字符串连接命令的时间。这里是使用SLF4J日志方法的代码,来自于slf4j-log4j12-1.6.1.jar中的Log4j的适配器类Log4jLoggerAdapter。

public void debug(String format, Object arg1, Object arg2) {
    if (logger.isDebugEnabled()) {
        FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
        logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
    }
}

同时,我们也很值得知道打日志是对应用程序的性能有着很大影响的,在生产环节上只进行必要的日志记录是我们所建议的。

当遇到诡异的日志问题

如:明明配置好了log4j.properties, 结果在控制台没有日志输出,或者只有部分输出,请问明明该怎么做?

  • 先检查一遍配置
  • 检查jdk版本,尝试使用高版本的jdk进行编译

其他参考

Log日志框架的学习五.正确使用日志的10个技巧