¿Cómo puedo cambiar la ubicación del archivo mediante programación?


Soy totalmente nuevo en Log4net.
He logrado poner en marcha algo agregando un archivo de configuración y un simple registro.
He codificado el valor para ser "C:\temp\log.txt" pero esto no es lo suficientemente bueno.

Los registros deben ir a las carpetas especiales

path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

Y esta ruta cambia dependiendo de si está utilizando Windows Server 2008 o Windows XP o Vista, etc...

¿Cómo puedo cambiar la ubicación del archivo en log4net mediante programación?

Esto es lo que tengo hecho:

<configSections>
<section name="log4net"
         type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>         
    <root>
        <level value="DEBUG" />
        <appender-ref ref="LogFileAppender" />
    </root>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
        <param name="File" value="C:\temp\log.txt" />
        <param name="AppendToFile" value="true" />
        <rollingStyle value="Size" />
        <maxSizeRollBackups value="10" />
        <maximumFileSize value="10MB" />
        <staticLogFileName value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
        </layout>
    </appender>
</log4net>

class Program
{
    protected static readonly ILog log = LogManager.GetLogger(typeof(Program));

    static void Main(string[] args)
    {
        log4net.Config.XmlConfigurator.Configure();
        log.Warn("Log something");

        path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);


        // How can I change where I log stuff?
    }
}

Solo necesito averiguar cómo puedo cambiar las cosas de registro a donde quiero.

Alguna sugerencia? Muchas gracias

 65
Author: Timo, 2009-10-08

10 answers

Log4net puede manejar esto por usted. Cualquier propiedad appender de tipo string puede ser formateada, en este caso, usando el log4net.Útil.PatternString controlador de opciones. PatternString incluso soporta la enumeración SpecialFolder que habilita la siguiente configuración elegante:

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
    <file type="log4net.Util.PatternString" 
        value="%envFolderPath{CommonApplicationData}\\test.txt" />
    ...
</appender>

Aquí hay una prueba unitaria que prueba el pudín:

[Test]
public void Load()
{
    XmlConfigurator.Configure();
    var fileAppender = LogManager.GetRepository()
        .GetAppenders().First(appender => appender is RollingFileAppender);

    var expectedFile = 
        Path.Combine(
            Environment.GetFolderPath(
                Environment.SpecialFolder.CommonApplicationData),
                "test.txt");

    Assert.That(fileAppender, 
        Is.Not.Null & Has.Property("File").EqualTo(expectedFile));
}

La siguiente prueba verifica que log4net realmente escribe en el disco (lo que básicamente hace que esto sea una prueba de "integración", no una prueba unitaria, sino lo dejaremos así por ahora):

[Test]
public void Log4net_WritesToDisk()
{
    var expectedFile = 
        Path.Combine(
            Environment.GetFolderPath(
                Environment.SpecialFolder.CommonApplicationData),
                "test.txt");

    if (File.Exists(expectedFile))
        File.Delete(expectedFile);

    XmlConfigurator.Configure();

    var log = LogManager.GetLogger(typeof (ConfigTest));
    log.Info("Message from test");

    LogManager.Shutdown();

    Assert.That(File.ReadAllText(expectedFile), 
        Text.Contains("Message from test"));
}

NB: Recomiendo encarecidamente usar la sintaxis de propiedades compactas mostrada en el ejemplo anterior. Eliminar todos esos "

 83
Author: Peter Lillevold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-19 20:44:54

Encontré una mutación de este código en las interwebs:

XmlConfigurator.Configure();
log4net.Repository.Hierarchy.Hierarchy h =
(log4net.Repository.Hierarchy.Hierarchy) LogManager.GetRepository();
foreach (IAppender a in h.Root.Appenders)
{
    if (a is FileAppender)
    {
        FileAppender fa = (FileAppender)a;
        // Programmatically set this to the desired location here
        string logFileLocation = @"C:\MySpecialFolder\MyFile.log";

        // Uncomment the lines below if you want to retain the base file name
        // and change the folder name...
        //FileInfo fileInfo = new FileInfo(fa.File);
        //logFileLocation = string.Format(@"C:\MySpecialFolder\{0}", fileInfo.Name);

        fa.File = logFileLocation;
        fa.ActivateOptions();
        break;
    }
}

Esto funciona para mí. Nuestra aplicación necesita poner el archivo de registro en una carpeta que contenga el número de versión de la aplicación basado en el AssemblyInfo.archivo CS.

Debería ser capaz de establecer el logFileLocation mediante programación (por ejemplo, puede utilizar Server.MapPath () si se trata de una aplicación web) para satisfacer sus necesidades.

 35
Author: JackAce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-05 22:51:07

Parece que La respuesta de Peter no funciona para Log4net v1.2.10.0. Un método alternativo se describe aquí.

Básicamente el método es implementar un convertidor de patrones personalizado para el archivo de configuración log4net.

Primero agregue esta clase a su proyecto:

public class SpecialFolderPatternConverter : log4net.Util.PatternConverter
{
    override protected void Convert(System.IO.TextWriter writer, object state)
    {
        Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), base.Option, true);
        writer.Write(Environment.GetFolderPath(specialFolder));
    }
}

Luego configure el parámetro File de su FileAppender de la siguiente manera:

<file type="log4net.Util.PatternString">
    <converter>
      <name value="folder" />
      <type value="MyAppName.SpecialFolderPatternConverter,MyAppName" />
    </converter>
    <conversionPattern value="%folder{CommonApplicationData}\\SomeOtherFolder\\log.txt" />
  </file>

Básicamente el %folder le dice que mire el convertidor llamado folder que lo apunta a la Clase de convertidor especial Folderpattern. Luego llama a Convert en esa clase, pasando el valor de enumeración CommonApplicationData (o lo que sea).

 13
Author: codeulike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:44

¿Qué tal un simple:

XmlConfigurator.LogFullFilename = @"c:\ProgramData\MyApp\Myapp.log";

¿Por qué es tan complejo hacer algo realmente simple?

 5
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-19 21:14:18

Esto funcionó para mí:

  <log4net>
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
..
      <file value="${APPDATA}\MyApp\MyApp Client\logs\Log.txt"/>
..
  </log4net>

Si necesitaba escribir en carpetas especiales, encontré ayuda aquí (ejemplo 2 y 3).

Editar:

Para responder OP.. Esto funciona para el área 'todos los usuarios':

      ...
      <file value="${ALLUSERSPROFILE}\MyApp\MyApp Client\logs\Log.txt"/>
      ...

Que es normalmente "C:\ProgramData" en las versiones más recientes de Windows.

Ver estos también:
¿Cómo especificar la carpeta de datos de aplicaciones comunes para log4net? == https://stackoverflow.com/a/1889591/503621 y observaciones
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621

 3
Author: bshea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:24

Para cambiar también la ruta del registro de errores (basado en la respuesta de JackAce):

private static void SetLogPath(string path, string errorPath)
{
    XmlConfigurator.Configure();
    log4net.Repository.Hierarchy.Hierarchy h =
    (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
    foreach (var a in h.Root.Appenders)
    {
        if (a is log4net.Appender.FileAppender)
        {
            if (a.Name.Equals("LogFileAppender"))
            { 
                log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a;                    
                string logFileLocation = path; 
                fa.File = logFileLocation;                   
                fa.ActivateOptions();
            }
            else if (a.Name.Equals("ErrorFileAppender"))
            {
                log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a;
                string logFileLocation = errorPath;
                fa.File = logFileLocation;
                fa.ActivateOptions();
            }
        }
    }
}
 2
Author: Jim109,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-04 19:00:20

Como alternativa a hacer esto programáticamente, puede usar variables de entorno y patrones personalizables en el archivo de configuración. Ver esta respuesta a una pregunta similar.

Mira "PatternString for pattern based configuration" en las notas de la versión de Log4Net V1.2.10.

También si está pensando en escribir en un directorio como Enviroment.Plafón especial.Commonapplicationdatos que debe tener en cuenta:

  • Todas las instancias de su aplicación para todos los usuarios tienen acceso de escritura al archivo de registro? Por ejemplo, no creo que los no administradores puedan escribir a Medio Ambiente.Plafón especial.Datos de aplicación común.

  • Contención si varias instancias de su aplicación (para el mismo o diferentes usuarios) están intentando el mismo archivo. Puede utilizar el " modelo de bloqueo mínimo "(ver http://logging.apache.org/log4net/release/config-examples.html para permitir que múltiples procesos escriban en el mismo archivo de registro, pero probablemente habrá un impacto en el rendimiento. O puede darle a cada proceso un archivo de registro diferente, por ejemplo, incluyendo el id del proceso en el nombre del archivo utilizando un patrón personalizable.

 0
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:35

Si tiene que implementar en sistemas desconocidos y desea utilizar la solución simple de Philipp M incluso con diferentes carpetas especiales, puede recuperar la ruta de carpeta especial que desee y establecer una variable env personalizada antes de cargar la configuración de log4net. string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData); XmlConfigurator.Configure( ...

... solo para estar seguro de que la variable env existe y tiene el valor que desea.

 0
Author: user3529289,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-13 15:36:57

Gran caso de uso para LINQs OfType<T> filtro:

/// <summary>
/// Applies a transformation to the filenames of all FileAppenders.
/// </summary>
public static void ChangeLogFile(Func<string,string> transformPath)
{
    // iterate over all FileAppenders
    foreach (var fileAppender in LogManager.GetRepository().GetAppenders().OfType<FileAppender>())
    {
        // apply transformation to the filename
        fileAppender.File = transformPath(fileAppender.File);
        // notify the logging subsystem of the configuration change
        fileAppender.ActivateOptions();
    }
}

Si el nombre del archivo en la aplicación.config es log.txt esto cambiará la salida del registro a logs/some_name_log.txt:

ChangeLogFile(path => Path.Combine("logs", $"some_name_{Path.GetFileName(path)}"));

Para responder al problema original de OPs que sería:

ChangeLogFile(path => Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), path));
 0
Author: Gigo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-30 18:58:44

En la versión actual de Log4Net (2.0.8.0) simplemente podría usar <file value="${ProgramData}\myFolder\LogFiles\" /> para C:\ProgramData\.. y ${LocalAppData} para C:\Users\user\AppData\Local\

 0
Author: Apfelkuacha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-13 16:42:28