ここ数日、この問題に苦しんでいます。
要件 このアプリケーションでは、nodejs で開発された UI を介してファイルをアップロードし、ファイル レコードは amazon シンプル ワークフロー (SWF) を介して処理されます。amazon SWF への呼び出しは、ファイルの処理時に nodejs アプリが呼び出す Spring アプリを介して行われます。要件は、処理中のすべてのファイルについて、処理中にレコードに何が起こったかを詳述するログ ファイルをアプリケーションが作成する必要があることです。
どのように実装しましたか? SWF をトリガーする Spring アプリケーションで、静的な StringBuffer 変数を維持する FileLogger クラスを作成しました。この fileLogger クラスはワークフロー スコープに設定されます。つまり、クラスはワークフローの実行ごとに作成され、最後に破棄されます。ファイルが処理されると、FileLogger クラスの StringBuffer にログを追加し続け、処理の最後にファイルに書き込み、保存します。
問題 の説明 アプリケーションのインスタンスが 1 つしか実行されていない限り、このソリューションは正常に機能しているように見えました。アプリケーションを複数の amazon ec-2 インスタンスにデプロイするとすぐに、不完全なログがファイルに保存されているように見えます。さらに調べてみると、アプリケーションのすべてのインスタンスがログを保持するための独自の stringBuffer を持っており、アプリケーションに書き込みを行っているときに stringbuffers のコンテンツの 1 つしか読み取れないため、ログが不完全であることがわかりました。言うまでもなく、ログのパターンはランダムです。アプリケーションの N 個のインスタンスをデプロイすると、StringBuffer の N 個のインスタンスが存在することがわかりました。
ここに FileLogger クラスがあります
private static final Logger logger = LoggerFactory.getLogger(FileLogger.class);
//private static final Logger logger = LoggerFactory.getLogger(FileLogger.class);
private static final SimpleDateFormat logFileDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
private static final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
private static final String COLON = ":";
private static StringBuffer logAppender = null;
public synchronized void debug(Date date, String logMessage){
if(appConfig.getLogLevel().equalsIgnoreCase(LogLevel.DEBUG.name())){
this.log(LogLevel.DEBUG.name(), date, logMessage);
}
}
public synchronized void info(Date date, String logMessage){
if(appConfig.getLogLevel().equalsIgnoreCase(LogLevel.INFO.name()) ||
appConfig.getLogLevel().equalsIgnoreCase(LogLevel.DEBUG.name())){
this.log(LogLevel.INFO.name(), date, logMessage);
}
}
public synchronized void error(Date date, String logMessage){
if(appConfig.getLogLevel().equalsIgnoreCase(LogLevel.ERROR.name()) ||
appConfig.getLogLevel().equalsIgnoreCase(LogLevel.DEBUG.name())){
this.log(LogLevel.ERROR.name(), date, logMessage);
}
}
private synchronized void log(String logLevel, Date date, String logMessage){
logger.info("logAppender Hashcode: "+logAppender.hashCode());
if(!logLevel.equalsIgnoreCase(LogLevel.NONE.name())){
//StringBuffer logAppender = getLogAppender();
getLogAppender().append(getLogAppender().hashCode());
getLogAppender().append(COLON);
getLogAppender().append(getFormattedDate(date, logFileDateFormat));
getLogAppender().append(COLON);
getLogAppender().append(logLevel);
getLogAppender().append(COLON);
getLogAppender().append(logMessage);
getLogAppender().append(System.getProperty("line.separator"));
}
}
private synchronized StringBuffer getLogAppender(){
logger.info("Getting logAppender .."+logAppender);
if(logAppender == null){
logger.info("Log appender is null");
logAppender = new StringBuffer();
}
return logAppender;
}
質問 アプリケーションの複数のインスタンス間で StringBuffer (logAppender) のインスタンスが 1 つだけであることを確認するにはどうすればよいですか?ログを追加し続け、最後に読み取り、内容をファイルに書き込んでから保存できますか?