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!
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? –
¿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
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 –