2010-11-16 19 views
8

Recientemente se metió en la experimentación con Nlog, y se me ocurre que me gustaría ser capaz de añadir información de cabecera a la parte superior de un archivo de registro, tales como:Nlog - Generación de la sección de encabezado de un archivo de registro

Ejecutable nombrar versión del archivo fecha de lanzamiento de Windows ID de usuario etc ...

Después de buscar información que he podido encontrar nada en los foros existentes de documentación o código en línea que indica este tipo de funcionalidad. es posible? Siempre he incluido previamente este tipo de información en archivos de registro, y la he encontrado útil en numerosas ocisiones en el pasado, cuando obtengo información sobre problemas de producción en los sitios de los clientes. Es cierto que esta funcionalidad fue creada a medida para las soluciones y no se basa en ninguno de los marcos de registro de .NET actuales.

Respuesta

4

No conozco una manera de hacerlo fácilmente. Habiendo dicho eso, todos los ejemplos que das están disponibles (o bastante bastante fácilmente disponibles con algún código personalizado) para ser agregados a cada mensaje de registro. Es decir, cada mensaje registrado se puede etiquetar con el nombre del archivo ejecutable, la versión del archivo, la fecha de publicación, el ID de usuario de Windows, etc. a través de los Elementos de diseño y Disposición.

Esto obviamente no es lo mismo que crear un encabezado en la parte superior del archivo de registro, por lo que podría no serle útil.

Por otro lado, puede utilizar una técnica mencionada en la respuesta de Pat in this post para asociar múltiples representadores de diseño con el mismo destino. Puede definir un diseño que contenga los campos que desee en su encabezado y establecer el filtro en FilteringWrapper para aplicar solo ese diseño para el primer mensaje de una sesión (o puede usar alguna otra técnica que se agregue al archivo de salida) sólo una vez).

Utilizando su archivo NLog.config, aquí hay una manera de lograr lo que desea. Tenga en cuenta que no he probado esto, por lo que no sé si este archivo de configuración es válido o, si lo es, si generará los resultados que desea.

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

En su código, su lógica de arranque podría tener este aspecto:

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

La idea aquí es que usted pondría la versión de archivo, fecha de lanzamiento, etc en la GDC cuando el programa se inicia. Registre un mensaje con el registrador "HeaderLogger". Este mensaje se escribiría en el archivo de registro usando el "HeaderLayout" ya que el "HeaderLogger" está asociado con el objetivo "fileHeader" que está asociado con el "HeaderLayout". Los campos definidos en el diseño del encabezado se escriben en el archivo de registro. Los mensajes de registro subsiguientes, dado que no usarán el "HeaderLogger", usarán el diseño "raíz" (*). Irán al mismo archivo, ya que los destinos "file" y "fileHeader" apuntan al mismo nombre de archivo.

Antes de comenzar a escribir esta respuesta, no estaba seguro de cuán fácilmente podría lograr agregar un encabezado a su archivo de registro. ¡Después de haber tipeado esto, creo que en realidad podría ser bastante fácil!

¡Buena suerte!

[EDITAR] Algo como esto podría funcionar para cambiar el diseño según el nivel. En la primera sección, he definido varias variables, cada una de las cuales define un diseño. En la siguiente sección he definido varios objetivos, cada uno de los cuales usa el mismo archivo, pero se filtra para permitir que solo se escriban mensajes de un nivel específico. En la sección final, defino una regla única que enviará todos los mensajes (de ahí el nombre del registrador "*") a todos los objetivos.Dado que cada objetivo se filtra por nivel, el objetivo de "rastreo" solo escribirá mensajes de "seguimiento", etc. Por lo tanto, los mensajes de "rastreo" se escribirán utilizando el diseño de "seguimiento", los mensajes de "depuración" se escribirán utilizando la "depuración" diseño, etc. Dado que todos los destinos finalmente escriben en el mismo archivo, todos los mensajes terminarán en el mismo archivo. No lo he intentado, pero creo que probablemente funcione.

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

(Tenga en cuenta que solo he incluido 3 niveles aquí).

Después de haber demostrado cómo (si funciona, de todos modos) para aplicar un diseño diferente basado en el nivel, esto parece una especie de caso de uso inusual. No digo que sea una buena idea o una mala idea, pero no puedo decir que realmente haya visto esto hecho. Dependiendo de cómo quiera que se vea exactamente su resultado final, lo que le he mostrado puede ser o no la mejor manera de lograrlo. Tal vez podría publicar algunos ejemplos de cómo desea que se vea su resultado.

También podría considerar aceptar mi respuesta original y luego hacer una nueva pregunta sobre la variación del diseño de salida por nivel para que podamos centrar la discusión en esa pregunta en el problema de nivel/diseño. Depende de usted si eso le parece útil o no.

Esto funciona:

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

He creado un diseño para cada nivel de registro, la adición de una cadena literal al principio que describe el nivel del mensaje (esto es mostrar que se utiliza un formato diferente para cada nivel). Cada diseño está asociado a un FilteringWrapper que se filtra según el nivel del mensaje y dirige todos los mensajes que pasan el filtro para que se registren en el archivo de salida. Cada FilteringWrapper está envolviendo el mismo archivo de salida, por lo que todos los mensajes de registro se registrarán en el mismo archivo.

Aquí es una sección de código que he utilizado para la prueba:

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

Y aquí es lo que se ve la salida, como:

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 

Al parecer, el problema en mi información de configuración anterior fue el espacio entre los valores "writeTo". Supongo que NLog es sensible a esto. Tenía algo así como "writeTo=blah1, blah2, blah3". Cuando lo cambié a "writeTo=blah1,blah2,blah3", el error desapareció. ¡Buena suerte!

+0

Muchos gracias wageoghe, eso funcionó. Sin embargo, como es siempre el caso, después de haber logrado que funcionase la funcionalidad básica, ahora necesito afinar las cosas :-) Básicamente necesito tener diferentes diseños para los diferentes niveles de registro, ¿cómo se condiciona el diseño al nivel seleccionado? –

+0

¿Cómo quieres que sean los diferentes diseños? ¿Desea tener diferentes campos en los diseños para diferentes niveles de registro? En cualquier caso, probablemente puedas usar la técnica que Pat muestra en el enlace de arriba. Define un objetivo de archivo para sus mensajes de registro "normales" y define un objetivo de "filtro envoltorio" para utilizar un diseño diferente para los mensajes que contienen una excepción. Trataré de agregar un ejemplo de algo que pueda ayudarte. – wageoghe

+0

Usando la técnica sugerida, para lo siguiente: Recibo el siguiente error en el archivo de configuración: 'El atributo' writeTo 'no es válido ...' para –

9

Acabo de tropezar con esto mientras busco replicar un encabezado/pie de página en un registro de uno de mis compañeros de trabajo creado con log4net. Encontré esto de algún proyecto de código abierto y lo adapté como un ejemplo interno. Creo que debería ser simple modificarlo para sus necesidades.

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

Me da salida que se parece a esto:

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

no tengo ni idea de por qué esto parece ser indocumentado. La única referencia que pude encontrar fue aquí: https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter

-Jody

+0

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

+0

Se corrigió el enlace. Gracias. – JKoplo

1

Puede generar una sección de encabezado/pie de página por "ejemplo" (es decir,la primera vez que la aplicación y la última vez que la aplicación escribe a cualquier archivo dado) con los diseños como indicated by previous answer:

más detalle:

+0

Quizás podamos fusionar su respuesta con la anterior, ya que solo está agregando nuevos enlaces. También podría apuntar a https://github.com/NLog/NLog/issues/2119 donde alguien solicita tener el encabezado y el pie de página cada vez que se inicia y se detiene la aplicación. – user276648

Cuestiones relacionadas