J2EE项目中,经常会用到很多第三方的开源组件和软件,这些组件都使用各自的日志组件,比较常用的包括slf4j,common-log, log4j等,很多老的开源软件(包括TOMCAT)使用的是JDK14-LOGGER。这些日志都有自己独立的配置,或只是其中一些可以整合。但是在项目实际部署的时候,需要把所有开源软件和项目程序的各种日志都整合到日志文件中输出,包括tomcat。
本文介绍使用log4j作为日志组件,commons-log, slf4j 作为整合器,同时使用slf4j桥接jdk14-logger输出到log4j日志器。总的来说,达到项目中所有使用这四中日志输出的都统一使用log4j输出。
1.日志需要的包依赖(maven dependency):
<properties> <slf4j.version>1.7.2</slf4j.version> <log4j.version>1.2.17</log4j.version> </properties> <!-- LOGGING begin --> <!-- slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <!-- slf4j-log4j绑定 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <!-- common-logging 实际调用slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <!-- java.util.logging 实际调用slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <!-- LOGGING end -->
2.log4j配置
log4j的配置较简单,使用通常的log4j.properties文件配置就可以,一般放到classes下就OK,你可以在web.xml中加入常量配置配置文件路径。该常量用于filter加载的时候加载日志配置。
<!--tomcat启动,filter载入的Log4j配置文件位置 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/log4j.properties</param-value> </context-param> <!--Spring默认刷新Log4j配置文件的间隔,单位为millisecond, 用于在线动态修改log4j日志 --> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>30000</param-value> </context-param>
一般情况下,使用Spring提供的org.springframework.web.util.Log4jConfigListener负载在tomcat启动的时候加载log4j配置托管spring的日志输出配置。
log4j.properties
log4j.rootCategory=INFO,stdout,logfile # Spring framework log level log4j.logger.org.springframework=INFO # spring modules log level #log4j.logger.org.springmodules=DEBUG # Hibernate log level # log4j.logger.org.hibernate=DEBUG log4j.logger.org.hibernate.SQL=DEBUG # Quartz log level #log4j.logger.org.quartz=INFO # Tomcat,commons... etc log level #log4j.logger.org.apache=INFO # Application log level #sql and execute time # log4jdbc log4j.logger.jdbc.sqltiming=INFO log4j.logger.jdbc.audit=OFF log4j.logger.jdbc.resultset=OFF log4j.logger.jdbc.sqlonly=INFO log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n #\u4e3b\u65e5\u5fd7\u6587\u4ef6 log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender log4j.appender.logfile.File=logs/intergration.log log4j.appender.logfile.DatePattern=.yyyy-MM-dd log4j.appender.logfile.layout=org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - <%m>%n
3. 整合日志
- slf4j的日志会自动根据slf4j-log4j12-xxx.jar输出日志到log4j,无需配置。
- commons-log的日志会自动根据jcl-over-slf4j转到log4j输出,无需配置
- jdk14-logger的日志输出(如:tomcat,restlet等软件)可以根据jul-to-slf4j提供的Handler转移日志输出到slf4j,然后又slf4j转log4j输出。但是需要配置或编程方式设置
配置方式整合:
建立jdk14-logger的配置文件logger.properties.加入Hander配置:
handlers = org.slf4j.bridge.SLF4JBridgeHandler
然后在启动程序或容器的时候加入JVM参数配置JDK日志只是用SLF4JBridgeHandler处理:
-Djava.util.logging.config.file=/path/logger.properties
我不太喜欢这种方式,需要外部修改,麻烦,耦合性强。所以推荐是用编程方式。
编程方式:
扩展Spring提供的org.springframework.web.util.Log4jConfigListener,在TOMCAT启动的时候编程方式设置JDK的日志只是用SLF4JBridgeHandler进行处理。如果你不是WEB程序就更简单了,直接在程序MAIN方式里面设置就OK。
APP程序DEMO:
public class CommonLogAndLog4j { private static final Log log = LogFactory.getLog(CommonLogAndLog4j.class); private static final Logger log4jLogger = Logger.getLogger(CommonLogAndLog4j.class); private static final java.util.logging.Logger jdkLogger = java.util.logging.Logger .getLogger(CommonLogAndLog4j.class.getName()); private static final org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger(CommonLogAndLog4j.class); // -Djava.util.logging.config.file=D:/workshop/log-intergration/src/logging.properties public static void main(String[] args) { installJulToSlf4jBridge(); log.info("CommonsLog日志输出"); log4jLogger.info("Log4j日志输出"); jdkLogger.info("JDK14日志输出"); slf4jLogger.info("slft4j日志输出"); } public static void installJulToSlf4jBridge() { SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); } }
Webapp程序:
LoggerIntergrationListener.class
/** * 扩展Spring的Log4jConfigListener,在容器启动的时候,桥接JDK14的输出到slf4j-logger * * @author zhangpu */ public class LoggerIntergrationListener extends Log4jConfigListener { @Override public void contextInitialized(ServletContextEvent event) { installJulToSlf4jBridge(); event.getServletContext().log("Install Jdk-util-logger to slf4j success."); super.contextInitialized(event); } private void installJulToSlf4jBridge() { SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); } }
web.xml配置
<!--Intergration log4j/slf4j/commons-logger/jdk14-logger to log4j --> <listener> <listener-class>com.feinno.framework.common.web.support.LoggerIntergrationListener</listener-class> </listener>
OK,over!~