log4j及log4j2在Spring MVC中的使用.md

96
混迹在Amoy
2018.07.28 08:22* 字数 853

项目已上线许久,项目中使用的是log4j 1.x版本,本来日志也可以正常记录,但是运维报怨说,你们的日志太大了,catalina.out日志输出无限大,以致有些应用出现服务器存储告警,所以建议我们:

“应用日志必须对接公司统一日志平台,若同时也存放在本地服务器,则统一放在容器根目录下的单独文件夹,文件夹名称带有log字样,日志文件按日期或大小归档,单个日志文件超过20M的文件需要在归档时同时压缩,默认只保留最近一个月的日志,由代码实现自动清理。”

总结日志管理需求:

  1. 日志写入到统一日志平台(ELK日志平台);
  2. 本地日志文件需按日期或大小归档;
  3. 单个日志文件如超过20M需在归档时压缩;
  4. 自动清理日志,默认保留近一个月日志;
  5. 关闭catalina.out日志输出;

鉴于以上需求,我发现log4j 1.x版本有些做不到,而log4j 2.x版本正好可以很好的满足:

  1. Tomcat标准部署通过log4j配置无法关闭catalina.out日志输出;
  2. 无法自动清理日志,仅保存近一个月日志;
  3. 无法对超过20M的日志文件在归档时自动压缩;

备注:不升级log4j,如何解决以上问题?
1.通过Tomcat配置关闭catalina.out日志输出。

# 直接找到Tomcat下bin/catalina.sh文件中以下代码片段:
if [ -z "$CATALINA_OUT" ] ; then
  CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out

# 将上面的内容修改成下面内容即可:
if [ -z "$CATALINA_OUT" ] ; then
  CATALINA_OUT=/dev/null # 输入到/dev/null黑洞

2.通过编写服务器脚本、定时任务实现日志清理和压缩;

以上两种方法也可以达到同样的目的,但是运维的同学才不愿意这么干,给你们提供个web容器,其它最好你们程序自己实现:)

log4j2是log4j的升级版,log4j2除了可以满足以上需求,听说性能也更好,将旧项目中的log4j升级到log4j2的成本也较低。

[TOC]

一、log4j配置

官方文档:http://logging.apache.org/log4j/1.2/apidocs

1. Maven包引入

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.19</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.19</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

2. log4j.properties配置文件

log4j.properties配置文件

log4j约定了其配置文件在默认加载类的路径下,即classpath的根路径,所以如最终发布在classpath根路径下,则在使用时无需指定路径。

### set log levels ###
log4j.rootLogger=debug,stdout,debug,error,rsyslog
#log4j.rootLogger=debug,debug,error,rsyslog

### 配置根Logger:设定日志记录的最低级别 ###
log4j.category.org.springframework=ERROR
log4j.category.org.apache=INFO
log4j.logger.org.hibernate=ERROR

### 输出到控制台 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}][%t] %l %m %n

### 输出到日志文件 ###
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.File = ${catalina.home}/msp-logs/info.log
log4j.appender.debug.datePattern='.'yyyy-MM-dd
log4j.appender.debug.append=true
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}][%t] %l %m %n

### ERROR输出到日志文件 ###
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File = ${catalina.home}/msp-logs/error.log
log4j.appender.error.datePattern='.'yyyy-MM-dd
log4j.appender.error.append=true
log4j.appender.error.Threshold=ERROR
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n

#appender rsyslog 端口不可配置,使用默认的:514
log4j.appender.rsyslog=org.apache.log4j.net.SyslogAppender
log4j.appender.rsyslog.syslogHost=11.4.74.26
log4j.appender.rsyslog.Facility=local1
log4j.appender.rsyslog.FacilityPrinting=true
log4j.appender.rsyslog.header=true
log4j.appender.rsyslog.layout=org.apache.log4j.PatternLayout
log4j.appender.rsyslog.layout.conversionPattern=WEIXIN-MSP %d [%-5p] [%t] - %m%n

3. web.xml配置

web.xml配置文件中添加log4j监听器,其中webAppRootKey配置,可将对应日志写入到对应的项目下,缺省值是“webapp.root”,最好要定义,值随便填写,否则对于tomcat部署多个项目时,会冲突。

<!-- log4j配置 -->
<!-- 配置文件如放默认路径,log4jConfigLocation可不配 -->
<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>WEB-INF/log4j.properties</param-value>
</context-param>
<context-param>
    <param-name>log4jRefreshInterval</param-name>
    <param-value>600000</param-value>
</context-param>
<context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>webName.root</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>

二、log4j2配置

1. Maven包引入

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.11.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.11.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.11.1</version>
        </dependency>

2. log4j2.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--status指定log4j本身(log4j2这个程序)打印日志的级别-->
<Configuration status="WARN" packages="">
    <Appenders>
        <!--输出至控制台的配置-->
        <Console name="Console" target="SYSTEM_OUT">
        <PatternLayout charset="utf-8" pattern="%d{yyyy-MM-dd HH:mm:ss} %class{36} [%p] %m%n"/>
        </Console>
        <!--输出至日志文件的配置-->
        <RollingFile name="errorFile" fileName="${sys:catalina.base}/logs/error.log"
        filePattern="${sys:catalina.base}/logs/error.log.%d{yyyyMMdd}">
        <PatternLayout charset="utf-8" pattern="%d{yyyy-MM-dd HH:mm:ss} %class{36} [%p] %m%n"/>
        <Policies>
        <TimeBasedTriggeringPolicy modulate="true"/>
        </Policies>
        </RollingFile>
        <RollingFile name="infoFile" fileName="${sys:catalina.base}/wx-logs/info.log"
                     filePattern="${sys:catalina.base}/wx-logs/info.log.%d{yyyyMMdd}">
            <PatternLayout charset="utf-8" pattern="%d{yyyy-MM-dd HH:mm:ss} %class{36} [%p] %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true"/>
            </Policies>
        </RollingFile>
        <!--输出至日志平台的配置 log4j2写入日志平台无法识别appName,希望采用facility=auth能与其它系统区别开-->
        <Syslog name="SYSLOG" format="RFC5424" host="11.4.74.26" port="514"
                protocol="UDP" appName="WEIXIN-VUE-API" includeMDC="true"
                facility="USER" enterpriseNumber="18060" newLine="true"
                messageId="Audit" mdcId="mdc" id="App"
                connectTimeoutMillis="1000" reconnectionDelayMillis="5000">
            <LoggerFields>
                <KeyValuePair key="thread" value="%t"/>
                <KeyValuePair key="priority" value="%p"/>
                <KeyValuePair key="category" value="%c"/>
                <KeyValuePair key="exception" value="%ex"/>
                <KeyValuePair key="message" value="%m"/>
            </LoggerFields>
        </Syslog>
    </Appenders>
    <!--日志级别:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.-->
    <Loggers>
        <!--只有定义了logger并引入的appender,appender才会生效-->
        <Logger name="error" level="error" additivity="false">
        <!--Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.
        如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"
        只在自定义的Appender中进行输出-->
            <AppenderRef ref="SYSLOG"/>
            <AppenderRef ref="errorFile"/>
        </Logger>
        <!--Root用来指定项目的根日志,没有单独指定Logger,会统一输出到Root中-->
        <Root level="Info" additivity="false">
            <AppenderRef ref="SYSLOG"/>
            <AppenderRef ref="infoFile"/>
        </Root>
    </Loggers>
</Configuration>

3. 使用方式

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

// 普通使用
private static final Logger LOGGER = LogManager.getLogger(HelloController.class);

LOGGER.error("error log.");  // 会命中log4j2配置的Root项

// 高级使用
LogManager.getLogger("LoggerName01").error(error log.); 会命中log4j2配置的LoggerName01项

LogManager.getLogger("LoggerName02").error(error log.); 会命中log4j2配置的LoggerName02项

4. 按天分日志文件

        <RollingFile name="error_appender" fileName="${sys:catalina.base}/wx-logs/error.log" filePattern="${sys:catalina.base}/wx-logs/error-%d{yyyy-MM-dd}.log">
            <PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss} [%thread] %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
            </Policies>
        </RollingFile>

5. 按大小分日志文件

        <RollingFile name="error_appender" fileName="${sys:catalina.base}/wx-logs/error.log" filePattern="${sys:catalina.base}/wx-logs/error-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss} [%thread] %m%n"/>
            <SizeBasedTriggeringPolicy size="100 MB" />
        </RollingFile>

6. 保留文件个数DefaultRolloverStrategy

DefaultRolloverStrategy是Log4j2提供的默认的rollover策略,默认的max为7。max参数指定了计数器的最大值,一旦计数器达到了最大值,旧的文件将被删除。

            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="200 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="7"/>

7. 自动清理日志

自动清理日志功能,要求log4j的版本为2.5+,日志包而已,直接用现在最新的版本2.11。

            <!-- 保存最多50个日志文件/天,保留30天 -->
            <DefaultRolloverStrategy max="50">
                <Delete basePath="${LOG_HOME}/" maxDepth="2">
                    <IfFileName glob="*.log.gz" />
                    <IfLastModified age="30d" />
                </Delete>
            </DefaultRolloverStrategy>
后端开发
Gupao