Log4j、相対パスを使用するようにWebアプリを構成する


80

WinまたはLinuxマシンのいずれかにデプロイする必要のあるJavaWebアプリケーションがあります。ロギング用にlog4jを追加したいのですが、展開ごとにファイルパスを変更したくないので、ログファイルの相対パスを使用したいと思います。コンテナはTomcatである可能性が高いですが、必ずしもそうとは限りません。

これを行うための最良の方法は何ですか?


3
これは実際には質問の半分にすぎません。ログファイルの動的パスがあることは素晴らしいことですが、構成ファイル自体はどうでしょうか。動的なのがログファイルの場所だけである場合、これが展開されているすべての場所で同じログレベルがあり、それが望ましいとは思いません。開発環境がDEBUGでログを記録し、INFO / WARNでprodできるように、構成を動的に指定するための最良のアプローチを知りたいです。どう思いますか?
ルーカス

回答:


100

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

2
正直なところ、このアプローチが、回答で説明したリスナーを使用することに対してどのような利点があるのか​​わかりません。コンテナが何であるかは関係ありません。どこにデプロイしても機能しますが、あなたのアプローチでは、環境を変更した場合は値を変更してください。
Iker Jimenez

4
どちらのソリューションもシステムプロパティを使用しており、設定が異なるだけです。それは本当に、柔軟性と単純さに依存します。アプリケーションが実行されているすべてのTomcatサーバーを管理しているので、柔軟性が気に入っています。サードパーティが使用するために戦争を配布する場合、単純さは理にかなっています
Steve K

54

私はついにこのようにそれをしました。

次のことを行う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自体からは使用できませんが、アプリ内の他の場所からは使用できるはずです。

コンテナ固有のシステムプロパティに依存せず、OS固有のパスの問題の影響を受けないため、すべてのWebコンテナとOSで機能するはずです。TomcatとOrionのWebコンテナ、およびWindowsとLinuxでテストされ、これまでのところ正常に動作しています。

どう思いますか?


4
これは良い考えですが、catalina.homeは、log4jコードが初期化される前に常に設定/使用可能になるため、より安全に使用できると思います。
マットb

6
これは、Tomcatのみを使用している場合にも当てはまりますが、構成が0のコンテナーで機能する必要があるという要件があります。私のアプローチはこれを満たし、これまでのところ誰もこれより良いアプローチを提案していません。
Iker Jimenez

2
このソリューションは、サーブレットを使用するWebアプリケーションで機能する可能性がありますが、Steve Kのソリューション(stackoverflow.com/questions/216781/…)は、Log4jを使用するすべてのアプリケーションで機能します。
デレクマハール2010年

2
同じく相対パスに基づくSpencerKのソリューションは、ベースディレクトリを予測可能なパスに設定していることを前提として、Log4jを使用するすべてのアプリケーションで機能します。
デレクマハール2010年

12
このソリューションは、単一のWebAppを使用するように構成されている場合にのみ機能します。これは、システムプロパティがグローバルであり、2番目のアプリをTomcatすると、最初のWebアプリが設定した値が上書きされるためです。各Webアプリに一意のプロパティ名を付けることもできますが、そうする場合は、$ {catalina.home}を使用して、エラーが発生しにくいため、パスの一意の部分をlog4j.propertiesファイルに追加することもできます。 。
3urdoch 2010年

14

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

「myWebapp-instance-root」は後でポイント(3)で定義します。

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


6

Ikerのソリューションについてのコメントです。

ServletContextあなたの問題の良い解決策です。しかし、それは維持には良くないと思います。ほとんどの場合、ログファイルは長期間保存する必要があります。

以来ServletContext展開されたファイルの下のファイルを作成、サーバーが再デプロイされたときに、それが削除されます。私の提案は、子フォルダーではなく、rootPathの親フォルダーを使用することです。


5

FileAppenderのpathプロパティでルートディレクトリを指定しない場合、log4jはアプリケーションのルートディレクトリを使用するだけではありませんか?したがって、次のものを使用できるはずです。

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

Java Web開発を行ってからしばらく経ちますが、これは最も直感的であるように思われ、$ {catalina.home} / logsディレクトリに書き込む他の残念な名前のログとも衝突しません。


4
私が見たところ、絶対パスを指定しない場合は、ユーザーのホームディレクトリ、またはコンテナのホームディレクトリを使用できます。信頼性がありません。
Iker Jimenez

1
@Iker:コンテナまたはアプリケーション構成でアプリケーションのルートディレクトリを明示的に設定できないのはなぜですか?開発と本番で一度それを行うと、相対パスを確実に使用できます。ルートディレクトリが正しく設定されていると仮定すると、相対パスが最も移植性の高い(再配置可能な)ソリューションです。
デレクマハール2010年

1
私はこれが古い投稿であることを知っていますが、他の人のためにこれについてメモしたいと思いました。tomcatの場合、アプリケーションのルートディレクトリが明示的に設定されていない場合、tomcatを開始したディレクトリがデフォルトになると思います。
Geren White

2

https://stackoverflow.com/a/218037/2279200に関する追加のコメントとして、Webアプリが他のServletContextListenerを暗黙的に開始すると、これが破損する可能性があります。他のServletContextListenerは以前に呼び出され、すでにlog4jを使用しようとしています。 log4j構成は、ログルートディレクトリを決定するプロパティが設定される前にすでに読み取られて解析されます=>ログファイルは現在のディレクトリ(tomcatを起動したときの現在のディレクトリ)の下のどこかに表示されます。

この問題に対する次の解決策しか考えられませんでした。-log4j.properties(またはlogj4.xml)ファイルの名前をlog4jが自動的に読み取らない名前に変更します。-コンテキストフィルターで、プロパティを設定した後、DOM / PropertyConfiguratorヘルパークラスを呼び出して、log4j-。{xml、properties}が読み取られるようにします-log4j構成をリセットします(IIRCにはそれを行うメソッドがあります)

これは少し野蛮な力ですが、それを水密にする唯一の方法であると考えています。


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. ファイルで定義済みのlogDirectoryプロパティを使用しlog4j.propertiesます。

    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を使用して達成できると確信していますが、残念ながら、十分な経験がありません。


1

私の提案では、ログファイルは常にwebAppのルートコンテキストの上に記録する必要があるため、webAppを再デプロイする場合に備えて、既存のログファイルを上書きしたくありません。


1

私のソリューションはIkerJimenezのソリューションに似ていますが、使用System.setProperty(...)する代わりにを使用しますorg.apache.log4j.PropertyConfigurator.configure(Properties)。そのためには、log4jがそれ自体で構成を見つけることができないようにする必要があり、手動でロードします(両方のポイントはWolfgangLiebichの回答に記載されています))。

IDEから桟橋とTomcat、スタンドアロンまたは実行のためのこの作品は、どんなに多くのアプリケーション(あるコンテナ内、自分のフォルダ内の各アプリケーションのログを配置することができます、ゼロ設定が必要になり、問題Systemベースのソリューション)。このようにして、log4j構成ファイルをWebアプリ内の任意の場所に配置することもできます(たとえば、1つのプロジェクトにすべての構成ファイルが含まれていましたWEB-INF/)。

詳細:

  1. log4j-no-autoload.propertiesクラスパスのファイルにプロパティがあります(たとえば、Mavenプロジェクトではsrc/main/resources、元々含まれていて、にパッケージ化されています)WEB-INF/classes)、
  2. 次のように構成されたファイルアペンダーがあります。

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  3. そして、私はこのようなコンテキストリスナーを持っています(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(...)
        }
        ...
    }
    

1

作業ディレクトリを使用して、ログファイルへの相対パスを指定できます。

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

これはサーブレットコンテナから独立しており、カスタム変数をシステム環境に渡す必要はありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.