Java 日志

来源:互联网 发布:数据线路的通讯方式 编辑:程序博客网 时间:2024/05/28 05:18

19.1.1. Spring对log4j的几个增强

注意

个人建议都不要使用。

  • 定时刷新log4j.properties,无须重启服务器更新log4j设置。虽然这是个J2EE Best Practice,但在Spring的JavaDoc里注明了不推荐用于生产环境,因为服务器重启的时候,那条watch thread不会关闭。

  • 将log4j.properties文件放在WEB-INF/log4j.properties。

    这种增强看不出有什么好处,而且如果放WEB-INF,测试的时候就不能输出log4j信息了,除非像Appfuse那样把WEB-INF也设为class path,不过这种设法只适用于Ant脚本的情况。

  • 通过设定{web.root}这样的系统变量,将log文件放到项目的WEB-INF目录中

    log4j.appender.logfile.File=${oa.root}/WEB-INF/logs/oa.log

    这样做的好处是路径比较稳定,但如果是war式的部署,每次重新部署的时候就会把原来的log文件全部删掉,遇上jboss 这种不解压war包的应用服务器就更会出错,所以把log文件放WEB-INF/logs不是一个好的选择。

其实logfile路径的规则是,如果不是绝对路径,就以应用运行的目录作为相对路径的根目录。

可以这样定义,一般就指向tomcat和很多应用服务器的logs目录:

log4j.appender.logfile.File=../logs/oa.log

19.1.2. 默认写入操作员ID

比如在一个ServletFilter里实现如下代码

Customer customer = (Customer) session.getAttribute("customer");
MDC.put("userid", customer.getLoginid());

则log4j会线程安全的把cusomer id写入MDC的userId变量中,而userID变量的使用见下。

19.1.3. 忽略某些类库框架的不必要的信息

控制第三方框架类库的logging level,可以避免满屏都是不重要的info,把真正重要的信息掩盖了。

# Changing the log level to DEBUG when debug
log4j.logger.org.springframework=WARN
# Changing the log level to DEBUG will display SQL Hibernate generated
log4j.logger.org.hibernate=WARN
log4j.logger.org.hibernate.SQL=ERROR

19.1.4. 把重要的业务日志异步批量写入数据库

配置文件示例:

log4j.logger.business=INFO,db
log4j.appender.db=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.db.BufferSize=10
log4j.appender.db.URL=jdbc:hsqldb:res:/hsqldb/bookstore
log4j.appender.db.driver=org.hsqldb.jdbcDriver
log4j.appender.db.user=sa
log4j.appender.db.password=
log4j.appender.db.sql=INSERT INTO SS_LOG4J_LOG (PRIORITY,LOGDATE,CLASS,METHOD,MSG) VALUES('%p','%d{yyyy-MM-dd HH:mm:ss}','%C','%M','%m')
log4j.appender.db.layout=org.apache.log4j.PatternLayout

log4j提供了简单灵活且不影响性能的机制, 将重要业务日志写入数据库,方便日后的查询:

建立一个任意命名的日志记录表,在log4j.properties里设置连接参数,根据刚才建的表名列名,编写插入的语句。

BufferSize=10 这样的参数可以让日志异步批量写入,不会影响系统性能。

业务日志log最好不要用原来的package结构,而是在项目里协调一个独立的名字,如business。

Log buzzLog = LogFactory.getLog("business");

自己有几点考虑,既然实时修改日志级别是最佳实践,为什么不干脆把数据库配置作为系统配置的一部分保存进数据库呢?这样不但可以实时修改,还可以保证系统重启后依然获得上次修改后的配置。

19.2. slf4j + logback

slf4j由log4j作者Ceki开发,逐步取代apahce commons logging。

logback由log4j作者Ceki开发,逐步取代log4j。

19.2.1. 优势

十个转移到logback的理由

slf4j支持参数化的logger.error("帐号ID:{}不存在", userId);告别了if(logger.isDebugEnable()) 时代。

另外logback的整体性能比log4j也较佳,hibernate等项目已经采用了slf4j:

"某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在LOGBack中需要3纳秒,而在Log4J中则需要30纳秒。 LOGBack创建记录器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它获取已存在的记录器只需94纳秒,而 Log4J需要2234纳秒,时间减少到了1/23。"

19.2.2. slf4J与旧日志框架的关系

  1. slf4j等于commons-logging,是各种日志实现的通用入口,会根据classpath中存在下面哪一个Jar来决定具体的日志实现库。

    • logback-classic(默认的logback实现)

    • slf4j-jcl.jar(apache commons logging)

    • slf4j-logj12.jar(log4j 1.2.4)

    • slf4j-jdk14(java.util.logging)

  2. 将所有使用旧式日志API的第三方类库或旧代码的日志调用转到slfj。

    • jcl-over-slf4j.jar/jcl104-over-slf4j

      apache commons logging 1.1.1/1.0.4,直接替换即可。

    • log4j-over-slf4j.jar

      log4j,直接替换即可。

    • jul-to-slf4j

      jdk logging,需要在程序开始时调用SLF4JBridgeHandler.install()来注册listener

      参考JulOverSlf4jProcessor,可在applicationContext.xml中定义该bean来实现初始化。

注意原有的log4j.properites将失效,logback网站上提供转换器,支持从log4j.properties 转换到logback.xml 。

19.2.3. logback.xml的功能与配置

  1. 定义变量

    <substitutionProperty name="log.base" value="../logs/helloworld" />   
  2. JMX管理,logback支持使用JMX随时重载logback.xml或者单独设置某个package的level。

    <jmxConfigurator />
  3. Appender配置

    Rolling每天生成一个日志文件,方便按日期翻查。日志文件会自动压缩,定义文件名pattern时加上.zip即可。

    Encoding默认为平台的编码,建议Console Appender使用默认值。

    Tomcat和Glassfish中,设定日志路径为../logs/xxxx.log 都能将日志放入应用服务器本身的logs目录。

    <appender name="logfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <Encoding>UTF-8</Encoding>
    <File>${log.base}.log</File>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <FileNamePattern>${log.base}.%d{yyyy-MM-dd}.log.zip</FileNamePattern>
    </rollingPolicy>
    <layout class="ch.qos.logback.classic.PatternLayout">
    <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
    </layout>
    </appender>

    特别设置某个logger打印到特殊的log文件。注意,logger的appender默认是叠加的,如果没有设置additivity="false",会同时打印到stdout,logfile和webservice-logfile中。

    <logger name="org.apache.cxf.interceptor.LoggingOutInterceptor" additivity="false">
    <level value="INFO" />
    <appender-ref ref="webservice-logfile" />
    </logger>

19.2.4. slf4j和logback的使用

  1. 如果日志的参数超过3个,需要写成

    Object[] params = {newVal, below, above};
    logger.debug("Value {} was inserted between {} and {}.", params);
  2. 因为内部已优化,作者认为slf4j的logger不需要定义为static。

  3. 可设置缓存后批量写日志文件(但服务器如果重启,可能会丢失未写到磁盘的记录)

  4. MDC,用Filter,将当前用户名等业务信息放入MDC中,在日志format定义中即可使用该变量。

  5. JMS Appender用于告警, DB Appender用于业务日志等

可以使用插件,如生成Log代码的Eclipse插件Log4E。

19.2.5. 选型

使用log4j作者的新作logback+slf4j,因为可以参数化的语句,不用再为了丁点性能写什么 if( logger.isDebugenable()) ....另外logback的整体性能也较佳,Hibernate、Jetty等项目已经迁移到了slf4j。

特别注意使用commons logging + log4j的第三方框架的日志操作会被拦截并转发到logback中,因此原有的log4j.properties文件将失效,真正配置文件为logback.xml。

而原来使用java.util.logging的第三方框架(如CXF),使用JulOverSlf4jProcessor进行拦截。

logback.xml与log4j.xml很像,详细配置见日志的资料。

tomcat和glassfish中,设定日志路径为../logs/xxxx.log 都能将日志放入应用服务器本身的logs目录。

原创粉丝点击