2008-10-19 136 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容器,且不需要將自定義變量傳遞給系統環境。

相關問題