2009-10-14 22 views
5

log4net no hace la sustitución correcta PatternString para mi nombre de usuario. Quiero que mi registro para serLog4Net no puede encontrar el nombre de usuario% propiedad cuando nombro el archivo en mi appender

Logs \ AAAAMMDD \ MSMQcore_ [nombre de usuario] .log

Cuando uso la propiedad %username, consigo el dominio en la ruta, lo que añade otra vía indirecta carpeta en la que hay . Solo quiero el nombre de usuario.

Logs \ AAAAMMDD \ MSMQcore_ [dominio] \ [nombre de usuario] .log

Alguien tiene un ejemplo de insertar el "nombre de usuario" en el nombre de archivo del appender? He intentado un montón de cosas, todavía estoy rascándome la cabeza.

<appender name="core_Appender" type="log4net.Appender.RollingFileAppender" > 
<!-- <file type="log4net.Util.PatternString" value="Logs/%date{yyyyMMdd}/MSMQcore_%identity.log" /> --> 
<!-- <file type="log4net.Util.PatternString" value="Logs/%date{yyyyMMdd}/MSMQcore_%property{user}.log" /> --> 
<file type="log4net.Util.PatternString" value="Logs/%date{yyyyMMdd}/MSMQcore_%username.log" /> 
</appender> 
+0

Puede obtenerlo a través de un patrón de apéndice en Log4Net versión 1.2.11. Ver stackoverflow.com/a/26277219/203371 –

Respuesta

9

Utilizando el entorno de patrón variable funciona para mí:

<file type="log4net.Util.PatternString" value="Logs\\%env{USERNAME}.txt" /> 

Actualización: si la variable de entorno USERNAME no es una opción, la subclasificación PatternString podría ser una alternativa. Aquí es una aplicación sencilla:

public class MyPatternString : PatternString 
{ 
    public MyPatternString() 
    { 
     AddConverter("usernameonly", typeof(UserNameOnlyConverter)); 
    }  
} 

public class UserNameOnlyConverter : PatternConverter 
{ 
    override protected void Convert(TextWriter writer, object state) 
    { 
     var windowsIdentity = WindowsIdentity.GetCurrent(); 
     if (windowsIdentity != null && windowsIdentity.Name != null) 
     { 
      var name = windowsIdentity.Name.Split('\\')[1]; 
      writer.Write(name); 
     } 
    } 
} 

El nuevo ajuste se verá así:

<file type="MyPatternString" value="Logs\\%usernameonly.txt" /> 

Actualización 2: de responder por qué% de identidad y% propiedad {usuario} no trabajo:

El% de patrón de identidad recoge la propiedad de identidad en el hilo actual. Esta propiedad está en mis pruebas nula, y probablemente sea así hasta que uno asigne una identidad de Windows específica al hilo en ejecución. Esto no funcionará en el contexto del appender porque no sabrá qué thread realizará el anexar real.

El% del patrón de propiedad recoge las propiedades de las clases GlobalContext y ThreadContext. De forma predeterminada, solo el log4net: HostName (LoggingEvent.HostNameProperty) se registra en GlobalContext. Entonces, a menos que usted activamente registre propiedades en esos contextos, no puede usarlos con el patrón de propiedad%. Una vez más, ThreadContext es inútil en el contexto del appender ya que no tiene forma de saber qué thread hará el anexar.

Dicho esto, el registro de una propiedad llamada nombre de usuario en la colección GlobalContext.Properties, en alguna parte de la rutina de inicio de la aplicación tal vez, permitirá a la propiedad% {usuario} para funcionar como se espera.

+0

Peter, gracias ... esto también funcionó para mí. Lucky, la variable de entorno se estableció. Todavía no estoy seguro de por qué las otras versiones no funcionaron. ¿quizás PatternString solo analiza la cadena en un solo pase? tvm, Craig – Craig

+0

Muchas gracias. Esto es asombroso – Stephen

+0

Craig, creo que llamar a AddConverter demasiado pronto en el código puede haber sido parte del problema. Vea mi respuesta a continuación para saber qué funcionó para mí. – Kit

3

La respuesta de Peter casi trabajó para mí; Definitivamente me puso en el camino correcto porque necesitaba una solución similar.Lo que tenía que hacer era subclase PatternConverter:

public class ConfigurationSettingsConverter : PatternConverter 
{ 
    protected override void Convert(TextWriter writer, object state) 
    { 
     // use Option as a key to get a configuration value... 
     if (Option != null) 
      writer.Write(ConfigUtils.Setting[Option]); 
    } 
} 

y añadir este convertidor en el ActivateOptions anulación de una subclase de PatternString:

public class ConfigurationSettingsPatternString : PatternString 
{ 
    public ConfigurationSettingsPatternString() 
    {} 

    public ConfigurationSettingsPatternString(string pattern): base(pattern) 
    {} 

    public override void ActivateOptions() 
    { 
     AddConverter("cs", typeof(ConfigurationSettingsConverter)); 
     base.ActivateOptions(); 
    } 
} 

originalmente tratado de hacer esto en el constructor como respondió Pedro pero el convertidor no se devolvió desde la llamada subyacente de la cadena de patrones para analizar la cadena de origen. También tuve que registrar un convertidor de tipos (que no debe confundirse con un PatternConverter) en cualquier parte de la ruta de código antes de log4net se configuró:

ConverterRegistry.AddConverter(
    // type we want to convert to (from string)... 
    typeof(ConfigurationSettingsPatternString), 
    // the type of the type converter that will do the conversion... 
    typeof(ConfigurationSettingsPatternStringConverter)); 

No hacer esto evita log4net de ser capaz de convertir el valor atributo en FileAppender 'nodo (es decir, una cadena) en un ConfigurationSettingsPatternString. Por ejemplo, en este fragmento de configuración,

<file 
    type="Some.Name.Space.ConfigurationSettingsPatternString, Some.Assembly" 
    value="some\path\MyLog.%cs{SomeKey}.log" /> 

%cs.{SomeKey} no llegaría expandido, y log4net produce una excepción. Aquí está el código para el convertidor de tipos:

public class ConfigurationSettingsPatternStringConverter : IConvertTo, IConvertFrom 
{ 
    public bool CanConvertFrom(Type sourceType) 
    { 
     return sourceType == typeof(string); 
    } 

    public bool CanConvertTo(Type targetType) 
    { 
     return typeof(string).IsAssignableFrom(targetType); 
    } 

    public object ConvertFrom(object source) 
    { 
     var pattern = source as string; 
     if (pattern == null) 
      throw ConversionNotSupportedException.Create(typeof(ConfigurationSettingsPatternString), source); 
     return new ConfigurationSettingsPatternString(pattern); 
    } 

    public object ConvertTo(object source, Type targetType) 
    { 
     var pattern = source as PatternString; 
     if (pattern == null || !CanConvertTo(targetType)) 
      throw ConversionNotSupportedException.Create(targetType, source); 
     return pattern.Format(); 
    } 
} 

Esto resulta para funcionar bien para múltiples servicios de Windows alojados dentro del mismo ejecutable (por ejemplo, es posible añadir un serviceName patrón % como el nombre del archivo para separar el registros de servicios de los

+0

Muchas gracias, esto está funcionando para mí. – Vince

1

el uso de '% nombre de usuario' funciona para mí;..

<parameter> 
    <parameterName value="@identity" /> 
    <dbType value="String" /> 
    <size value="255" /> 
    <layout type="log4net.Layout.PatternLayout"> 
    <conversionPattern value="%username" /> 
    </layout> 
</parameter> 

Pero, de nuevo estoy en el contexto de una aplicación Windows Forms estándar, no una aplicación ASP.NET no estoy seguro si esto es Que estas buscando . Ya no se requiere Uso atributo

[TypeConverter("namespace.ConfigurationSettingsPatternStringConverter")] 
public class ConfigurationSettingsPatternString : PatternString 
{ 

Y la llamada a

ConverterRegistry.AddConverter(
// type we want to convert to (from string)... 
typeof(ConfigurationSettingsPatternString), 
// the type of the type converter that will do the conversion... 
typeof(ConfigurationSettingsPatternStringConverter)); 

:

0
<layout type="log4net.Layout.PatternLayout"> 
    <conversionPattern value="Running on ${COMPUTERNAME}/${USERNAME} %newline %logger %date%newline Thread ID=[%thread]%newline %-5level - %message%newline" /> 
</layout> 

Esto funcionó bien para mí.

Cuestiones relacionadas