Log4j,configurationWeb App使用相对path

我有一个Java Web应用程序,必须在Win或Linux机器上部署。 我现在想要添加log4j进行日志logging,我想为日志文件使用相对path,因为我不想在每个部署上更改文件path。 容器很可能是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中没有链接到/ var / log / tomcat6。 这里只需使用${catalina.base}

如果你使用另一个容器,试着find一个类似的系统属性,或者定义你自己的。 设置系统属性将因平台和容器而异。 但是对于Linux / Unix上的Tomcat,我会在CATALINA_HOME / bin目录下创build一个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容器和操作系统上工作,因为它不依赖于特定于容器的系统属性,并且不受操作系统特定path问题的影响。 使用Tomcat和Orion Web容器进行testing,在Windows和Linux上运行良好。

你怎么看?

如果你使用Spring,你可以:

1)创build一个log4jconfiguration文件,例如“/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中指定configuration位置:

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

3)为你的webapp的根目录指定一个唯一的variables名称,例如“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> 

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

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

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

只是对伊克解决scheme的评论。

ServletContext是你的问题的一个很好的解决scheme。 但是我不认为这对维护有好处。 大部分时间日志文件都需要长时间保存。

由于ServletContext使文件在部署文件下,因此在重新部署服务器时将被删除。 我的build议是去rootPath的父文件夹,而不是孩子。

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

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

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

如果你使用Maven我有一个很好的解决scheme给你:

  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. 而已!

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

我的build议是,日志文件应该始终logging在Web应用程序的根上下文之上,所以如果我们重新部署webApp,我们不希望覆盖现有的日志文件。

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

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

这有点暴躁,但认为这是使水密的唯一途径。

我的解决scheme与Iker Jimenez的解决scheme类似,但使用System.setProperty(...)我使用org.apache.log4j.PropertyConfigurator.configure(Properties) 。 为此,我还需要log4j无法自己find它的configuration,并手动加载(Wolfgang Liebich的回答中描述了这两点)。

这适用于Jetty和Tomcat,独立运行或者从IDE运行,需要零configuration,允许将每个应用程序的日志放在自己的文件夹中,而不pipe容器内有多less应用程序(这是基于System的解决scheme的问题 )。 这样,你也可以把log4jconfiguration文件放在web应用程序的任何地方(例如,在一个项目中,我们已经在WEB-INF/里面configuration了所有的文件)。

细节:

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

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

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

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

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