3

歴史的背景:この問題は、私が思っていたものとはまったく異なりました。以下に原因と解決策を記しますが、参考までに元の投稿を残しておきます。

.properties ファイルのディレクトリを定期的にポーリングし、その構成に基づいて SQL クエリを実行し、電子メールを送信するための単純なフレームワークを開発しています。各 .properties ファイルには同じ範囲の操作があるため、それらはすべて同じ Task クラスによって解釈されます。ただし、それぞれが異なる論理操作を表しているため、それぞれ別のログ ファイルを取得します。

これは、log4j RollingFileAppender の 1 つのインスタンスを共有し、.properties ファイルの値に基づいてその出力ファイルを動的に変更することによって実現されます。これはシングル スレッド アプリケーションであるため、問題なく動作します。

ただし、特定の状況では、この RollingFileAppender が閉じられ、ログが記録されないことを除けば、アプリケーションは何も知らずに継続することに気付きました。通常、このサービスは Linux サーバーでバックグラウンド プロセスとして実行されているため、コンソール出力のおかげで、これを実際に確認できたのは 1 回だけです。何が起こったかは次のとおりです。

1) メイン クラスである StartScheduler は、毎分 TaskPoller の新しいインスタンスを作成します。

2) TaskPoller はディレクトリをスキャンし、各 .properties ファイルから小さな情報をロードして、実行するかどうかを決定します。また、Logger.getLogger(TaskPoller.class) を介して取得する独自の RollingFileAppender もあります。Task を実行する必要がある場合は、Task オブジェクトをインスタンス化し、実行する特定の .properties ファイルを渡します。

3) タスクはその RollingFileAppender を取得し、fileAppender.setFile("newtaskname.log") および fileAppender.activateOptions() を呼び出して、出力ファイルの場所を変更します。次に、その実行中に、次のようなことが起こります。

[TaskPoller]
...
task = new Task(fileName); //Points RollingFileAppender to the right place
if (!task.Execute())
    logger.warn(fileName + " returned with an error code."); //Succeeds
[Task.Execute]
...
try {
    dbDAO.Connect();
} catch (Exception e) {
    logger.fatal{"Database connection error.", e}; //Different RFA; Fails
    return false;
}
[DBDAO.Connect throws SQLException, ClassNotFoundException]
...
try {
    Class.forName(dbDriver); //Dynamically loaded jdbc driver class name
    connection = DriverManager.getConnection(urlString, userName, password);
} catch (SQLException e) {
    if (connection != null)
        try { connection.close(); } catch (Exception e2) { ; }
    throw e;
}

何が起こっているのかというと、DBDAO.Connect() 中に、com.mysql.jdbc.exceptions.jdbc4.CommunicationsException (またはロードされている jdbc クラスからのその他の予期しない例外) が発生することがあります。これは Connect() では捕捉されませんが、Execute() では捕捉されます。

どういうわけか、このプロセスにより、Task の RollingFileAppender が閉じられます。一貫性のある安定した通常の操作とは対照的に、この状況に特有であると私が考えることができる唯一のことは、スローされる例外が Connect() によってスローされると宣言されていないことです。しかし、それによって log4j Appender が閉じられるべきではないと思います。

だから私の質問は、このアペンダーが構成とは関係のないメソッドで予期せず終了する原因は何ですか?

--編集-- 完全に見当違いだったようです。問題は、TaskPoller を毎分起動させるために使用していた Quartz と log4j の間の相互作用のどこかにあります。その原因はまだ完全には理解できていませんが、[この解決策][1] はこの問題を解決しているようです。今まで観測された問題として現れなかっただけなので、最近起こっていることと関係があると思いました。

4

1 に答える 1

0

この問題の本当の原因は、Quartz スケジューラーと私が log4j を使用していた方法との間の相互作用です。Quartzワーカースレッドでlog4jのプロパティ(fileAppender.setFile(fileName)とfileAppender.activateOptions()を呼び出して行っていた)を変更すると(Quartzが一度に1つのスレッドのみを実行するように構成されている場合でも)ことがわかります)、物事は崩壊します。これは、使用する前にワーカー スレッドの新しいインスタンスごとに log4j プロパティを再読み込みすることで修正されます。

[Task() Constructor]
Properties props = new Properties();
URL url = ClassLoader.getSystemResource("log4j.properties");
try {
    props.load(url.openStream());
    PropertyConfigurator.configure(props);
} catch (Exception e) {
    //The logger that never got renamed never stopped working.
    Logger.getLogger(TaskPoller.class).error("Diagnostics!");
}
logger = Logger.getLogger(Task.class);
于 2010-10-26T18:21:22.327 に答える