Как я могу изменить местоположение файла программно? - PullRequest
71 голосов
/ 08 октября 2009

Я совершенно новичок в Log4net.
Мне удалось что-то сделать, добавив файл конфигурации и простую регистрацию.
Я жестко закодировал значение, равное "C:\temp\log.txt", но этого недостаточно.

Журналы должны идти в специальные папки

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

и этот путь меняется в зависимости от того, используете ли вы Windows Server 2008 или Windows XP или Vista и т. Д. *

Как мне просто программно изменить местоположение файла в log4net?

Вот что я сделал:

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

Просто нужно выяснить, как я могу перейти в журнал, где я хочу.

Есть предложения? Большое спасибо

Ответы [ 11 ]

86 голосов
/ 08 октября 2009

log4net может справиться с этим для вас. Любое свойство appender типа string можно отформатировать, в этом случае с помощью обработчика опций log4net.Util.PatternString . PatternString даже поддерживает перечисление SpecialFolder , которое включает следующую элегантную конфигурацию:

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

Вот модульный тест, который подтверждает пудинг:

[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));
}

Следующий тест проверяет, что log4net действительно записывает на диск (что в основном делает это "интеграционным" тестом, а не модульным тестом, но мы пока оставим его здесь):

[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"));
}

Примечание: я настоятельно рекомендую использовать синтаксис компактных свойств, показанный в приведенном выше примере. Удаление всех этих «

39 голосов
/ 06 августа 2011

Я нашел мутацию этого кода во внутренних сетях:

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

Это работает для меня. Наше приложение должно поместить файл журнала в папку, содержащую номер версии приложения на основе файла AssemblyInfo.cs.

Вы должны быть в состоянии установить logFileLocation программно (например, вы можете использовать Server.MapPath (), если это веб-приложение) для удовлетворения ваших потребностей.

14 голосов
/ 08 декабря 2010

Похоже, Ответ Питера не работает для Log4net v1.2.10.0. Альтернативный метод описан здесь .

По сути, метод заключается в реализации пользовательского конвертера шаблонов для файла конфигурации log4net.

Сначала добавьте этот класс в ваш проект:

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));
    }
}

Затем настройте параметр File вашего FileAppender следующим образом:

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

В основном %folder говорит ему взглянуть на конвертер с именем folder, который указывает на класс SpecialFolderPatternConverter. Затем он вызывает Convert для этого класса, передавая значение перечисления CommonApplicationData (или любого другого).

6 голосов
/ 20 октября 2012

Как насчет простого:

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

Почему так сложно сделать действительно простую вещь?

4 голосов
/ 06 октября 2011

Это сработало для меня:

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

При необходимости записи в специальные папки я нашел справку здесь (2-й и 3-й пример).

Edit:

Для ответа OP. Это работает для области «все пользователи»:

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

Обычно это "C: \ ProgramData" в более новых версиях Windows.

См. Также:
Как указать общую папку данных приложения для log4net? == https://stackoverflow.com/a/1889591/503621 и комментарии
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621

3 голосов
/ 09 октября 2018

Ответ JackAce, просто более кратко, используя Linq:

C #

XmlConfigurator.Configure();
var appender = (LogManager.GetRepository() as Hierarchy).Root.Appenders
    .OfType<FileAppender>()
    .First();

appender.File = logPath;
appender.ActivateOptions();

VB.NET

XmlConfigurator.Configure()
Dim appender = CType(LogManager.GetRepository(), Hierarchy).Root.Appenders _
    .OfType(FileAppender)() _
    .First()

appender.File = logPath
appender.ActivateOptions()
3 голосов
/ 04 февраля 2015

Чтобы также изменить путь журнала ошибок (на основе ответа 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();
            }
        }
    }
}
1 голос
/ 13 сентября 2018

В текущей версии Log4Net (2.0.8.0) вы можете просто использовать <file value="${ProgramData}\myFolder\LogFiles\" /> для C:\ProgramData\.. и ${LocalAppData} для C:\Users\user\AppData\Local\

1 голос
/ 30 сентября 2015

Отличный вариант использования для LINQ OfType<T> filter:

/// <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();
    }
}

Если имя файла в app.config равно log.txt, это изменит вывод журнала на logs/some_name_log.txt:

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

Чтобы ответить на оригинальную задачу ОП, это будет:

ChangeLogFile(path => Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), path));
0 голосов
/ 13 апреля 2014

Если вам необходимо выполнить развертывание в неизвестных системах и вы хотите использовать простое решение от Philipp M даже с различными специальными папками, вы можете получить нужный путь к специальной папке и установить пользовательскую переменную env перед загрузкой конфигурации log4net. string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData); XmlConfigurator.Configure( ...

... просто чтобы убедиться, что переменная env существует и имеет желаемое значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...