2013-02-19 17 views
14

Zastanawiam się nad same issue as HENRI COOK did. Zostało to zgłoszone jako bug on Apache Jira, o ile możemy to stwierdzić na podstawie krótkiego opisu.Log4Net RollingFileAppender nie przepłukuje bufora IO z logiem o niskiej głośności

Mój problem polega w istocie na tym, że zdarzenia są rejestrowane tylko wtedy, gdy aplikacja jest wyłączona (nawet tygodnie po wydarzeniu). Dzieje się tak, gdy wielkość rejestracji jest bardzo niska. Widzę to na Windows Server 2008 R2. Zapobiega to przechwytywaniu i reagowaniu na błędy produkcyjne.

Teraz aplikant nie jest buforujący. Domyślnie wywołuje również Flush() w strumieniu bazowym za każdym razem, gdy dołączana jest wiadomość.

Moje pytanie brzmi: DLACZEGO nie jest ono spłukiwane? I czy istnieje jakieś rozwiązanie oprócz programatically flushing all appenders? Czy rozważasz możliwość obejścia tego problemu w postaci pulsing appender?

config appender:

<appender name="RollingErrorFileAppender" type="log4net.Appender.RollingFileAppender"> 
    <param name="File" value="D:\LogFiles\zzzz\xxxxxx__ERROR" /> 
    <param name="AppendToFile" value="true" /> 
    <param name="DatePattern" value="_yyyyMMddHH&quot;.log&quot;" /> 
    <param name="RollingStyle" value="Date" /> 
    <param name="StaticLogFileName" value="false" /> 
    <filter type="log4net.Filter.LevelRangeFilter"> 
    <param name="LevelMin" value="ERROR" /> 
    <param name="LevelMax" value="FATAL" /> 
    </filter> 
    <layout type="log4net.Layout.PatternLayout"> 
    <param name="ConversionPattern" value="%utcdate{yyyy-MM-dd HH:mm:ss.fff},[%thread],%level,%logger,%m%n"/> 
    </layout> 
</appender> 

UPDATE 2013-06-19

I nie były w stanie odtworzyć zachowanie z dowolnego kodu. Bez względu na to, jak źle próbuję, dane są zawsze zapisywane na dysku natychmiast. Jednakże, dokonano ważnej obserwacji: Jeśli pierwszy zapis do pliku jest większy niż 1 KB, zmodyfikowany czas nigdy nie jest aktualizowany przy kolejnych zapisach. Będzie on aktualizowany tylko wtedy, gdy plik zostanie zamknięty wraz z czasem zamknięcia. Jeśli z drugiej strony pierwszy zapis to krótki jednolinijkowy, każdy kolejny zapis zaktualizuje zmodyfikowany czas. Takie zachowanie jest spójne między protokołem log4net a ręczną operacją IO, między 32-bitowym WinXP a 64-bitowym W2k8R2, między .NET 2.0, 3.5 i .NET 4.0. To jeszcze nie rozwiązuje problemu, ale przynajmniej mogę teraz zrozumieć dziwny wzór czasu modyfikacji.

Dzięki Rob

+0

możesz pisać config dla appender używasz? –

+0

@AdamS, konfiguracja dodana, dziękuję – Rbjz

+0

A żeby wyjaśnić, czy dzienniki nie wyświetlają się co godzinę, gdy w tym okresie wystąpił co najmniej jeden poziom błędu lub wyższe zdarzenie rejestrowania?Przetestowałem z twoim aplikantem i zobaczyłem logi równo z rolkami. –

Odpowiedz

25

Skoro jesteś tylko o poziomie błędu lub gorzej zdarzeń dziennika, a ruch jest na szczęście rzadko, chciałbym zasugerować konfiguracji appender natychmiast spłukać.

<param name="ImmediateFlush" value="true" /> 

To pozwala uniknąć konieczności programowo przemyj appender na każde zdarzenie dziennika (co zresztą nie pracował z nim dźwięk). Teraz, jeśli chcesz otworzyć aplikację do większej liczby poziomów logowania, natychmiastowe spłukanie wszystkich zdarzeń może spowodować większe problemy z wydajnością.

EDIT

Dodałem plik konfiguracyjny i prosty program główny użyłem do testów. Korzystając z poniższych, widzę zdarzenia dziennika natychmiast przepłukane. W związku z twoim komentarzem, mogę również usunąć linię ImmediateFlush z xml i zobaczyć domyślną wartość wartości true do płukania. Zachowałem wiersz w moim przykładzie, aby wyraźnie określić pożądane zachowanie.

Podstawowe głównym prog:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ILog log = LogManager.GetLogger(typeof(Program)); 
     XmlConfigurator.Configure(new FileInfo(@"C:\temp\logTest.config")); 

     string msg; 
     while ((msg = Console.ReadLine()) != "Done") 
     { 
      log.Error(msg); 
     } 

     LogManager.Shutdown(); 
    } 
} 

logTest.config odwołuje głównego prog:

<log4net> 
    <appender name="RollingErrorFileAppender" type="log4net.Appender.RollingFileAppender"> 
     <param name="File" value="C:\temp\log" /> 
     <param name="AppendToFile" value="true" /> 
     <param name="DatePattern" value="_yyyyMMddHH&quot;.log&quot;" /> 
     <param name="RollingStyle" value="Date" /> 
     <param name="StaticLogFileName" value="false" /> 
     <param name="ImmediateFlush" value="true" /> 
     <filter type="log4net.Filter.LevelRangeFilter"> 
      <param name="LevelMin" value="ERROR" /> 
      <param name="LevelMax" value="FATAL" /> 
     </filter> 
     <layout type="log4net.Layout.PatternLayout"> 
      <param name="ConversionPattern" value="%utcdate{yyyy-MM-dd HH:mm:ss.fff},[%thread],%level,%logger,%m%n"/> 
     </layout> 
    </appender> 
    <root> 
     <level value="INFO" /> 
     <appender-ref ref="RollingErrorFileAppender" /> 
    </root> 
</log4net> 
+1

Dzięki @AdamS, chociaż śmiem się nie zgodzić. Jeśli przejrzysz kod 'private bool m_immediateFlush = true;' i 'override protected void Append (LoggingEvent loggingEvent)' w [v1.2.10 TextWriterAppender] (http://svn.apache.org/viewvc/logging/log4net/ tags/log4net-1.2.10/src/Appender/TextWriterAppender.cs? view = markup), zgodzisz się ze mną, że ImmediateFlush jest domyślnie prawdziwe, więc appender faktycznie wywołuje Flush() na każdym Append(), tak jak ja powiedział w Q. – Rbjz

+1

Zmieniono moją odpowiedź za pomocą programu testowego, którego użyłem. Dzięki temu widzę wydarzenia natychmiast spłukane. Czy nie widzisz tego samego zachowania? –

+0

Dzięki AdamS, to świetny pomysł. Spróbuję jutro z nadzieją. – Rbjz