2008-10-19 109 views
75

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

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

+2

这实在只是问题的一半。有一个动态路径的日志文件是伟大的,但配置文件本身呢。如果它只是动态的日志文件位置,那么在部署的所有位置中都会具有相同的日志级别,并且我不认为这是可取的。我想知道动态指定配置的最佳方法,以便我的开发环境可以在DEBUG上登录并在INFO/WARN中生成。你怎么看? – Lucas 2011-10-07 11:24:35

回答

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 

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

它应该适用于每个Web容器和操作系统,因为它不依赖于特定于容器的系统属性,也不受操作系统特定路径问题的影响。 使用Tomcat和Orion Web容器进行测试,并且在Windows和Linux上运行良好,至今为止工作正常。

您认为如何?

+4

这是一个好主意,但我认为catalina.home可能更安全,因为在任何log4j代码初始化之前,它始终会设置/可用。 – 2008-10-20 13:59:00

97

Tomcat设置了catalina.home系统属性。你可以在你的log4j属性文件中使用它。事情是这样的:

log4j.rootCategory=DEBUG,errorfile 

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

在Debian(包括Ubuntu),${catalina.home}不会工作,因为它指向位于/ usr /共享/ tomcat6中它没有链接到/ var /日志/ 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 
+2

我真的不明白这个方法在使用Listener方面有什么优势,我在我的回答中解释过。我不在乎它是什么容器,无论我在哪里部署,它都能正常工作,而在我的方法中,如果我改变环境,我必须改变一个值。 – 2008-10-20 16:01:22

+4

这两种解决方案都使用系统属性,我们只是以不同的方式设置它们。这实际上只取决于灵活性与简单性。我们管理运行我们的应用程序的所有Tomcat服务器,所以我喜欢这种灵活性。如果您为第三方使用发布战争,简单有道理 – 2008-10-20 16:39:39

4

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

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

它已经一段时间,因为我做了Java Web开发,但这似乎是最直观的,并且不会与写入$ {catalina.home}/logs目录的其他不幸命名的日志冲突。

14

如果你使用Spring,你可以:

1)创建一个log4j的配置文件,如“/WEB-INF/classes/log4j-myapp.properties” 请勿将其命名为“log4j。属性”

实施例:

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 

我们将定义 “myWebapp实例根” 稍后点(3)

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

UPDATE(2009/08/01) 我翻译我的文章以英文: http://www.megadix.it/node/136

6

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

ServletContext是您的问题的一个很好的解决方案。但我认为这不利于维护。大多数时间日志文件需要长时间保存。

由于ServletContext使文件在部署的文件下,所以在重新部署服务器时它将被删除。我的建议是使用rootPath的父文件夹而不是子文件夹。

1

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

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财产特别到OS系列。

  2. 使用已经在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=%d{ISO8601} [%x] %-5p [%t] [%c{1}] %m%n 
    
  3. 这就是它!

P.S:我敢肯定,这可以使用Ant来实现,但是不幸的是我没有与它足够的经验。

1

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

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

这是一个有点蛮力,但methinks它是唯一的方法,使其水密。

0

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

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

详情:

  1. 我在classpath我在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的更短的“尝试 - 与清晰度乌尔斯河”语法):

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

您可以指定相对路径到日志文件,并使用工作目录

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

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