2016-08-25 108 views
2

小さなプログラムやタスクを起動するプログラムがあり、今度はタスクの名前を使用して動的に自分のファイル名に動的にログを記録したい。 少し掘り下げましたが、Log4Netで使用できるのは、%propertyという素晴らしいものがあるようです。だから私はそれを試みた。しかし、Log4Netは、初期化された後、これに対してピックアップの変更がないようです。実行時にlog4netのファイル名を変更する

私は周りに遊ぶために少しテストプログラムを書いた。 ウィンザーコンテナを一度しかビルドしたくないのですが、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

log4net.configで定義されたあなたのアペンダで指定できますファイル名の出力形式。例えば、<file value="fixedName"/><staticLogFileName value="false"/>をパターンとともに使用して、動的ファイル名を指定することもできます。

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

日付とあなたの"SomePropertyName"プロパティに基づいて別のファイルにこの意志ルート。

タスクには、log4net.ThreadContext.Properties["SomePropertyName"] = "someValue";のようにそのプロパティを設定する必要があります。

ロギングイベント(%tまたは%thread)を生成したスレッドの名前が良いスイッチだと思います。名前がない場合はスレッド番号を出力します。しかし、スレッド名をITaskに明示的に設定することができます。 1つのロガーを持っているされて - あなたのタスクを同時に実行仮定 -

+1

あなたが本当にやったすべてが 'ThreadContext'の代わりに使用' GlobalContext'されますこれはまだ動作しません - ファイル名は設定時に設定されます。プロパティの値は必要なだけ変更できますが、効果はありません。 – stuartd

0

は私が各タスクが好ましくタスク

の名前、これを行うための唯一の方法を使用して、動的に自分のファイル名にログインしますタスクごとに、各ロガーにはそれ自身のアペンダーがあります。

気づいたとおり、設定時に設定されているように、プロパティを変更してもログファイルは変更されません。一般的な解決策は、実行時にアペンダーファイル名をプログラムでパッチすることです。これは簡単ですが、ロガーがアペンダーを共有するため、別のタスクのファイルに1つのタスクが記録されます。

だから、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

関連する問題