Log4j,配置Web App以使用相对路径

时间:2008-10-19 18:32:02

标签: java web-applications log4j

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

这样做的最佳方式是什么?

10 个答案:

答案 0 :(得分:99)

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

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${catalina.home}/logs/LogFilename.log

在Debian(包括Ubuntu)上,${catalina.home}将无效,因为它指向/ 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

答案 1 :(得分:52)

我终于以这种方式完成了它。

添加了一个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就会写入正确的文件夹。这意味着您无法从ServletContextListener本身使用它,但您应该能够在应用程序的任何其他位置使用它。

它应该适用于每个Web容器和操作系统,因为它不依赖于特定于容器的系统属性,并且不受操作系统特定路径问题的影响。 使用Tomcat和Orion Web容器以及Windows和Linux进行测试,到目前为止工作正常。

您怎么看?

答案 2 :(得分:14)

如果你使用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

稍后我们将在第(3)点

定义“myWebapp-instance-root”

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

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

3)为您的网络应用根指定唯一变量名称,例如“myWebapp实例根”

<context-param>
  <param-name>webAppRootKey</param-name>
  <param-value>myWebapp-instance-root</param-value>
</context-param>

4)添加一个Log4jConfigListener:

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

如果您选择其他名称,请记住在log4j-myapp.properties中更改它。

查看我的文章(仅限意大利语......但这应该是可以理解的): http://www.megadix.it/content/configurare-path-relativi-log4j-utilizzando-spring

更新(2009/08/01) 我把文章翻译成英文: http://www.megadix.it/node/136

答案 3 :(得分:6)

仅对Iker's解决方案发表评论。

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

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

答案 4 :(得分:5)

如果未在FileAppender的path属性中指定根目录,log4j是否只使用应用程序根目录?所以你应该能够使用:

log4j.appender.file.File =日志/ MyLog.log

自从我完成Java Web开发以来已经有一段时间了,但这似乎是最直观的,也不会与写入$ {catalina.home} / logs目录的其他不幸的命名日志冲突。

答案 5 :(得分:2)

作为对https://stackoverflow.com/a/218037/2279200的进一步评论 - 这可能会破坏,如果Web应用程序隐含地启动其他ServletContextListener(可能先前调用并且已经尝试使用log4j) - 在这种情况下,将读取log4j配置并且在确定日志根目录的属性之前已经解析= set =&gt;日志文件将出现在当前目录下的某个位置(启动tomcat时的当前目录)。

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

这是一种蛮力,但认为它是使其不漏水的唯一方法。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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

  1. 编辑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>
    

    在这里,您可以专门为OS系列定义logDirectory属性。

  2. logDirectory文件中使用已定义的log4j.properties属性:

    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
    
  3. 就是这样!
  4. P.S。:我确信这可以通过Ant来实现,但遗憾的是我没有足够的经验。

答案 8 :(得分:1)

我的解决方案类似于Iker Jimenez的solution,但我没有使用System.setProperty(...),而是使用org.apache.log4j.PropertyConfigurator.configure(Properties)。为此,我还需要log4j无法自己找到它的配置,我手动加载它(Wolfgang Liebich&#39; s answer中描述的两个点)。

这适用于Jetty和Tomcat,独立或从IDE运行,需要零配置,允许将每个应用程序的日志放在自己的文件夹中,无论容器内有多少个应用程序({{3}使用基于System的解决方案)。这样,人们也可以将log4j配置文件放在Web应用程序的任何位置(例如,在WEB-INF/内的所有配置文件的一个项目中)。

详细说明:

  1. 我在类路径的log4j-no-autoload.properties文件中有我的属性(例如,在我的Maven项目中,它最初在src/main/resources中,被打包到WEB-INF/classes),
  2. 它将文件appender配置为例如:

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  3. 我有一个像这样的上下文监听器(使用Java 7&#39; s-try-with-resource&#34;语法缩短得更短):

    @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(...)
        }
        ...
    }
    

答案 9 :(得分:1)

您可以使用工作目录

指定日志文件的相对路径
appender.file.fileName = ${sys:user.dir}/log/application.log

这与servlet容器无关,也不需要将自定义变量传递给系统环境。