2010-11-16 5 views
8

Erst vor kurzem kam in mit NLog experimentiert, und es fällt mir ein, dass ich möchte in der Lage sein, Header-Informationen an die Spitze eine Protokolldatei wie hinzuzufügen:Nlog - Generieren von Header-Abschnitt für eine Protokolldatei

Executable Name Dateiversion Erscheinungsdatum Windows User ID etc ...

nach einiger Suche wir nicht in der Lage gewesen, etwas in den bestehenden online-Dokumentation oder Code-Foren zu finden, die diese Art von Funktionalität angibt. Ist das möglich? Ich habe diese Art von Informationen bisher immer in Protokolldateien aufgenommen und fand sie in der Vergangenheit häufig nützlich, wenn Informationen zu Produktionsproblemen beim Kunden abgerufen wurden. Zugegeben, diese Funktionalität wurde speziell für die Lösungen entwickelt und basiert nicht auf den aktuellen .NET-Protokoll-Frameworks.

Antwort

4

Ich bin mir nicht bewusst, eine Möglichkeit, das sehr einfach zu tun. Allerdings sind alle Beispiele, die Sie angeben, verfügbar (oder ziemlich einfach verfügbar mit benutzerdefiniertem Code), um zu jeder Protokollnachricht hinzugefügt zu werden. Das heißt, jede protokollierte Nachricht kann über den Layout- und LayoutRenderer mit ausführbarem Namen, Dateiversion, Veröffentlichungsdatum, Windows-Benutzer-ID usw. versehen werden.

Dies ist natürlich nicht das gleiche wie nur eine Kopfzeile am Anfang der Protokolldatei zu erstellen, so dass es für Sie möglicherweise nicht nützlich ist.

Auf der anderen Seite könnten Sie eine Technik verwenden, die in Pats Antwort in this post erwähnt wird, um mehrere Layout-Renderer mit demselben Ziel zu verknüpfen. Sie könnten ein Layout definieren, das die gewünschten Felder in Ihrem Header enthält, und den Filter im FilteringWrapper so einstellen, dass er nur das Layout für die erste Nachricht einer Sitzung anwendet (oder Sie verwenden eine andere Technik, die der Ausgabedatei hinzugefügt wird) nur einmal).

Mit seiner NLog.config-Datei können Sie hier erreichen, was Sie wollen. Beachten Sie, dass ich dies nicht ausprobiert habe. Daher weiß ich nicht, ob diese Konfigurationsdatei gültig ist oder ob sie die gewünschten Ergebnisse generiert.

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

In Ihrem Code, könnte Ihr Startlogik wie folgt aussehen:

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

Die Idee dabei ist, dass Sie die Dateiversion, Release-Datum, usw. in der GDC setzen würde, wenn das Programm startet. Protokollieren Sie eine Nachricht mit dem Logger "HeaderLogger". Diese Nachricht wird mit "HeaderLayout" in die Protokolldatei geschrieben, da "HeaderLogger" dem Ziel "fileHeader" zugeordnet ist, das mit "HeaderLayout" verknüpft ist. Die im Kopfzeilenlayout definierten Felder werden in die Protokolldatei geschrieben. Untersequenzprotokollnachrichten verwenden, da sie nicht den "HeaderLogger" verwenden, das "root" (*) Layout. Sie werden zu derselben Datei wechseln, da sowohl die Ziele "file" als auch "fileHeader" letztendlich auf denselben Dateinamen verweisen.

Bevor ich anfing, diese Antwort einzugeben, war ich mir nicht sicher, wie einfach Sie einen Header zu Ihrer Protokolldatei hinzufügen konnten. Nachdem ich dies eingegeben habe, denke ich, dass es eigentlich ziemlich einfach sein könnte!

Viel Glück!

[EDIT] So etwas funktioniert möglicherweise, um das Layout basierend auf dem Level zu ändern. Im ersten Abschnitt habe ich mehrere Variablen definiert, von denen jede ein Layout definiert. Im nächsten Abschnitt habe ich mehrere Ziele definiert, von denen jedes die gleiche Datei verwendet, aber gefiltert wird, um nur Nachrichten einer bestimmten Ebene zu schreiben. Im letzten Abschnitt definiere ich eine einzelne Regel, die alle Nachrichten (daher den "*" Loggernamen) an alle Ziele sendet.Da jedes Ziel nach Level gefiltert wird, schreibt das "Trace" -Ziel nur "Trace" -Nachrichten usw. So werden "Trace" -Nachrichten unter Verwendung des "Trace" -Layouts geschrieben, "Debug" -Nachrichten werden unter Verwendung des "Debug" geschrieben. Layout usw. Da alle Ziele letztendlich in dieselbe Datei schreiben, landen alle Nachrichten in derselben Datei. Ich habe das nicht versucht, aber ich denke, dass es wahrscheinlich funktionieren wird.

(Beachten Sie, dass ich hier nur 3 Ebenen enthalten habe).

Nachdem gezeigt wurde, wie (wenn es überhaupt funktioniert) ein anderes Layout auf der Ebene anzuwenden, scheint dies eine Art ungewöhnlicher Anwendungsfall zu sein. Ich sage nicht, dass es eine gute Idee oder eine schlechte Idee ist, aber ich kann nicht sagen, dass ich das wirklich sehr gesehen habe. Abhängig davon, wie genau Ihre endgültige Ausgabe aussehen soll, kann das, was ich Ihnen gezeigt habe, der beste Weg sein, dies zu erreichen. Vielleicht könnten Sie einige Beispiele dafür veröffentlichen, wie Ihre Ausgabe aussehen soll.

Sie könnten auch in Erwägung ziehen, meine ursprüngliche Antwort zu akzeptieren und dann eine neue Frage zum Ändern des Ausgabe-Layouts pro Ebene zu stellen, damit wir die Diskussion in dieser Frage auf das Ebenen-/Layout-Problem konzentrieren können. Es liegt an Ihnen, ob Ihnen das nützlich erscheint oder nicht.

Dies funktioniert:

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

Ich habe ein Layout für jede Protokollebene einrichten, eine Zeichenkette am Anfang hinzufügen, die das Niveau der Nachricht beschreibt (dies ist zu zeigen, dass ein anderes Format verwendet wird, für jedes Level). Jedem Layout ist ein FilteringWrapper zugeordnet, der auf der Ebene der Nachricht filtert und alle Nachrichten, die den Filter passieren, in der Ausgabedatei protokolliert. Jeder FilteringWrapper verpackt dieselbe Ausgabedatei, sodass alle Protokollmeldungen in derselben Datei protokolliert werden.

Hier ist ein Abschnitt des Codes, die ich für den Test verwendet:

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

Und hier ist es, was die Ausgabe wie folgt aussieht:

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 

Anscheinend ist das Problem in meiner früheren Konfigurationsinformation der Raum war zwischen den "writeTo" Werten. Ich denke, NLog ist dafür sensibel. Ich hatte etwas wie "writeTo=blah1, blah2, blah3". Als ich das zu "writeTo=blah1,blah2,blah3" änderte, ging der Fehler weg. Viel Glück!

+0

Viele danke lohnoghe, das hat ein Vergnügen gemacht. Aber wie immer ist es mir gelungen, nachdem ich die grundlegenden Funktionen funktionierte, die Feinabstimmung der Dinge vorzunehmen :-) Grundsätzlich muss ich verschiedene Layouts für die verschiedenen Logging-Ebenen haben. Wie macht man das Layout abhängig von der gewählten Ebene? –

+0

Wie sollen die verschiedenen Layouts aussehen? Möchten Sie unterschiedliche Felder in den Layouts für verschiedene Protokollierungsstufen haben? Auf jeden Fall könnten Sie wahrscheinlich die Technik verwenden, die Pat im obigen Link zeigt. Er definiert ein Dateiziel für seine "normalen" Protokollierungsnachrichten und definiert ein "Filter-Wrapper" -Ziel, um ein anderes Layout für Nachrichten zu verwenden, die eine Ausnahme enthalten. Ich werde versuchen, ein Beispiel für etwas hinzuzufügen, das Ihnen helfen könnte. – wageoghe

+0

Verwenden Sie die vorgeschlagene Technik für die folgenden: Ich erhalte den folgenden Fehler in der Konfigurationsdatei: 'Das' writeTo 'Attribut ist ungültig ....' für –

9

Zufälligerweise stolperte ich bei der Replizierung einer Kopf-/Fußzeile in einem Protokoll eines meiner Mitarbeiter, die mit log4net erstellt wurden. Ich habe das aus einem Open-Source-Projekt herausgefunden und es als internes Beispiel adaptiert. Ich denke, es sollte einfach sein, für Ihre Bedürfnisse zu ändern.

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

Es gibt mir Ausgabe, die wie folgt aussieht:

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

Ich habe keine Ahnung, warum dies nicht dokumentiert zu sein scheint. Der einzige Hinweis, den ich finden konnte, war hier: https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter

-Jody

+0

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

+0

Die Verknüpfung wurde korrigiert. Vielen Dank. – JKoplo

1

Sie können einen Header/Footer erzeugen pro "Instanz" (ddas erste Mal die App und das letzte Mal, wenn die App zu einem bestimmten Datei schreibt) Layouts als indicated by previous answer mit:

Mehr Detail:

+0

Vielleicht können wir Ihre Antwort mit der vorherigen zusammenführen, da Sie nur neue Links hinzufügen. Könnte auch auf https://github.com/NLog/NLog/issues/2119 verweisen, wo jemand bittet, die Kopf- und Fußzeile jedes Mal zu haben, wenn die App startet und stoppt. – user276648