【问题标题】:How to insert current webapp's folder name in log4j filename如何在 log4j 文件名中插入当前 webapp 的文件夹名称
【发布时间】:2011-07-01 23:23:00
【问题描述】:

我正在编写一个 Java Web 应用程序以部署在 Tomcat 中,并且我正在使用 log4j 进行日志记录。我喜欢在生成的日志文件名称中自动插入 Web 应用程序的文件夹名称。

目前 log4j.properties 中的文件名设置如下所示:

log4j.appender.R.File=${catalina.home}/logs/mywebapp.log

我需要这样的东西:

log4j.appender.R.File=${catalina.home}/logs/${current.webapp.folder}.log

是否有某种环境变量可以在属性文件中指定,或者我必须从代​​码中实例化记录器?

【问题讨论】:

    标签: java web-applications tomcat log4j


    【解决方案1】:

    您可以使用上下文侦听器来设置系统属性,然后在 log4j 配置中使用该属性。

    第一步:设置系统属性

    您可以首先将系统属性(例如,contextPath)设置为应用程序的 Tomcat 上下文路径的值。您可以在上下文侦听器中执行此操作。

    package my.package.listener;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    public class ContextListener implements ServletContextListener {
    
        @Override
        public void contextDestroyed(ServletContextEvent arg0) {
        }
    
        @Override
        public void contextInitialized(ServletContextEvent event) {
            defineContextPath(event);
        }
        
        private void defineContextPath(ServletContextEvent event) {
            ServletContext context = event.getServletContext();
            String contextPath = context.getContextPath();
            
            if (contextPath != null) {
                String pattern = ".*/(.*)";
                String contex = contextPath.replaceAll(pattern, "$1");
                System.setProperty("contextPath", contex);
                System.out.println("contextPath: " + contex);
            } else {
                System.out.println("contextPath not found");
            }
        }
    }
    

    在你的 web.xml 中声明监听器:

    <!-- Be sure to keep my.package.ContextListener as the first listener 
         if you have more listeners as below --> 
    <listener>
        <listener-class>my.package.ContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    

    第 2 步:使用系统属性设置 log4j 文件名

    然后在您的 log4j 配置文件中,您可以使用系统属性contextPath 来设置您的 log4j 文件名。

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <Appenders>
            <Console name="STDOUT" target="SYSTEM_OUT">
                <PatternLayout pattern="%d %5p %c{1}:%L - %m%n" />
            </Console>
            <RollingFile name="RollingFile" fileName="${catalina.base}/logs/${tomcat.hostname}/${contextPath}.log" 
                filePattern="${catalina.base}/logs/${tomcat.hostname}/$${date:yyyy-MM}/${contextPath}-%d{MM-dd-yyyy}-%i.log.gz">
                <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n" />
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="500 MB" />
            </RollingFile>
        </Appenders>
        <Loggers>
            <Logger name="org.apache.log4j.xml" level="info" />
            <Root level="info">
                <AppenderRef ref="STDOUT" />
                <AppenderRef ref="RollingFile"/> 
            </Root>
        </Loggers>
    </Configuration>
    

    参考

    【讨论】:

      【解决方案2】:

      这不是一个仅配置文件的解决方案,所以我暂时保留这个问题。

      我已将 log4j.properties 重命名为 myapp-log4j.properties 并修改了日志文件名属性,如下所示:

      log4j.appender.R.File=${catalina.base}/logs/#{context.name}.log
      

      因为我有一个在启动时加载的 servlet,所以我在 init() 函数中初始化 log4j。

      String contextPath = getServletContext().getContextPath();
      
      // First reconfigure log4j
      String contextName = contextPath.substring(1);
      if (!configureLog4J(contextName)) {
        return;
      }
      

      这个功能:

        public static final String LOG4JAPPENDERRFILE = "log4j.appender.R.File";
      
        private boolean configureLog4J(String contextName) {
          Properties props = new Properties();
          try {
             InputStream configStream = getClass().getResourceAsStream("/myapp-log4j.properties");
             props.load(configStream);
             configStream.close();
          } catch(IOException e) {
             System.out.println("FATAL! Cannot load log4j configuration file from classpath.");
             e.printStackTrace(System.out);
             return false;
          }
      
          String logFile = props.getProperty(LOG4JAPPENDERRFILE);
          logFile=logFile.replace("#{context.name}", contextName);
          props.setProperty(LOG4JAPPENDERRFILE, logFile);
          LogManager.resetConfiguration();
          PropertyConfigurator.configure(props);
          return true;
        }
      

      看起来工作正常,但我不太喜欢我必须在代码中修改属性文件。

      【讨论】:

      • Ummm...其他方式,挑战编辑系统属性?但它不是线程安全的......
      【解决方案3】:

      首先尝试附加您的“log4j.properties”。

      current.webapp.folder=myapp
      

      其次,如果你使用了“PropertyConfigurator”...

      Properties props = new Property();
      /* Read "log4j.properties" */
      
      Properties webappProps = new Property();
      /* Read setting ex."current.webapp.folder=myapp" */
      
      Enumeration<Object> e = props.propertyNames();
      while (e.hasMoreElements()) {
          String key = (String) e.nextElement();
          // used org.apache.log4j.helpers.OptionConverter
          props.setProperty(
                  key, 
                  OptionConverter.substVars(props.getProperty(key), webappProps));
      }
      
      PropertyConfigurator.configure(props);
      

      【讨论】:

      • 这是一个很好的解决方案,但我根本不喜欢硬编码 webapp 的文件夹名称。我的 Web 应用程序可以多次使用不同的名称部署到同一个 Tomcat。我想让日志文件配置尽可能自动化。
      猜你喜欢
      • 2012-05-23
      • 2013-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-21
      相关资源
      最近更新 更多