2010-11-16 11 views
8

Proprio di recente entrato in sperimentazione con NLog, e mi viene in mente che mi piacerebbe essere in grado di aggiungere informazioni di intestazione alla parte superiore di un file di log come ad esempio:NLog - Generazione di intestazione di sezione di un file di log

eseguibile nome versione file Data di rilascio di Windows ID utente ecc ...

Dopo alcune ricerche sono stato in grado di trovare qualsiasi cosa nelle attuali forum di documentazione o di codice in linea che indica questo tipo di funzionalità. È possibile? Ho sempre incluso in precedenza questo tipo di informazioni nei file di registro e l'ho trovato utile in numerose occasioni in passato, quando reperivo informazioni su problemi di produzione presso i siti dei clienti. Certamente, questa funzionalità è stata creata su misura per le soluzioni e non basata su nessuno degli attuali framework di registrazione .NET.

risposta

4

Non sono a conoscenza di un modo per farlo molto facilmente. Detto questo, tutti gli esempi che date sono disponibili (o abbastanza facilmente disponibili con qualche codice personalizzato) da aggiungere a ciascun messaggio di registro. Cioè, ogni messaggio registrato può essere taggato con il nome dell'eseguibile, la versione del file, la data di rilascio, l'id utente di Windows, ecc. Tramite Layout e LayoutRenderers.

Questo ovviamente non equivale alla creazione di un'intestazione nella parte superiore del file di registro, quindi potrebbe non essere utile.

D'altra parte, è possibile utilizzare una tecnica menzionata nella risposta di Pat in this post per associare più renderizzatori di layout con lo stesso obiettivo. È possibile definire un layout che contenga i campi desiderati nell'intestazione e impostare il filtro in FilteringWrapper per applicare solo quel layout per il primo messaggio di una sessione (oppure si potrebbe utilizzare qualche altra tecnica che viene aggiunta al file di output solo una volta).

Utilizzando il file NLog.config, ecco un modo per ottenere ciò che si desidera. Nota che non ho provato questo, quindi non so se questo file di configurazione è valido o, se lo è, se genererà i risultati che vuoi.

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

Nel codice, la logica di avvio potrebbe essere simile a questo:

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

L'idea è che si dovrebbe mettere la versione del file, data di uscita, ecc nella GDC all'avvio del programma. Registra un messaggio con il registratore "HeaderLogger". Questo messaggio verrebbe scritto nel file di registro utilizzando "HeaderLayout" poiché "HeaderLogger" è associato alla destinazione "fileHeader" associata a "HeaderLayout". I campi definiti nel layout dell'intestazione sono scritti nel file di registro. I messaggi di log successivi, dato che non useranno il "HeaderLogger", useranno il layout "root" (*). Andranno allo stesso file poiché entrambi gli obiettivi "file" e "fileHeader" alla fine puntano allo stesso nome file.

Prima di iniziare a digitare questa risposta non ero sicuro di quanto facilmente si possa ottenere l'aggiunta di un'intestazione al file di registro. Dopo aver digitato questo, penso che potrebbe essere davvero piuttosto semplice!

Buona fortuna!

[EDIT] Qualcosa di simile potrebbe funzionare per cambiare il layout in base al livello. Nella prima sezione ho definito diverse variabili, ognuna delle quali definisce un layout. Nella prossima sezione ho definito diversi target ognuno dei quali usa lo stesso file, ma viene filtrato per consentire solo la scrittura di messaggi di un livello specifico. Nella sezione finale definisco una singola regola che invierà tutti i messaggi (da cui il nome del logger "*") a tutti i target.Poiché ogni target viene filtrato per livello, il target "trace" scriverà solo i messaggi "trace" ecc. Quindi, i messaggi "trace" verranno scritti usando il layout "trace", i messaggi "debug" verranno scritti usando il "debug" layout, ecc. Dal momento che tutti i target scrivono sullo stesso file, tutti i messaggi finiranno nello stesso file. Non ho provato questo, ma penso che probabilmente funzionerà.

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

(Nota che ho incluso solo 3 livelli qui).

Dopo aver mostrato come (se funziona, comunque) per applicare un layout diverso in base al livello, sembra che si tratti di un caso di utilizzo insolito. Non sto dicendo che sia una buona idea o una cattiva idea, ma non posso dire di averlo visto davvero molto. A seconda del modo in cui vuoi che il tuo output finale appaia, quello che ti ho mostrato potrebbe essere o non essere il modo migliore per ottenerlo. Forse potresti pubblicare alcuni esempi di come vuoi che il tuo output appaia.

Si potrebbe anche considerare di accettare la mia risposta originale e quindi di fare una nuova domanda sulla variazione del layout di output per livello in modo da poter concentrare la discussione in quella domanda sul problema del livello/layout. Spetta a te se ciò ti sembra utile o meno.

Questo funziona:

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

ho creato un layout per ciascun livello di registrazione, l'aggiunta di una stringa letterale all'inizio che descrive il livello del messaggio (questo è quello di dimostrare che un formato diverso viene utilizzato per ogni livello). Ogni Layout è associato a un FilteringWrapper che filtra in base al livello del messaggio e indirizza i messaggi che passano al filtro da registrare nel file di output. Ogni FilteringWrapper include lo stesso file di output, quindi tutti i messaggi di log verranno registrati nello stesso file.

Ecco una sezione di codice che ho usato per la prova:

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

E qui è ciò che l'output appare come:

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 

A quanto pare il problema nel mio precedente informazioni di configurazione era lo spazio tra i valori "writeTo". Immagino che NLog sia sensibile a questo. Avevo qualcosa come "writeTo=blah1, blah2, blah3". Quando ho cambiato quello a "writeTo=blah1,blah2,blah3" l'errore è andato via. Buona fortuna!

+0

Molti grazie wageoghe, che ha funzionato bene. Tuttavia, come sempre, essendo riuscito a far funzionare le funzionalità di base, ora ho bisogno di mettere a punto le cose :-) Fondamentalmente ho bisogno di avere layout diversi per i diversi livelli di registrazione, come si fa a condizionare il layout sul livello selezionato? –

+0

Cosa vuoi che siano i diversi layout? Vuoi avere campi diversi nei layout per i diversi livelli di registrazione? Ad ogni modo, potresti probabilmente usare la tecnica mostrata da Pat nel link qui sopra. Definisce un target di file per i suoi messaggi di registrazione "normali" e definisce un target "filter wrapper" per utilizzare un layout diverso per i messaggi che contengono un'eccezione. Proverò ad aggiungere un esempio di qualcosa che potrebbe aiutarti. – wageoghe

+0

Utilizzando la tecnica suggerita, per il seguente: Ricevo il seguente errore nel file di configurazione: 'L'attributo' writeTo 'non è valido ....' per –

9

È capitato di inciampare su questo mentre si guardava la replica di un'intestazione/piè di pagina in un log uno dei miei colleghi creati con log4net. L'ho trovato da un progetto open source e l'ho adattato come un esempio interno. Penso che dovrebbe essere semplice da modificare per le tue esigenze.

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

mi dà in uscita che assomiglia a questo:

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

Non ho idea del perché questo sembra essere senza documenti. L'unico riferimento che ho trovato è stato qui: https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter

-Jody

+0

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

+0

risolto il collegamento. Grazie. – JKoplo

1

È possibile generare una sezione di intestazione/piè di pagina per "istanza" (vale a direla prima volta l'applicazione e l'ultima volta che l'applicazione scrive un dato file) utilizzando layout come indicated by previous answer:

Più particolare:

+0

Forse possiamo unire la tua risposta a quella precedente, poiché stai solo aggiungendo nuovi collegamenti. Potrebbe anche indicare https://github.com/NLog/NLog/issues/2119 dove qualcuno chiede di avere l'intestazione e il piè di pagina ogni volta che l'app si avvia e si arresta. – user276648

Problemi correlati