2011-08-05 18 views
9

起動時にXMLファイルを読み込み、XMLファイル内の各エントリのスレッドを開始するサービスアプリケーションがあります。各スレッドは、スレッド固有のログファイルに出力を記録するためにロガーを必要とするワーカークラスのインスタンスを作成します。私はlog4netの構成設定はXMLアペンダを使用するように設定されており、以下に示すように、ファイルがPatternStringとして指定されたApp.configファイルサービスに個々のスレッドごとに個別のログファイルに記録する

:のインスタンスごとにスレッドロック方法において

<appender name="XmlAppender" type="log4net.Appender.FileAppender"> 
    <file type="log4net.Util.PatternString" value="D:\Temp\Logs\%property{LogName}.log" /> 
    <immediateFlush value="true"/> 
    <appendToFile value="true" /> 
    <layout type="log4net.Layout.SimpleLayout" /> 
</appender> 

ワーカークラスを作成しました。log4net.LogManager.GetLogger("MyLogger")メソッドを使用してロガーを取得し、ThreadContext.Properties["LogName"] = "Log name prefix"を使用して現在のスレッドPatternStrings LogNameプロパティを設定しました。

すべてのファイルが作成されますが、ロガーが呼び出されると、一見無作為なファイルにすべてのメッセージが記録されます。

私は、しばらくの間、私が間違っていることに解決策や何らかの答えを見つけようとしたが、私は運がなかった。

これはなぜ起こっているのですか?

答えて

12

私は問題を解決したと思います。手順は次のとおりです。

  • 各スレッドでLoggerRepositoryという名前の個人を作成します。
  • ログファイル名のThreadContextsプロパティを設定します。
  • XmlConfiguratiorを使用してリポジトリを構成します。
  • LogManagerを使用して、そのスレッドの名前付きLoggerRepositoryを使用して(XML構成ファイル内の)指定されたロガーを取得します。

代わりに、そのスレッドのそれぞれのファイルを指す新しい構成済みのロガーを取得します。

XML構成は、それがもともとと完全性のためにここに示されたものと同じである。

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections>  
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> 
    </configSections> 
    <log4net> 
    <logger name="ProductionLogger"> 
     <appender-ref ref="XmlAppender"/>  
     <level value="ALL"/> 
    </logger> 
    <appender name="XmlAppender" type="log4net.Appender.FileAppender"> 
     <file type="log4net.Util.PatternString" value="D:\Temp\Logs\%property{LogName}.log" /> 
     <immediateFlush value="true"/> 
     <appendToFile value="true" /> 
     <layout type="log4net.Layout.SimpleLayout" /> 
    </appender> 
    </log4net> 
</configuration> 

ロガーを作成するためのコードは以下です。このコードが実行されるたびに、それ自身のスレッドで実行されます。

ILoggerRepository loggerRepository = LogManager.CreateRepository(logFileName + "Repository"); 
ThreadContext.Properties["LogName"] = logFileName; 
log4net.Config.XmlConfigurator.Configure(loggerRepository); 
ILog logger = LogManager.GetLogger(logFileName + "Repository", "ProductionLogger"); 

これはこれまで問題なく動作していたようです。私は今このソリューションで前進していきますが、他に何かを見つけたらこの記事を更新します。

+1

大きな感謝!私はスレッド化と異なるファイルにログインするのと同じ問題を抱えていました。私は多くの記事とソリューションを見ていたが、この1つだけが私を癒した。 –

+0

ありがとうございました...このアプローチは私の問題を解決しました... – Emerson

4

アダムの答えは私のためにはうまくいきましたが、追加したいものが1つあります。アプリケーションでlogFileNameが再利用される可能性がある場合は、リポジトリが存在しないことを確認する必要があります。

string repoName = String.Format("{0}Repository", logFileName); 

// Check for existing repository 
ILoggerRepository[] allRepos = LogManager.GetAllRepositories(); 
ILoggerRepository repo = allRepos.Where(x => x.Name == repoName).FirstOrDefault(); 

// If repository does not exist, create one, set the logfile name, and configure it 
if (repo == null) 
{ 
    repo = LogManager.CreateRepository(repoName); 
    ThreadContext.Properties[KEY_LOG_FILE] = logFileName; 
    log4net.Config.XmlConfigurator.Configure(repo); 
} 

// Set logger 
ILog logger = LogManager.GetLogger(repoName, logName); 
+1

どこでも、このようにFirstOrDefaultを直接呼び出すことができます: 'allRepos.FirstOrDefault(x => x.Name == repoName);' –

関連する問題