WinまたはLinuxマシンのいずれかにデプロイする必要があるJavaWebアプリケーションがあります。ロギング用にlog4jを追加したいのですが、展開ごとにファイルパスを変更したくないので、ログファイルの相対パスを使用したいと思います。コンテナはTomcatである可能性が高いですが、必ずしもそうとは限りません。
これを行うための最良の方法は何ですか?
WinまたはLinuxマシンのいずれかにデプロイする必要があるJavaWebアプリケーションがあります。ロギング用にlog4jを追加したいのですが、展開ごとにファイルパスを変更したくないので、ログファイルの相対パスを使用したいと思います。コンテナはTomcatである可能性が高いですが、必ずしもそうとは限りません。
これを行うための最良の方法は何ですか?
Tomcat は catalina.home システム プロパティを設定します。これは、log4j プロパティ ファイルで使用できます。このようなもの:
log4j.rootCategory=DEBUG,errorfile
log4j.appender.errorfile.File=${catalina.home}/logs/LogFilename.log
Debian (Ubuntu を含む) では、${catalina.home}
/var/log/tomcat6 へのリンクがない /usr/share/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
私はついにこのようにそれをしました。
次のことを行う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自体からは使用できませんが、アプリ内の他の場所からは使用できるはずです。
コンテナ固有のシステムプロパティに依存せず、OS固有のパスの問題の影響を受けないため、すべてのWebコンテナとOSで機能するはずです。TomcatとOrionのWebコンテナ、およびWindowsとLinuxでテストされ、これまでのところ正常に動作しています。
どう思いますか?
Spring を使用すると、次のことができます。
1) 「/WEB-INF/classes/log4j-myapp.properties」などの log4j 構成ファイルを作成します。「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) Web アプリケーションのルートに一意の変数名を指定します (例: "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
Ikerのソリューションに関するコメントです。
ServletContext
あなたの問題の良い解決策です。でもメンテナンスには向かないと思います。ほとんどの場合、ログ ファイルは長期間にわたって保存する必要があります。
デプロイされたファイルの下にファイルを作成するためServletContext
、サーバーの再デプロイ時に削除されます。私の提案は、子フォルダーではなく rootPath の親フォルダーを使用することです。
FileAppenderのpathプロパティでルートディレクトリを指定しない場合、log4jはアプリケーションのルートディレクトリを使用するだけではありませんか?したがって、次を使用できるはずです。
log4j.appender.file.File = logs / MyLog.log
私がJavaWeb開発を行ってからしばらく経ちましたが、これは最も直感的であるように思われ、$ {catalina.home}/logsディレクトリに書き込む他の残念な名前のログとも衝突しません。
https://stackoverflow.com/a/218037/2279200に関するさらなるコメントとして- Web アプリが暗黙的に他の ServletContextListener を開始すると、これは壊れる可能性があります。これは以前に呼び出され、既に log4j を使用しようとしています - この場合、 log4j 構成は、ログのルート ディレクトリを決定するプロパティが設定される前に既に読み取られて解析されます => ログ ファイルは、現在のディレクトリ (Tomcat 起動時の現在のディレクトリ) の下のどこかに表示されます。
この問題に対する次の解決策しか考えられませんでした: - log4j.properties (または logj4.xml) ファイルの名前を、log4j が自動的に読み取らない名前に変更します。- コンテキスト フィルターで、プロパティを設定した後、DOM/PropertyConfigurator ヘルパー クラスを呼び出して、log4j-.{xml,properties} が読み取られるようにします - log4j 構成をリセットします (IIRC にはそれを行うメソッドがあります)。
これは少し強引ですが、これが水密にする唯一の方法だと思います。
私の提案は、ログ ファイルは常に webApp のルート コンテキストの上に記録する必要があるため、webApp を再デプロイする場合に備えて、既存のログ ファイルを上書きしたくないということです。
私の解決策は Iker Jimenez の解決策に似ていますが、代わりに をSystem.setProperty(...)
使用しますorg.apache.log4j.PropertyConfigurator.configure(Properties)
。そのためには、log4j がその構成を自分で見つけられないようにする必要もあり、手動でロードします (どちらの点も Wolfgang Liebich's answerで説明されています)。
これは、スタンドアロンまたは IDE から実行される Jetty および Tomcat で機能し、構成が不要で、コンテナー内のアプリの数に関係なく、各アプリのログを独自のフォルダーに配置できます (これは、ベースのソリューションの問題です)。System
このようにして、log4j 構成ファイルを Web アプリ内の任意の場所に配置することもできます (たとえば、1 つのプロジェクトでは、すべての構成ファイルが 内にありました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(...)
}
...
}