2014-01-09 83 views
6

早上好。log4net:在運行時不同日誌文件上的不同文件

我寫了一個單一的C#2.0應用程序(叫它myapp)。
Myapp被調用很多次,每次調用都會生成一種「任務」,這個任務將在一個單獨的線程中執行。
如果您在短時間內多次調用myapp,則任務將並行執行。

通常我使用log4net進行記錄;我將其配置爲在啓動時通過XmlConfigurator.Configure(<config>.xml)加載xml文件,然後在每個需要記錄器的課程中使用靜態LogManager.GetLogger(name),非常簡單。

相反,這種情況很具有挑戰性。 我需要做的是:基於在每次調用(稱之爲ARG)接受args來一個,我需要一個不同的RollingFileAppender進行,在不同的文件,電子記錄。 G。日誌。

只是打一個比方:

第一個呼叫:myapp.exe -arg:01
- MYAPP創建線程1
- 設置一個新的RollingFileAppender進行到01.log文件,如果不存在
- 在這個線程使用必須登錄對象在01.log文件

第二個呼叫:myapp.exe -arg:02
- 創建線程2
- 設置一個新的RollingFileAppender進行到02.log文件,如果不存在
級 - 在這個線程使用的對象必須登錄02.log文件,但不是在log.01

第三個呼叫:myapp.exe -arg:01
- 創建thread03
- 讓RollingFileAppender進行到01.log文件(它已經存在!
- 在這個線程使用的對象必須登錄01.log文件,但不是在log.02

等。 我不需要在xml文件中保留RollingAppender的配置,我可以以編程方式創建它;我的想法是使用靜態包裝類,稱之爲LogHelper,如果它們不存在基於ARG創建附加目的地,以及調度權需要通過對象時(在課堂上我會使用類似ILog log = LogHelper.GetLogger(name, arg)獲得的ILog istances一個記錄器來代替o使用默認的log4net方法LogManager.GetLogger(name))。因此,如果我在2個不同的線程中有2個同一類的事件,當我記錄消息去每個文件一個,根據或arg(我將注入arg在每個對象,如果需要的話)。

我在StackOverflow中瀏覽了很多線程,但是我找不到解決方案。

有人能指點我正確的方向嗎?

在此先感謝。

回答

7

我結束了一個稍微不同的解決方案。
我創建了一個類似於默認log4net LogManager類的靜態類(對不起,名稱抱歉)。
區別在於,您可以根據arg獲得不同的ILog接口:LogMaster將爲您將使用的每種不同的arg創建一個新的ILoggerRepository

下面的代碼:

#region Usings 
using System; 
using System.IO; 

using log4net; 
using log4net.Appender; 
using log4net.Config; 
using log4net.Core; 
using log4net.Filter; 
using log4net.Layout; 
using log4net.Repository; 
using log4net.Repository.Hierarchy; 


#endregion 


namespace Common.Voyager 
{ 
    /// <summary> 
    /// A static class that emulates defualt log4net LogManager static class. 
    /// The difference is that you can get various loggers istances based from an args. 
    /// LogMaster will create a different logger repository for each new arg it will receive. 
    /// </summary> 
    public static class LogMaster 
    { 
     #region Const 
     private const string RollingFileAppenderNameDefault = "Rolling"; 
     private const string MemoryAppenderNameDefault = "Memory"; 
     #endregion 


     #region Constructors 
     static LogMaster() 
     { 
     } 
     #endregion 


     #region Public Methods 
     public static ILog GetLogger(string arg, string name) 
     { 
      //It will create a repository for each different arg it will receive 
      var repositoryName = arg; 

      ILoggerRepository repository = null; 

      var repositories = LogManager.GetAllRepositories(); 
      foreach (var loggerRepository in repositories) 
      { 
       if (loggerRepository.Name.Equals(repositoryName)) 
       { 
        repository = loggerRepository; 
        break; 
       } 
      } 

      Hierarchy hierarchy = null; 
      if (repository == null) 
      { 
       //Create a new repository 
       repository = LogManager.CreateRepository(repositoryName); 

       hierarchy = (Hierarchy)repository; 
       hierarchy.Root.Additivity = false; 

       //Add appenders you need: here I need a rolling file and a memoryappender 
       var rollingAppender = GetRollingAppender(repositoryName); 
       hierarchy.Root.AddAppender(rollingAppender); 

       var memoryAppender = GetMemoryAppender(repositoryName); 
       hierarchy.Root.AddAppender(memoryAppender); 

       BasicConfigurator.Configure(repository); 
      } 

      //Returns a logger from a particular repository; 
      //Logger with same name but different repository will log using different appenders 
      return LogManager.GetLogger(repositoryName, name); 
     } 
     #endregion 


     #region Private Methods 
     private static IAppender GetRollingAppender(string arg) 
     { 
      var level = Level.All; 

      var rollingFileAppenderLayout = new PatternLayout("%date{HH:mm:ss,fff}|T%2thread|%25.25logger|%5.5level| %message%newline"); 
      rollingFileAppenderLayout.ActivateOptions(); 

      var rollingFileAppenderName = string.Format("{0}{1}", RollingFileAppenderNameDefault, arg); 

      var rollingFileAppender = new RollingFileAppender(); 
      rollingFileAppender.Name = rollingFileAppenderName; 
      rollingFileAppender.Threshold = level; 
      rollingFileAppender.CountDirection = 0; 
      rollingFileAppender.AppendToFile = true; 
      rollingFileAppender.LockingModel = new FileAppender.MinimalLock(); 
      rollingFileAppender.StaticLogFileName = true; 
      rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Date; 
      rollingFileAppender.DatePattern = ".yyyy-MM-dd'.log'"; 
      rollingFileAppender.Layout = rollingFileAppenderLayout; 
      rollingFileAppender.File = string.Format("{0}.{1}", "log", arg); 
      rollingFileAppender.ActivateOptions(); 

      return rollingFileAppender; 
     } 

     private static IAppender GetMemoryAppender(string station) 
     { 
      //MemoryAppender 
      var memoryAppenderLayout = new PatternLayout("%date{HH:MM:ss} | %message%newline"); 
      memoryAppenderLayout.ActivateOptions(); 

      var memoryAppenderWithEventsName = string.Format("{0}{1}", MemoryAppenderNameDefault, station); 
      var levelRangeFilter = new LevelRangeFilter(); 
      levelRangeFilter.LevelMax = Level.Fatal; 
      levelRangeFilter.LevelMin = Level.Info; 

      var memoryAppenderWithEvents = new MemoryAppenderWithEvents(); 
      memoryAppenderWithEvents.Name = memoryAppenderWithEventsName; 
      memoryAppenderWithEvents.AddFilter(levelRangeFilter); 
      memoryAppenderWithEvents.Layout = memoryAppenderLayout; 
      memoryAppenderWithEvents.ActivateOptions(); 

      return memoryAppenderWithEvents; 
     } 
     #endregion 
    } 
} 

用法:

var arg = "myArg"; 
var loggerName = "MyLogger"; 
var log = LogMaster.GetLogger(arg, loggerName); 

使用此解決方案,您可以從默認的日誌管理行爲檢索ILog記錄儀中受益:如果具有相同名稱的記錄已經存在於存儲庫,你會得到回報(回收行爲)。

謝謝@ making3爲您的建議!

+0

嗨Ferdinando Santacroce,首先是所有的偉大的研究,恭喜... 如果您使用控制檯應用程序的代碼日誌輸出也發送到控制檯,你知道嗎? – oakman

+0

謝謝,我希望你覺得它有用。是的,我知道,謝謝:) –

2

我做了類似的事情,我需要一個類的每個實例的不同日誌。您可以通過幾個步驟動態創建日誌。

它看起來像一個default Logger (Line 97)已經定義,但它是它的程序集的內部,所以它需要被繼承(據我所知)。

public sealed class DynamicLogger : Logger 
{ 
    internal DynamicLogger(string name) : base(name) 
    { 
     base.Hierarchy = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository(); 
    } 
} 

樣的方法來檢索的ILog:

public static ILog GetSample(string arg) 
{ 
    var logger = new DynamicLogger(arg); 
    logger.Level = Level.All; 

    var consoleAppender = new ConsoleAppender(); 
    consoleAppender.Name = arg; 
    consoleAppender.Layout = new PatternLayout(arg + ": %m%newline"); 
    logger.AddAppender(consoleAppender); 

    var newLog = new LogImpl(logger); 
    if (_logs.Any(log => log.Logger.Name == newLog.Logger.Name) == false) 
     _logs.Add(newLog); 

    return newLog; 
} 

基本用法:

var foo = DynamicLog.GetSample("foo"); 
var bar = DynamicLog.GetSample("bar"); 
foo.Error("Test"); 
bar.Error("Test"); 

對於您的情況,考慮創建一個RollingFileAppender,並期待在對象上可用的屬性因爲這只是一個例子。

編輯:增加了以下用於存儲ILog's,並修改了上面的原始GetSample方法。

添加ILOG的數組和GetLogger方法:

private static List<ILog> _logs = new List<ILog>(); 

public static ILog GetLogger(string name) 
{ 
    return _logs.SingleOrDefault(a => a.Logger.Name == name); 
} 

使用範例:

DynamicLog.GetSample("foo"); 
var foo = DynamicLog.GetLogger("foo"); 
+0

非常感謝您的建議。我在RollingFileAppender的簡單控制檯應用程序中嘗試成功。 我會嘗試與平行線程現在,我交叉手指:) –

+0

有一種方法來檢索特定的記錄程序,一旦你用DynamicLog.GetSample()構建它?我不會在存儲庫中添加記錄器;如果我調用BasicConfigurator.Configure(),log4net將使用ConsoleAppender構建默認存儲庫。 –

+0

您可以隨時創建自己的'LogManager.GetLogger'方法。所有需要的是創建一個ILog列表,存儲'GetSample'創建的日誌,然後使用另一個方法,比如你自己的'GetLogger',它將搜索所有ILog的特定名稱,使用'log.Logger.Name '。讓我知道你是否需要一個例子。 – matth

相關問題