Log4j,将 Web 应用配置为使用相对路径

Posted

技术标签:

【中文标题】Log4j,将 Web 应用配置为使用相对路径【英文标题】:Log4j, configuring a Web App to use a relative path 【发布时间】:2010-09-18 00:33:11 【问题描述】:

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

最好的方法是什么?

【问题讨论】:

这真的只是问题的一半。拥有日志文件的动态路径很好,但是配置文件本身呢。如果只是动态的日志文件位置,那么您将在所有部署的位置拥有相同的日志级别,我认为这是不可取的。我想知道动态指定配置的最佳方法,以便我的开发环境可以在 DEBUG 上登录并在 INFO/WARN 上进行生产。你怎么看? 【参考方案1】:

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

【讨论】:

老实说,我看不出这种方法比使用我在回答中解释的监听器有什么优势。我不在乎它是什么容器,无论我在哪里部署它都可以工作它,而在你的方法中,如果我改变环境,我必须改变一个值。 两种解决方案都使用系统属性,我们只是设置不同。它实际上只取决于灵活性与简单性。我们管理运行我们的应用程序的所有 Tomcat 服务器,所以我喜欢这种灵活性。如果您将战争分发给第 3 方使用,那么简单是有意义的【参考方案2】:

我终于做到了。

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

public void contextInitialized(ServletContextEvent event) 
    ServletContext context = event.getServletContext();
    System.setProperty("rootPath", context.getRealPath("/"));

然后在log4j.properties文件中:

log4j.appender.file.File=$rootPathWEB-INF/logs/MyLog.log

通过这种方式,只要您在设置“rootPath”系统属性之前不使用它,Log4j 就会写入正确的文件夹。这意味着您不能从 ServletContextListener 本身使用它,但您应该能够从应用程序的其他任何地方使用它。

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

你怎么看?

【讨论】:

这是个好主意,但我认为 catalina.home 使用起来可能更安全,因为它总是在任何 log4j 代码初始化之前设置/可用。 如果我只使用 Tomcat,那将是真的,但我的要求是它必须在任何配置为 0 的容器上工作。我的方法实现了这一点,迄今为止没有人为此提出更好的方法。 此解决方案可能适用于使用 Servlet 的 Web 应用程序,但 Steve K 的解决方案 (***.com/questions/216781/…) 适用于任何使用 Log4j 的应用程序。 Spencer K 的解决方案同样基于相对路径,适用于任何使用 Log4j 的应用程序,前提是您将基本目录设置为可预测的路径。 此解决方案仅在您将单个 WebApp 配置为使用它时才有效,因为系统属性对于 tomcat 是全局的,第二个应用程序启动将覆盖第一个 Web 应用程序设置的值。您可以为每个 webapp 指定一个唯一的属性名称,但如果您要这样做,那么您也可以使用 $catalina.home 并在 log4j.properties 文件中添加路径的唯一部分,因为它不容易出错.【参考方案3】:

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

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

【参考方案5】:

如果您没有在 FileAppender 的路径属性中指定根目录,log4j 是否只使用应用程序根目录?所以你应该可以使用:

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

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

【讨论】:

据我所见,它可以使用用户的主目录,如果您不提供绝对路径,则可以使用容器的主目录。不可靠。 @Iker:为什么不能在容器或应用程序配置中明确设置应用程序根目录?一旦在开发和生产中完成了该操作,就可以可靠地使用相对路径。假设根目录设置正确,相对路径是最便携(可重新定位)的解决方案。 我知道这是一篇旧帖子,但我想为其他人做个笔记。对于tomcat,如果没有明确设置应用程序根目录,我相信它默认为您启动tomcat的任何目录。【参考方案6】:

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

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

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

【讨论】:

【参考方案7】:

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

    您在这里专门为操作系统系列定义logDirectory 属性。

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

    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=%dISO8601 [%x] %-5p [%t] [%c1] %m%n
    
    就是这样!

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

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

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

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

详情:

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

    它的文件附加器配置为例如:

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = $webAppRoot/WEB-INF/logs/my-app.log
    ...
    

    我有一个像这样的上下文监听器(使用 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(...)
        
        ...
    
    

【讨论】:

【参考方案10】:

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

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

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

【讨论】:

以上是关于Log4j,将 Web 应用配置为使用相对路径的主要内容,如果未能解决你的问题,请参考以下文章

转:log4j的使用简介

Log4j中配置日志文件相对路径

如何在logback日志配置文件中配置相对路径

Servlet / Tomcat相对文件路径

log4j2 为 FileAppender 指定 tomcat 主目录的相对路径

log4j配置文件中路径配置一般有三种方法: