2016-08-25 47 views
2

我有一個啓動較小程序或任務的程序,現在我希望每個任務都動態地記錄到它們自己的文件名,最好使用任務名稱。 我已經挖掘了一點,似乎有一個漂亮的%property事情,你可以使用Log4Net。所以我試了一下。但似乎Log4Net在初始化之後沒有爲此獲取更改。運行時更改log4net文件名

我寫了一個小測試程序來玩。 我寧願只構建windsor容器一次,但是Log4Net不會「重新初始化」,並創建一個新的日誌文件。所以現在我必須在開始任務之前構建容器,以確保我在日誌文件中獲得了正確的文件名。

有誰知道是否有更好/更聰明的方法來改變運行時的日誌文件名?

這裏是我的testcode:

public class Program 
{ 
    static void Main(string[] args) 
    { 
     GlobalContext.Properties["LogName"] = "default"; 
     XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config")); 

     while (true) 
     { 
      Console.WriteLine(); 
      Console.Write("> "); 
      string cmd = (Console.ReadLine() ?? string.Empty); 
      if (string.IsNullOrWhiteSpace(cmd)) continue; 
      if (cmd.ToLower() == "exit") Environment.Exit(0); 

      ExecuteTask(Regex.Split(cmd, @"\s+")); 
     } 
    } 

    private static void ExecuteTask(string[] args) 
    { 
     //This changes the filename Log4Net logs to, but Log4Net only picks it up if I rebuild my container 
     GlobalContext.Properties["LogName"] = args[0]; 

     //This should only be run once. No real need to build the container before each run, except to reinitialize Log4Net 
     var container = BuildContainer(); 
     try 
     { 
      var task = container.Resolve<ITask>(args[0]); 
      task.DoLog(); 
     } 
     catch (Exception) 
     { 
      // This doesn't work as expected, Log4Net logs to the file specified outside of the trycatch 
      GlobalContext.Properties["LogName"] = "default"; 
      var logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 
      logger.Info("Could not find "+args[0]); 
     } 
    } 


    private static WindsorContainer BuildContainer() 
    { 
     Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); 

     var container = new WindsorContainer(); 
     container.Install(
      FromAssembly.This()); 

     return container; 
    } 
} 

public interface ITask 
{ 
    void DoLog(); 
} 

public class TwoTask : ITask 
{ 
    private readonly ILogger _logger; 

    public TwoTask(ILogger logger) 
    { 
     _logger = logger; 
    } 

    public void DoLog() 
    { 
     _logger.Info("Hello!"); 
    } 
} 

public class OneTask : ITask 
{ 
    private readonly ILogger _logger; 

    public OneTask(ILogger logger) 
    { 
     _logger = logger; 
    } 

    public void DoLog() 
    { 
     _logger.Info("Hello!"); 
    } 
} 

public class Installer : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(Classes.FromThisAssembly() 
            .BasedOn(typeof(ITask)) 
            .Configure(c => c.LifeStyle.Transient.Named(c.Implementation.Name))); 
     container.AddFacility<LoggingFacility>(f => f.UseLog4Net("log4net.config")); 
    } 
} 

Nugets使用: Castle.Core,Castle.Core-log4net的,Castle.LoggingFacility,Castle.Windsor

回答

-1

在你的appender在log4net.config定義,你可以指定一個輸出格式爲文件名。例如<file value="fixedName"/>。您還可以使用<staticLogFileName value="false"/>以及一個圖案(例如,

<file type="log4net.Util.PatternString" value="somePrefix-%property{SomePropertyName}-%utcdate{yyMMdd}.trace.log" />. 

這將路線基於日期不同的文件和"SomePropertyName"財產。

你將不得不在你的任務中設置這個propery,如log4net.ThreadContext.Properties["SomePropertyName"] = "someValue";

我想一個好的開關將是生成記錄事件(%t%thread)的線程的名稱。如果沒有名稱可用,則輸出線程號。但是你可以在你的ITask中明確地設置線名。

+1

所有你真的做的是使用'ThreadContext',而不是'GlobalContext'但這仍然不起作用 - 文件名在配置時設置。您可以儘可能多地更改屬性的值,但它不會起作用。 – stuartd

0

我想每個任務登錄到自己的文件名動態,最好使用任務

的名稱要做到這一點的唯一方法 - 假設你的任務同時運行 - 就是有一個記錄器每個任務,其中每個記錄器有它自己的appender

正如您已經注意到的那樣,更改屬性並不會更改日誌文件,因爲這是在配置時設置的。一個常見的解決方案是在運行時以編程方式修補appender文件名 - 這很容易,但是由於記錄器共享appender,您會看到一個任務登錄到另一個任務的文件。

所以,你將不得不construct loggers and appenders at runtime - 從後摘錄:

// Create a new file appender 
public static log4net.Appender.IAppender CreateFileAppender(string name, 
string fileName) 
{ 
    log4net.Appender.FileAppender appender = new 
    log4net.Appender.FileAppender(); 
    appender.Name = name; 
    appender.File = fileName; 
    appender.AppendToFile = true; 

    log4net.Layout.PatternLayout layout = new 
    log4net.Layout.PatternLayout(); 
    layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n"; 
    layout.ActivateOptions(); 

    appender.Layout = layout; 
    appender.ActivateOptions(); 

    return appender; 
} 

和:

// Add an appender to a logger 
public static void AddAppender(string loggerName,log4net.Appender.IAppender appender) 
{ 
    log4net.ILog log = log4net.LogManager.GetLogger(loggerName); 
    log4net.Repository.Hierarchy.Logger l = 
      (log4net.Repository.Hierarchy.Logger)log.Logger; 

     l.AddAppender(appender); 
} 
+0

這些任務不會同時運行,所以他們在彼此的文件中寫入應該沒有問題。 如果我只是在每次運行之前就可以讓Castle.Windsor解決記錄器問題,我認爲它可以。但這似乎也不起作用。 – Markus

+1

在這種情況下,您可以通過編程爲每個任務設置文件名,log4net將創建一個新文件 - 例如, http://stackoverflow.com/a/32873679/43846 – stuartd