Java Log4j,配置Web应用程序以使用相对路径

Java Log4j,配置Web应用程序以使用相对路径,java,web-applications,log4j,Java,Web Applications,Log4j,我有一个java webapp,必须部署在Win或Linux机器上。现在我想为日志添加log4j,我想为日志文件使用相对路径,因为我不想在每次部署时更改文件路径。容器很可能是Tomcat,但不一定是 执行此操作的最佳方法是什么?Tomcat设置catalina.home系统属性。您可以在log4j属性文件中使用它。大概是这样的: log4j.rootCategory=DEBUG,errorfile log4j.appender.errorfile.File=${catalina.home}/l

我有一个java webapp,必须部署在Win或Linux机器上。现在我想为日志添加log4j,我想为日志文件使用相对路径,因为我不想在每次部署时更改文件路径。容器很可能是Tomcat,但不一定是


执行此操作的最佳方法是什么?

Tomcat设置catalina.home系统属性。您可以在log4j属性文件中使用它。大概是这样的:

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${catalina.home}/logs/LogFilename.log
在Debian(包括Ubuntu)上,
${catalina.home}
将不起作用,因为它指向/usr/share/tomcat6,而/usr/share/tomcat6没有指向/var/log/tomcat6的链接。这里只需使用
${catalina.base}

如果您正在使用另一个容器,请尝试查找类似的系统属性,或定义自己的属性。设置系统属性将因平台和容器而异。但是对于Linux/Unix上的Tomcat,我会在CATALINA_HOME/bin目录中创建一个setenv.sh。它将包括:

export JAVA_OPTS="-Dcustom.logging.root=/var/log/webapps"
那么您的log4j.properties将是:

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${custom.logging.root}/LogFilename.log

我终于这样做了

添加了执行以下操作的ServletContextListener:

public void contextInitialized(ServletContextEvent event) {
    ServletContext context = event.getServletContext();
    System.setProperty("rootPath", context.getRealPath("/"));
}
然后在log4j.properties文件中:

log4j.appender.file.File=${rootPath}WEB-INF/logs/MyLog.log
通过这种方式,只要在设置“rootPath”系统属性之前不使用Log4j,Log4j就会写入正确的文件夹。这意味着您不能从ServletContextListener本身使用它,但您应该能够从应用程序中的任何其他位置使用它

它应该适用于每个web容器和操作系统,因为它不依赖于特定于容器的系统属性,也不受特定于操作系统的路径问题的影响。 在Tomcat和Orion web容器以及Windows和Linux上进行了测试,目前为止效果良好


您认为呢?

如果您没有在FileAppender的path属性中指定根目录,那么log4j不是只使用应用程序根目录吗?因此,您应该能够使用:

log4j.appender.file.file=logs/MyLog.log


我已经有一段时间没有进行Java web开发了,但这似乎是最直观的,而且也不会与写入${catalina.home}/logs目录的其他不幸命名的日志发生冲突。

如果使用Spring,您可以:

1) 创建一个log4j配置文件,例如“/WEB-INF/classes/log4j myapp.properties” 不要将其命名为“log4j.properties”

例如:

log4j.rootLogger=ERROR, stdout, rollingFile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.File=${myWebapp-instance-root}/WEB-INF/logs/application.log
log4j.appender.rollingFile.MaxFileSize=512KB
log4j.appender.rollingFile.MaxBackupIndex=10
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.rollingFile.Encoding=UTF-8
log4j.rootLogger=错误,标准输出,滚动文件
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.patternalyout
log4j.appender.stdout.layout.ConversionPattern=%d%p[%c]-%n
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.File=${myWebapp实例root}/WEB-INF/logs/application.log
log4j.appender.rollingFile.MaxFileSize=512KB
log4j.appender.rollingFile.MaxBackupIndex=10
log4j.appender.rollingFile.layout=org.apache.log4j.patternalyout
log4j.appender.rollingFile.layout.ConversionPattern=%d%p[%c]-%m%n
log4j.appender.rollingFile.Encoding=UTF-8
稍后我们将在第(3)点定义“myWebapp实例根”

2) 在web.xml中指定配置位置:

<context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>/WEB-INF/classes/log4j-myapp.properties</param-value>
</context-param>

log4jConfigLocation
/WEB-INF/classes/log4j-myapp.properties
3) 为您的webapp的根指定一个唯一的变量名,例如“myWebapp实例根”


WebApprotKey
myWebapp实例根
4) 添加Log4jConfigListener:

<listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

org.springframework.web.util.Log4jConfigListener
如果您选择了不同的名称,请记住也在log4j-myapp.properties中更改它

请参阅我的文章(仅意大利语…但应该可以理解):

更新(2009/08/01) 我已将我的文章翻译成英文:

只是对解决方案的评论

ServletContext
是解决问题的好方法。但我不认为这对我有好处。大多数时间日志文件需要长时间保存


由于
ServletContext
将文件放在已部署的文件下,因此在重新部署服务器时将删除该文件。我的建议是使用rootPath的父文件夹而不是子文件夹。

我的建议是日志文件应始终记录在webApp的根上下文之上,因此,如果我们重新部署webApp,我们不希望覆盖现有的日志文件。

如果您使用Maven,我有一个很好的解决方案:

  • 编辑pom.xml文件以包含以下行:

    <profiles>
        <profile>
            <id>linux</id>
            <activation>
                <os>
                    <family>unix</family>
                </os>
            </activation>
            <properties>
                <logDirectory>/var/log/tomcat6</logDirectory>
            </properties>
        </profile>
        <profile>
            <id>windows</id>
            <activation>
                <os>
                    <family>windows</family>
                </os>
            </activation>
            <properties>
                <logDirectory>${catalina.home}/logs</logDirectory>
            </properties>
        </profile>
    </profiles>
    
  • 就这样 p.S.:我确信使用Ant可以实现这一点,但不幸的是,我没有足够的经验。

    作为进一步的评论,如果web应用程序隐式启动其他ServletContextListener,可能会中断,这些ServletContextListener可能会在更早的时候被调用,并且已经尝试使用log4j-在这种情况下,在设置确定日志根目录的属性=>日志文件将出现在当前目录(启动tomcat时的当前目录)下的某个地方之前,将读取并解析log4j配置

    我只能想到以下解决这个问题的方法: -将log4j.properties(或logj4.xml)文件重命名为log4j不会自动读取的文件。 -在您的上下文过滤器中,在设置属性之后,调用DOM/PropertyConfigurator助手类以确保您的log4j-.{xml,properties}被读取 -重置log4j配置(IIRC有一种方法可以做到这一点)


    这有点暴力,但我认为这是使其防水的唯一方法。

    我的解决方案与Iker Jimenez的类似,但不是使用
    System.setProperty(…)
    而是使用
    org.apache.log4j.PropertyConfigurator.configure(Properties)
    。为此,我还需要log4j自己无法找到它的配置,并手动加载它(Wolfgang-Liebich中描述了这两点)

    这适用于Jetty和Tomcat,独立或从IDE运行,需要零配置,允许将每个应用程序的日志放在各自的文件夹中,
    <profiles>
        <profile>
            <id>linux</id>
            <activation>
                <os>
                    <family>unix</family>
                </os>
            </activation>
            <properties>
                <logDirectory>/var/log/tomcat6</logDirectory>
            </properties>
        </profile>
        <profile>
            <id>windows</id>
            <activation>
                <os>
                    <family>windows</family>
                </os>
            </activation>
            <properties>
                <logDirectory>${catalina.home}/logs</logDirectory>
            </properties>
        </profile>
    </profiles>
    
    log4j.appender.FILE=org.apache.log4j.RollingFileAppender
    log4j.appender.FILE.File=${logDirectory}/mylog.log
    log4j.appender.FILE.MaxFileSize=30MB
    log4j.appender.FILE.MaxBackupIndex=10
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.FILE.layout.ConversionPattern=%d{ISO8601} [%x] %-5p [%t] [%c{1}] %m%n
    
    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
    @WebListener
    public class ContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(final ServletContextEvent event) {
            Properties props = new Properties();
            InputStream strm =
                ContextListener.class.getClassLoader()
                    .getResourceAsStream("log4j-no-autoload.properties");
            try {
                props.load(strm);
            } catch (IOException propsLoadIOE) {
                throw new Error("can't load logging config file", propsLoadIOE);
            } finally {
                try {
                    strm.close();
                } catch (IOException configCloseIOE) {
                    throw new Error("error closing logging config file", configCloseIOE);
                }
            }
            props.put("webAppRoot", event.getServletContext().getRealPath("/"));
            PropertyConfigurator.configure(props);
            // from now on, I can use LoggerFactory.getLogger(...)
        }
        ...
    }
    
    appender.file.fileName = ${sys:user.dir}/log/application.log