2010-11-16 12 views
8

Niedawno dostał się eksperymentować z NLog, i wydaje mi się, że chciałbym, aby móc dodać informacje nagłówka na górę plik dziennika, takich jak:nlog - Generowanie Sekcja nagłówka do pliku dziennika

Executable wymienić wersję pliku data wydania Okna ID użytkownika etc ...

Po pewnym poszukiwań nie udało mi się znaleźć coś w istniejącej dokumentacji on-line kod lub forach co wskazuje tego typu funkcjonalności. czy to możliwe? Zawsze zawierałem tego rodzaju informacje w plikach dziennika i okazało się, że jest to przydatne w wielu przypadkach w przeszłości, gdy pozyskiwano informacje o problemach produkcyjnych na stronach klientów. Trzeba przyznać, że ta funkcjonalność została stworzona na zamówienie dla rozwiązań i nie opierała się na żadnym z obecnych frameworków rejestrowania .NET.

Odpowiedz

4

Nie jestem świadomy sposobu, aby to zrobić bardzo łatwo. Mimo to wszystkie podane przykłady są dostępne (lub dość łatwo dostępne z niestandardowym kodem) do dodania do każdej wiadomości dziennika. Oznacza to, że każda zalogowana wiadomość może być oznaczona za pomocą nazwy pliku, wersji pliku, daty wydania, identyfikatora użytkownika Windows itp. Za pośrednictwem układu Layout i LayoutRenderers.

Oczywiście nie jest to to samo, co tworzenie nagłówka u góry pliku dziennika, więc może Ci się to nie przydać.

Z drugiej strony można zastosować technikę wymienioną w odpowiedzi Pat in this post, aby powiązać wiele rendererów układu z tym samym obiektem docelowym. Możesz zdefiniować układ zawierający pola, które chcesz umieścić w swoim nagłówku i ustawić filtr w FilteringWrapper, aby zastosować ten układ tylko dla pierwszej wiadomości z sesji (lub możesz użyć innej techniki, która zostanie dodana do pliku wyjściowego tylko raz).

Korzystając z jego pliku NLog.config, można w prosty sposób osiągnąć to, co chcesz. Zauważ, że nie próbowałem tego, więc nie wiem, czy ten plik konfiguracyjny jest prawidłowy lub, jeśli tak jest, czy wygeneruje oczekiwane wyniki.

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.mono2.xsd" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     autoReload="true" 
     internalLogLevel="Warn" 
     internalLogFile="nlog log.log" 
     > 
    <variable name="HeaderLayout" value="${processname} ${gdc:item=version} ${gdc:item=releasedate} ${windows-identity}" /> 
    <variable name="NormalLayout" value="${longdate} ${logger} ${level} ${message} /> 

    <targets async="true"> 
     <target name="file" xsi:type="File" fileName="log.log" 
       layout="${NormalLayout}"> 
     </target> 

     <target name="fileHeader" xsi:type="File" fileName="log.log" 
       layout="${HeaderLayout}"> 
     </target>  
    </targets> 

    <rules> 
     <logger name="HeaderLogger" minlevel="Trace" writeTo="fileHeader" final="true" />   
     <logger name="*" minlevel="Trace" writeTo="file" /> 
    </rules> 

</nlog> 

W kodzie, logika startowy może wyglądać następująco:

public void Main() 
{ 
    AddHeaderToLogFile(); 
} 

public void AddHeaderToLogFile() 
{ 
    Logger headerlogger = LogManager.GetLogger("HeaderLogger"); 

    //Use GlobalDiagnosticContext in 2.0, GDC in pre-2.0 
    GlobalDiagnosticContext["releasedate"] = GetReleaseDate();  
    GlobalDiagnosticContext["version"] = GetFileVersion();  
    GlobalDiagnosticContext["someotherproperty"] = GetSomeOtherProperty(); 

    headerlogger.Info("message doesn't matter since it is not specified in the layout"); 

    //Log file should now have the header as defined by the HeaderLayout 

    //You could remove the global properties now if you are not going to log them in any 
    //more messages. 
} 

Chodzi o to, że będzie można umieścić wersję pliku, datę wydania, etc w GDC podczas uruchamiania programu. Zaloguj się do loggeru "HeaderLogger". Ta wiadomość zostanie zapisana w pliku dziennika przy użyciu "HeaderLayout", ponieważ "HeaderLogger" jest powiązany z celem "fileHeader", który jest powiązany z "HeaderLayout". Pola zdefiniowane w układzie nagłówka są zapisywane w pliku dziennika. Komunikaty o kolejnych odcinkach, ponieważ nie będą używać "HeaderLogger", będą używać układu "root" (*). Przejdą one do tego samego pliku, ponieważ oba cele "file" i "fileHeader" ostatecznie wskazują na tę samą nazwę pliku.

Zanim zacząłem pisać tę odpowiedź, nie byłem pewien, jak łatwo można było dodać nagłówek do pliku dziennika. Po wpisaniu tego, myślę, że może to być całkiem łatwe!

Powodzenia!

[EDIT] Coś w tym stylu może działać, aby zmienić układ na podstawie poziomu. W pierwszej sekcji zdefiniowałem kilka zmiennych, z których każda definiuje układ. W następnej sekcji zdefiniowałem kilka celów, z których każdy używa tego samego pliku, ale jest filtrowany, aby umożliwić tylko zapisywanie komunikatów określonego poziomu. W ostatniej sekcji definiuję pojedynczą regułę, która wyśle ​​wszystkie komunikaty (stąd nazwa "*" rejestratora) do wszystkich obiektów docelowych.Ponieważ każdy cel jest filtrowany według poziomu, cel "trace" zapisuje jedynie komunikaty "trace". Tak więc, komunikaty "trace" będą zapisywane za pomocą układu "trace", komunikaty "debugowania" będą zapisywane za pomocą "debugowania" układ, itp. Ponieważ wszystkie cele ostatecznie zapisują do tego samego pliku, wszystkie wiadomości trafią do tego samego pliku. Nie próbowałem tego, ale myślę, że prawdopodobnie to zadziała.

<variable name="TraceLayout" value="THIS IS A TRACE: ${longdate} ${level:upperCase=true} ${message}" /> 
<variable name="DebugLayout" value="THIS IS A DEBUG: ${longdate} ${level:upperCase=true} ${message}" /> 
<variable name="InfoLayout" value="THIS IS AN INFO: ${longdate} ${level:upperCase=true} ${message}" /> 


<targets async="true"> 
    <target name="fileAsTrace" xsi:type="FilteringWrapper" condition="level==LogLevel.Trace"> 
     <target xsi:type="File" fileName="log.log" layout="${TraceLayout}" /> 
    </target> 
    <target name="fileAsDebug" xsi:type="FilteringWrapper" condition="level==LogLevel.Debug"> 
     <target xsi:type="File" fileName="log.log" layout="${DebugLayout}" /> 
    </target> 
    <target name="fileAsInfo" xsi:type="FilteringWrapper" condition="level==LogLevel.Info"> 
     <target xsi:type="File" fileName="log.log" layout="${InfoLayout}" /> 
    </target> 
</targets> 

<rules> 
    <logger name="*" minlevel="Trace" writeTo="fileAsTrace, fileAsDebug, fileAsInfo" /> 
</rules> 

(Uwaga: uwzględniono tutaj tylko 3 poziomy).

Po pokazaniu, jak (jeśli to działa, w każdym razie) zastosować inny układ na podstawie poziomu, wydaje się, że jest to nietypowy przypadek użycia. Nie twierdzę, że jest to dobry pomysł lub zły pomysł, ale nie mogę powiedzieć, że naprawdę widziałem to bardzo dobrze. W zależności od tego, jak dokładnie chcesz wyglądać końcowy wydruk, to co pokazałem Ci może, ale nie musi być najlepszym sposobem, aby to osiągnąć. Może mógłbyś opublikować kilka przykładów tego, jak chcesz wyglądać twój wydruk.

Możesz również rozważyć zaakceptowanie mojej oryginalnej odpowiedzi, a następnie zadać nowe pytanie dotyczące zmiany układu wyjściowego na poziom, abyśmy mogli skoncentrować dyskusję w tym pytaniu na poziomie problemu dotyczącego poziomu/układu. To zależy od Ciebie, jeśli wydaje Ci się to przydatne, czy nie.

to działa:

<variable name="TraceLayout" value="This is a TRACE - ${longdate} | ${logger} | ${level} | ${message}"/> 
    <variable name="DebugLayout" value="This is a DEBUG - ${longdate} | ${logger} | ${level} | ${message}"/> 
    <variable name="InfoLayout" value="This is an INFO - ${longdate} | ${logger} | ${level} | ${message}"/> 
    <variable name="WarnLayout" value="This is a WARN - ${longdate} | ${logger} | ${level} | ${message}"/> 
    <variable name="ErrorLayout" value="This is an ERROR - ${longdate} | ${logger} | ${level} | ${message}"/> 
    <variable name="FatalLayout" value="This is a FATAL - ${longdate} | ${logger} | ${level} | ${message}"/> 
    <targets> 
    <target name="fileAsTrace" xsi:type="FilteringWrapper" condition="level==LogLevel.Trace"> 
     <target xsi:type="File" fileName="xxx.log" layout="${TraceLayout}" /> 
    </target> 
    <target name="fileAsDebug" xsi:type="FilteringWrapper" condition="level==LogLevel.Debug"> 
     <target xsi:type="File" fileName="xxx.log" layout="${DebugLayout}" /> 
    </target> 
    <target name="fileAsInfo" xsi:type="FilteringWrapper" condition="level==LogLevel.Info"> 
     <target xsi:type="File" fileName="xxx.log" layout="${InfoLayout}" /> 
    </target> 
    <target name="fileAsWarn" xsi:type="FilteringWrapper" condition="level==LogLevel.Warn"> 
     <target xsi:type="File" fileName="xxx.log" layout="${WarnLayout}" /> 
    </target> 
    <target name="fileAsError" xsi:type="FilteringWrapper" condition="level==LogLevel.Error"> 
     <target xsi:type="File" fileName="xxx.log" layout="${ErrorLayout}" /> 
    </target> 
    <target name="fileAsFatal" xsi:type="FilteringWrapper" condition="level==LogLevel.Fatal"> 
     <target xsi:type="File" fileName="xxx.log" layout="${FatalLayout}" /> 
    </target> 
    </targets> 


    <rules> 
     <logger name="*" minlevel="Trace" writeTo="fileAsTrace,fileAsDebug,fileAsInfo,fileAsWarn,fileAsError,fileAsFatal" /> 
     <logger name="*" minlevel="Info" writeTo="dbg" /> 
    </rules> 

I utworzyły jeden układ dla każdego poziomu logowania, dodając ciągiem znaków na początku, który opisuje poziom wiadomości (jest to, aby pokazać, że inny format jest używany dla każdego poziomu). Każdy układ jest powiązany z filtrem FilteringWrapper, który filtruje na podstawie poziomu komunikatu i kieruje wszystkie komunikaty, które przekazują filtr w celu zalogowania do pliku wyjściowego. Każdy FilteringWrapper zawija ten sam plik wyjściowy, więc wszystkie logi będą logowane do tego samego pliku.

Oto fragment kodu, który służy do testowania:

logger.Trace("Trace msg"); 
    logger.Debug("Debug msg"); 
    logger.Info("Info msg"); 
    logger.Warn("Warn msg"); 
    logger.Error("Error msg"); 
    logger.Fatal("Fatal msg"); 

A oto co wyjście wygląda następująco:

This is a TRACE - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Trace | Trace msg 
This is a DEBUG - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Debug | Debug msg 
This is an INFO - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Info | Info msg 
This is a WARN - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Warn | Warn msg 
This is an ERROR - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Error | Error msg 
This is a FATAL - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Fatal | Fatal msg 

Widocznie problem w moim wcześniejszym informacji config była przestrzeń między wartościami "writeTo". Domyślam się, że NLog jest na to wrażliwy. Miałem coś takiego, jak "writeTo=blah1, blah2, blah3". Po zmianie tego na "writeTo=blah1,blah2,blah3" błąd zniknął. Powodzenia!

+0

Wiele dziękuję wageoghe, który sprawił przyjemność. Jednak jak zwykle, po udanym uruchomieniu podstawowej funkcjonalności muszę teraz dokładnie dostroić :-) Zasadniczo potrzebuję różnych układów dla różnych poziomów rejestrowania, w jaki sposób uzależniasz układ od wybranego poziomu? –

+0

Co chcesz, aby wyglądały różne układy? Czy chcesz mieć różne pola w układach dla różnych poziomów rejestrowania? W każdym razie prawdopodobnie możesz użyć techniki, którą Pat pokazuje w powyższym linku. Definiuje docelowy plik dla swoich "normalnych" komunikatów rejestrowania i definiuje cel "opakowania filtru", aby użyć innego układu dla wiadomości zawierających wyjątek. Postaram się dodać przykład czegoś, co może ci pomóc. – wageoghe

+0

Przy użyciu sugerowanej techniki, dla następujących: Otrzymuję następujący błąd w pliku konfiguracyjnym: "Atrybut" writeTo "jest nieprawidłowy ...." dla –

9

Po prostu zdarzyło się, że natknąłem się na to, patrząc na replikację nagłówka/stopki w dzienniku jednego z moich współpracowników utworzonych za pomocą log4net. Znalazłem to z jakiegoś projektu open source i zaadaptowałem go jako wewnętrzny przykład. Myślę, że powinno to być proste do modyfikacji dla twoich potrzeb.

<target name="logfile2" xsi:type="File" fileName="Logs\NLogDemo2.txt"> 
    <layout xsi:type="LayoutWithHeaderAndFooter"> 
    <header xsi:type="SimpleLayout" text="----------NLog Demo Starting---------&#xD;&#xA;"/> 
    <layout xsi:type="SimpleLayout" text="${longdate}|${level:uppercase=true}|${logger}|${message}" /> 
    <footer xsi:type="SimpleLayout" text="----------NLog Demo Ending-----------&#xD;&#xA;"/> 
    </layout> 
</target> 

Daje mi wyjście, które wygląda tak:

----------NLog Demo Starting--------- 

2013-03-01 16:40:19.5404|INFO|Project.Form1|Sample informational message 
2013-03-01 16:40:19.5714|WARN|Project.Form1|Sample warning message 
2013-03-01 16:40:19.5714|ERROR|Project.Form1|Sample error message 
2013-03-01 16:40:19.5714|FATAL|Project.Form1|Sample fatal error message 
----------NLog Demo Ending----------- 

nie mam pojęcia, dlaczego to wydaje się być udokumentowany. Jedyne odniesienie mogę znaleźć tutaj: https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter

-Jody

+0

? https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter – drzaus

+0

Naprawiono link. Dzięki. – JKoplo

1

Można wygenerować sekcję nagłówka/stopki za „przykład” (tjPo raz pierwszy aplikacja i ostatni raz aplikacja zapisuje na danym pliku) przy użyciu układów jak indicated by previous answer:

Więcej szczegółów:

+0

Może możemy połączyć twoją odpowiedź z poprzednią, ponieważ właśnie dodajesz nowe linki. Może również wskazywać na https://github.com/NLog/NLog/issues/2119, gdzie ktoś prosi o nagłówek i stopkę przy każdym uruchomieniu i zatrzymaniu aplikacji. – user276648

Powiązane problemy