首页 > 解决方案 > Tomcat WebApp 中的 log4j2:意外的日志轮换

问题描述

当我将 log4j2 与运行在Apache Tomcat/8.0.32 (Ubuntu). 似乎日志在新的一天开始时被旋转并用 gzip 打包,并且没有创建新的普通日志文件。

Appender 配置在 Web 应用程序的上下文中不使用时可以正常工作。

是什么导致了日志轮换以及如何修复它?是否与Tomcat 的内部日志记录机制冲突?

我创建了一个 SSCCE:

src/test/log4j/listener/StartStopListener.java

package test.log4j.listener;

import javax.servlet.ServletContextEvent;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.web.Log4jServletContextListener;

import test.log4j.logger.BaseLogger;
import test.log4j.logger.BaseLoggerSetup;

public class StartStopListener extends Log4jServletContextListener{

   @Override
   public void contextInitialized(ServletContextEvent sce){

      super.contextInitialized(sce);

      System.setProperty("java.util.logging.manager",
                         "org.apache.logging.log4j.jul.LogManager");
      System.setProperty("log4j.skipJansi",
                         "true");
      try{
         new BaseLoggerSetup();
         BaseLogger.getLogger().info("Servlet starts ...");
      }
      catch(Exception e){
         BaseLogger.getLogger().catching(e);
      }

      BaseLogger.getLogger().info("Servlet started");
   }

   @Override
   public void contextDestroyed(ServletContextEvent sce){

      BaseLogger.getLogger().info("Servlet terminates ...");

      LogManager.shutdown();

      super.contextDestroyed(sce);
   }
}

src/test/log4j/logger/BaseLogger.java

package test.log4j.logger;

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

public interface BaseLogger{

   public static Logger getLogger(){

      return LogManager.getLogger(StackLocatorUtil.getCallerClass(2));
   }
}

src/test/log4j/logger/BaseLoggerSetup.java

package test.log4j.logger;

import java.net.URL;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;

public class BaseLoggerSetup implements BaseLogger{

   public BaseLoggerSetup() throws Exception{

      this("/META-INF/log4j.properties");
   }

   public BaseLoggerSetup(String internalProperties) throws Exception{

      URL url = BaseLoggerSetup.class.getResource(internalProperties);

      if (System.getProperty("log4j.configurationFile") == null){
         final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
         ctx.setConfigLocation(url.toURI());
      }
   }
}

资源/META-INF/log4j.properties

name=testlogger 
status=debug
dest=err

appender.test.type=RollingFile
appender.test.name=test
appender.test.fileName=${sys:user.dir}/logs${web:contextPath}/test.log
appender.test.filePattern=${sys:user.dir}/logs${web:contextPath}/test.%i.log.gz
appender.test.layout.type=PatternLayout
appender.test.layout.pattern=%d - %-5p - [%t] - (%C::%M[%L]) - %notEmpty{%marker: }%m%n
appender.test.policies.type=Policies
appender.test.policies.size.type=SizeBasedTriggeringPolicy
appender.test.policies.size.size=50000KB
appender.test.strategy.type=DefaultRolloverStrategy
appender.test.strategy.max=10

appender.test_error.type=RollingFile
appender.test_error.name=test_error
appender.test_error.fileName=${sys:user.dir}/logs${web:contextPath}/test_error.log
appender.test_error.filePattern=${sys:user.dir}/logs${web:contextPath}/test_error.%i.log.gz
appender.test_error.layout.type=PatternLayout
appender.test_error.layout.pattern=%d - %-5p - [%t] - (%C::%M[%L]) - %notEmpty{%marker: }%m%n
appender.test_error.policies.type=Policies
appender.test_error.policies.size.type=SizeBasedTriggeringPolicy
appender.test_error.policies.size.size=50000KB
appender.test_error.strategy.type=DefaultRolloverStrategy
appender.test_error.strategy.max=10

rootLogger.level=info
rootLogger.appenderRefs=test test_error
rootLogger.appenderRef.test.level=info
rootLogger.appenderRef.test.ref=test
rootLogger.appenderRef.test_error.level=error
rootLogger.appenderRef.test_error.ref=test_error

资源/log4j2.component.properties

Log4jContextSelector=org.apache.logging.log4j.core.selector.JndiContextSelector

WEB_INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
    <display-name>Test Log4j Web</display-name>

    <listener>
        <listener-class>
            test.log4j.listener.StartStopListener
        </listener-class>
    </listener>

    <filter>
        <filter-name>log4jServletFilter</filter-name>
        <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>log4jServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
        <dispatcher>ASYNC</dispatcher><!-- Servlet 3.0 w/ disabled auto-initialization only; not supported in 2.5 -->
    </filter-mapping>

    <context-param>
        <param-name>isLog4jAutoInitializationDisabled</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>isLog4jContextSelectorNamed</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>log4jContextName</param-name>
        <param-value>testLog4j</param-value>
    </context-param>

</web-app>  

构建.gradle

apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'war'

group = 'test.log4j.service'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    compile group: 'org.apache.tomcat', name: 'tomcat-servlet-api', version: '8.0.53'
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.11.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-web', version: '2.11.1'    
}

sourceSets {
    main {
        java {
            srcDirs  = ['src']
        }
        resources {
            srcDirs  = ['resources']
        }
    }
    test {
        java {
           srcDirs  = ['src', 'test']
        }
        resources {
            srcDirs  = ['resources']
        }
    }
}

war{
    webInf {
        from("WEB_INF")
        include "web.xml"
    }
    metaInf {
        from("resources/META_INF")
        include "*"
    }
}

编辑:我将 Tomcat 的日志系统从 JUL 切换到 log4j2(请参阅Log4j App Server Integration),现在这个问题也会影响 Tomcat 的日志。

Edit2:这似乎是 Ubuntu 对 tomcat8 的 logrotate 配置的问题。编辑 logrotate 配置后问题消失。

标签: javatomcatlogginglog4j2tomcat8

解决方案


推荐阅读