日志组件

来源:互联网 发布:淘宝摄影棚用什镜头 编辑:程序博客网 时间:2024/05/19 13:21

项目开发时,日志系统是必不可少的东西,不管是开发过程中的调试还是生产环境中的问题跟踪,都离不开日志。在日常的工作中,接触过了Commons logging,JDK logging,Log4J,slf4J还有logback,大概知道怎么用,但对很多细节都不太了解,下面系统地整理一遍。

首先要明确的是,Apache的commons logging和另外一个slf4j是日志控件,是日志接口,本身并没有具体的日志功能,它们需要和日志实现框架一起使用。当然,实现了具体日志功能的日志框架也能单独使用,也就是说,JDK logging,Log4J和logback都能单独使用,但是这样就会造成在一个项目中使用了多个日志实现框架时,需要维护和管理不同的日志系统,非常麻烦。比如,不同的日志框架打印格式和日志级别不同,配置文件也不同。而日志接口框架起到这样一个作用:它可以将不同的日志实现框架整合起来使用,你可以在项目中使用log4j,也可以使用logback,最终都是通过slf4j表现出来,通过一个配置文件去控制日志打印格式和日志级别。

除了这两个日志接口控件之外,其他的都是能实现具体日志功能的日志系统。常用的组合有:Commons logging + JDK logging, Commons logging + Log4J,slf4J + Log4J,slf4J + logback。在最简单的小系统中,可能只需要Commons logging + JDK logging就可以应对了。而在大系统中,具体的日志实现经常用到的是log4j和logback。在早期大部分系统都使用的是Commons logging + Log4J,后来slf4J + Log4J使用较多,再然后则slf4J + logback用得比较多。下面一个个来说。

首先,先说Commons logging 与JDK logging/ Log4J的组合。Commons logging使用时要引入commons-logging包,然后根据引入的具体的日志系统的包来选择具体的日志实现。只要在项目中添加了log4j的包,commons-logging就会自动选择log4j进行日志输出。在进行日志输出时可以通过log4j.properties或log4j.xml进行日志系统配置,控制日志输出位置和输出级别等。如果没有引入log4j的包,commons-logging就会使用JDK自带的logging实现日志功能。下面举几个简单的例子:
1. 不引入log4j的包,默认使用JDK的日志输出功能:

import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.junit.Test;public class LogTest {    Log logger = LogFactory.getLog(LogTest.class);    @Test    public void test1(){        System.out.println("test1");        logger.debug("debug");        logger.debug("info");        logger.debug("error");    }}

当然只能出info级别以上的信息,因为其默认级别就是info。

  1. 引入log4j的包,不提供log4j.properties配置文件。控制台输出:
log4j:WARN No appenders could be found for logger (cn.tonghao.component.LogTest).log4j:WARN Please initialize the log4j system properly.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

添加log4j.properties配置文件:

log4j.rootLogger=DEBUG,console        #输出到控制台log4j.appender.console=org.apache.log4j.ConsoleAppender    #编码格式log4j.appender.console.encoding=UTF-8#设置输出样式log4j.appender.console.layout=org.apache.log4j.PatternLayout   #日志输出信息格式为log4j.appender.console.layout.ConversionPattern=[%-d{yyyy-MM-dd HH:mm:ss}]-[%t-%5p]-[%C-%M(%L)]: %m%n   

后正常输出日志信息。
这里需要说明一点:当log4j.properties放在类路径下时,LoggerFactory会自动去加载该配置文件。如果放在其他地方,则需要在web.xml中配置监听器,如下:

 <context-param>    <param-name>log4jConfigLocation</param-name>    <param-value>classpath:log4j.properties</param-value>  </context-param>  <!--检测日志配置  文件变化-->  <context-param>    <param-name>log4jRefreshInterval</param-name>    <param-value>60000</param-value>  </context-param>  <!--配置监听器-->  <listener>    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  </listener>

注意,检测日志配置文件变化的参数作用是在修改log4j.properties之后配置文件动态生效,生效时间就是配置的检测时间。

然后说说slf4j。Slf4j除了可以整合不同的日志实现组件外,还提供占位符,即可以用{}来代替变量,避免设置打印消息时进行字符串拼接。如logger.info(“xxx,{}”,a)打印出来就是xxx,a。slf4j提供各种抽象接口,日志应该基于slf4j的API进行日志打印,这样无论迁移到那个项目,只需要配一个实现类log4j or logback,都能正常打印日志。所以在选择日志框架的时候,一般选用slf4j,当然,要选择一个具体实现的日志框架。slf4j的实现类不能有多个,不然冲突。实现类用log4j还是logback好呢?其实这两个日志实现框架的作者是同一个人,logback是对log4j的升级改进。在大多数情况下,logback的性能都优于log4j。
要使用slf4j+log4j,需要引入几个包,分别是:slf4j-api,log4j的jar包,和两者绑定jar包slf4j-log4j12。Logback则需要slf4j-api,logback-core和logback-classic。如果要使用slf4j+logback,而项目中又有其他地方直接使用log4j的怎么办呢?可以加入log4j-over-slf4j,把旧的日志log4j适配到slf4j,这时候,再使用logback就可以了。同样,也可以通过引入jcl-over-slf4j来适配commons-logging系统。如:

<dependency>     <groupId>org.slf4j</groupId>     <artifactId>slf4j-api</artifactId>     <version>${org.slf4j-version}</version> </dependency> <dependency>     <groupId>org.slf4j</groupId>     <artifactId>jcl-over-slf4j</artifactId>     <version>${org.slf4j-version}</version> </dependency> <dependency>     <groupId>org.slf4j</groupId>     <artifactId>log4j-over-slf4j</artifactId>     <version>${org.slf4j-version}</version> </dependency> <dependency>     <groupId>org.slf4j</groupId>     <artifactId>jul-to-slf4j</artifactId>     <version>${org.slf4j-version}</version> </dependency> <dependency>     <groupId>org.jboss.logging</groupId>     <artifactId>jboss-logging</artifactId>     <version>3.1.4.GA</version> </dependency> 

使用logback时,如果没有配置logback.xml,则系统默认打印DEBUG级别日志。系统启动的时候会自动扫描classpath路径下的logback.xml和logback-test.xml,如果找到就使用配置文件的配置。下面是一个logback.xml配置模板:

<?xml version="1.0" encoding="UTF-8"?><configuration debug="false"><!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--><property name="LOG_HOME" value="/home" /><!-- 控制台输出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 按照每天生成日志文件 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_JOME}/testFile.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件输出的文件名--><FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern><!--日志文件保留天数--><MaxHistory>30</MaxHistory><TimeBasedFileNamingAndTriggeringPolicy   class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">   <maxFileSize>50MB</maxFileSize></TimeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 日志输出级别 --><root level="DEBUG"><appender-ref ref="STDOUT" /></root></configuration>

上面说过,系统启动时自动扫描类路径,按logback-groovy,logback-test,logback的顺序就行查找,找到了就使用其作为配置文件。但如果想使用自己指定的配置文件怎么办呢?方法是:根目录下保留一个最简单的logback.xml,然后在spring配置文件如spring-log.xml中配置:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">    <bean id="loggingInitialization"          class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">        <property name="targetClass"                  value="cn.tonghao.environment.LogConfigurerSupportMultiEnvironment"/>        <property name="targetMethod" value="registLogConfiguration"/>        <property name="arguments">            <list>                <value>classpath:config/log/${logback.name}.xml</value>            </list>        </property>    </bean></beans>

通过LogConfigurerSupportMultiEnvironment类重新初始化指定的logback配置文件。

public class LogConfigurerSupportMultiEnvironment {    public static void registLogConfiguration(String logConfigLocation) throws FileNotFoundException, JoranException {        String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(logConfigLocation);        if (resolvedLocation.toLowerCase().endsWith(".xml")) {            URL url = ResourceUtils.getURL(resolvedLocation);            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();            loggerContext.reset();            JoranConfigurator joranConfigurator = new JoranConfigurator();            joranConfigurator.setContext(loggerContext);            joranConfigurator.doConfigure(url);        }    }}

比如重新初始化logback-dev.xml(其中tomcat_base_path为tomcat配置文件中的变量):

<?xml version="1.0" encoding="UTF-8" ?><configuration>    <property name = "path_bath" value="/home"/>    <!-- 控制台输出日志 -->    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">        <encoder>            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n</pattern>        </encoder>    </appender>    <!-- 文件输出日志 (文件大小策略进行文件输出,超过指定大小对文件备份) -->    <appender name="FILE"              class="ch.qos.logback.core.rolling.RollingFileAppender">        <File>${path_bath}/${tomcat_app_base}/ly.log</File>        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">            <FileNamePattern>                ${path_bath}/${tomcat_app_base}/ly.%d{yyyy-MM-dd}-%i.log            </FileNamePattern>            <maxHistory>30</maxHistory>            <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">                <maxFileSize>50MB</maxFileSize>            </TimeBasedFileNamingAndTriggeringPolicy>        </rollingPolicy>        <encoder>            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{32} -  %msg%n</Pattern>        </encoder>    </appender>    <!--业务监控日志-->    <appender name="BUS"              class="ch.qos.logback.core.rolling.RollingFileAppender">        <File>${path_bath}/${tomcat_app_base}/lyBus.log</File>        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">            <FileNamePattern>                ${path_bath}/${tomcat_app_base}/lyBus.%d{yyyy-MM-dd}-%i.log            </FileNamePattern>            <maxHistory>30</maxHistory>            <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">                <maxFileSize>50MB</maxFileSize>            </TimeBasedFileNamingAndTriggeringPolicy>        </rollingPolicy>        <encoder>            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{32} -  %msg%n</Pattern>        </encoder>    </appender>    <logger name="lyBusLog" level="INFO" additivity="false">        <appender-ref ref="BUS"/>    </logger>    <root level="INFO">        <appender-ref ref="FILE"/>        <appender-ref ref="STDOUT"/>    </root></configuration>

参考文档:
【1】 http://blog.csdn.net/tianlincao/article/details/6101630
【2】 http://www.cnblogs.com/huayu0815/p/5341712.html

原创粉丝点击