2011-08-05 11 views
9

Mam aplikację usługową, która po uruchomieniu odczytuje plik XML i rozpoczyna wątek dla każdego wpisu w pliku XML. Każdy wątek tworzy instancję klasy robotniczej, która wymaga rejestratora do rejestrowania dowolnego wyniku w pliku dziennika wątku.Logowanie do pojedynczego pliku dziennika dla każdego wątku

w usługach app.config mam ustawienia konfiguracji log4net określone użycie appender XML i plik jest określony jako PatternString jak pokazano poniżej:

<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> 

w wątku zablokowane metody dla każdej instancji utworzono klasę robotniczą Otrzymuję program rejestrujący przy użyciu metody log4net.LogManager.GetLogger("MyLogger"), a następnie ustawiam bieżącą wątek PatternStrings LogName z wykorzystaniem właściwości ThreadContext.Properties["LogName"] = "Log name prefix".

Wszystkie pliki są tworzone, ale po wywołaniu rejestratora loguje się tylko do jednego pozornie losowego pliku.

Szukałem od dłuższego czasu, próbując znaleźć rozwiązanie lub odpowiedzi na to, co robię źle, ale nie miałem szczęścia.

Czy ktoś ma pojęcie, dlaczego tak się dzieje?

Odpowiedz

12

Myślę, że udało mi się rozwiązać problem. Poniższe kroki:

  • Utwórz osobę o nazwie LoggerRepository na każdym wątku.
  • Ustaw właściwość ThreadContexts dla nazwy pliku dziennika.
  • Skorzystaj z XmlConfiguratior, aby skonfigurować repozytorium.
  • Użyj LogManager, aby uzyskać nazwany program rejestrujący (w pliku konfiguracyjnym XML), używając nazwy LoggerRepository dla tego wątku.

W zamian otrzymuję nowy skonfigurowany program rejestrujący wskazujący odpowiedni plik dla tego wątku.

Konfiguracja XML jest takie samo jak to było pierwotnie i pokazane tutaj dla kompletności:

<?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> 

Kod do tworzenia rejestratorów jest poniżej. Za każdym razem, gdy ten kod jest uruchamiany, uruchamiany jest we własnym wątku.

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

Wydaje się, że działa bez żadnych problemów. Na razie będę się rozwijał z tym rozwiązaniem, ale zaktualizuję ten post, jeśli dowiem się czegoś jeszcze.

+1

Wielkie dzięki! Miałem ten sam problem z wątkami i logowaniem się do różnych plików. Przejrzałem wiele postów i rozwiązań, ale tylko ten jeden mnie ugodził. –

+0

Dziękuję bardzo ... To podejście rozwiązało mój problem ... – Emerson

4

Odpowiedź Adama była dla mnie bardzo dobra, ale jest jeszcze jedna, którą chciałbym dodać. Jeśli istnieje możliwość ponownego użycia obiektu logFileName w aplikacji, konieczne będzie sprawdzenie, czy repozytorium jeszcze nie istnieje.

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

Możesz bezpośrednio wywołać FirstOrDefault, bez Where, tak: 'allRepos.FirstOrDefault (x => x.Name == repoName);' –

Powiązane problemy