2009-10-08 7 views
65

Я совершенно новичок в Log4net.
Мне удалось что-то сделать, добавив файл конфигурации и простую регистрацию.
У меня есть hardcoded значение "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? 
    } 
} 

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

Любые предложения? Спасибо большое

+0

Вы должны копаться IAppenders вашего Logger и установить FileAppender.File на нужный путь вывода. Вот [действительно хороший пример] (http://insario.com/blog/jfk/archive/2004/11/30/164.aspx). –

ответ

82

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

NB: Я настоятельно рекомендую использовать комп синтаксис свойства действия, продемонстрированный в приведенном выше примере. Удаление всех этих «< property name =» делает вашу конфигурацию более читаемой.

+1

Привет Черт возьми, я пробовал это, но до сих пор не вхожу в приложение. Данные Я посмотрел в Интернете. Я нашел что-то под названием PatternString, но я понятия не имею, как его использовать. У кого-нибудь есть пример? – 2009-10-09 05:36:22

+0

@brix - Мой первоначальный ответ не сработал, поэтому я должен был доказать себе, что log4net может это сделать. PatternString - это решение :) –

+0

привет, попробовал ваше решение, но по некоторым причинам он вообще не регистрируется. Я скопировал то, что вы предложили. Запустите приложение, но файл не создан. Создает ли ваш файл файл? спасибо большое – 2009-10-11 05:20:27

0

В качестве альтернативы этому программно вы можете использовать переменные окружения и настраиваемые шаблоны в файле конфигурации. See this response to a similar question.

Посмотрите на «PatternString для конфигурации на основе шаблонов» в the Log4Net V1.2.10 release notes.

Кроме того, если вы думаете о письменной форме в каталогах, таких как Enviroment.SpecialFolder.CommonApplicationData вам необходимо рассмотреть следующие вопросы:

  • Будут ли все экземпляры приложения для всех пользователей есть доступ на запись в лог-файл? Например. Я не считаю, что не-администраторы смогут писать в Enviroment.SpecialFolder.CommonApplicationData.

  • Конфликт, если несколько экземпляров вашего приложения (для тех же или разных пользователей) пытаются в том же файле. Вы можете использовать «минимальную блокирующую модель» (см. http://logging.apache.org/log4net/release/config-examples.html, чтобы разрешить нескольким процессам писать в один и тот же файл журнала, но, вероятно, это повлияет на производительность.Или вы можете дать каждому процессу другой файл журнала, например. путем включения идентификатора процесса в имя файла с помощью настраиваемого шаблона.

13

Похоже, Peter's answer не работает для Log4net v1.2.10.0. Описан альтернативный способ here.

В основном метод заключается в реализации настраиваемого конвертера шаблонов для файла конфигурации 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 (или что-то еще).

+0

Спасибо за это. btw, App в MyAppName Я думаю, что это Project, а не App. –

34

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

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(), если это веб-приложение) в соответствии с вашими потребностями.

+3

Я думаю, что это лучший ответ :) –

+4

Я чувствую, что это дает гораздо больший контроль над расположением файла. – fregas

3

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

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

Если необходимости писать в специальные папки я нашел помощь here (второй и третий пример).

Edit:

Чтобы ответить на OP .. Это работает для области "всех пользователей:

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

, который обычно "C: \ ProgramData" в новых версиях Windows.

Смотреть это тоже:
How to specify common application data folder for log4net? == https://stackoverflow.com/a/1889591/503621 и комментарии
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621

+1

Мне это нравится - красиво и просто. –

+0

'Environment.SpecialFolder.CommonApplicationData' и' $ (APPDATA) 'не являются одной и той же папкой –

+0

Вместо этого вы можете попробовать« $ {ALLUSERSPROFILE} ». , – bshea

5

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

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

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

+11

Поскольку изменения пути зависят от того, находитесь ли вы в Windows Server 2008 или winxp или vista и т. Д. В XP нет папки c: \ ProgramData, только в Win7/Vista. Итак, если мы собираемся развернуть это приложение, оно должно быть совместимо для всех ОС. :-) Жесткое кодирование не является хорошей практикой. – Irshad

+4

Я использую log4net v2.0.3, и это свойство недоступно в XmlConfigurator. Должно быть удалено с момента отправки ответа. – Appetere

+0

Спасибо Джейсону за исправление моего английского языка, это не мой основной язык;) Спасибо! – Eric

0

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

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

2

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

Большой случай использования для LINQs OfType<T> фильтр:

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

Когда я это сделал, он просто заново создал пустой файл с новым именем, но вместо этого «Logger.GetLogger» продолжал писать вместо старого. –

Смежные вопросы