80

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

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

4

10 回答 10

101

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
于 2008-10-19T18:58:07.450 回答
55

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

添加了执行以下操作的 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 上进行了测试,到目前为止它运行良好。

你怎么看?

于 2008-10-20T10:52:18.397 回答
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) 为您的 webapp 的根指定一个唯一的变量名称,例如“myWebapp-instance-root”

<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

于 2008-11-26T11:40:15.367 回答
6

只是对Iker解决方案的评论。

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

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

于 2010-01-05T22:44:07.920 回答
5

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

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

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

于 2008-10-20T15:20:39.073 回答
2

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

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

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

于 2014-11-19T16:23:52.153 回答
1

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

于 2010-12-25T01:01:34.123 回答
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>
    

    在这里,您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. 就是这样!

PS:我确信这可以使用 Ant 来实现,但不幸的是我没有足够的经验。

于 2013-04-17T18:55:52.450 回答
1

我的解决方案类似于 Iker Jimenez 的解决方案,但System.setProperty(...)我没有使用org.apache.log4j.PropertyConfigurator.configure(Properties). 为此,我还需要 log4j 无法自行找到它的配置,我手动加载它(Wolfgang Liebich 的回答中描述了这两点)。

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

细节:

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

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  3. 而且我有一个这样的上下文监听器(使用 Java 7 的“try-with-resource”语法变得更短):

    @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(...)
        }
        ...
    }
    
于 2015-09-03T15:09:41.043 回答
1

您可以使用工作目录指定日志文件的相对路径:

appender.file.fileName = ${sys:user.dir}/log/application.log

这独立于 servlet 容器,不需要将自定义变量传递给系统环境。

于 2017-04-17T22:01:25.180 回答