2009-04-10 9 views
14

Je recherche des conseils sur la meilleure façon de reconfigurer dynamiquement le niveau de journalisation Log4Net dans mes applications ASP.NET. J'utilise généralement une configuration simple où l'enregistreur racine définit le niveau de journalisation par défaut, par ex.Reconfigurer dynamiquement Log4Net

<log4net> 
    <root> 
    <level value="INFO" /> 
    <appender-ref ref="..." /> 
    <appender-ref ref="..." /> 
    ... etc ...  
    </root> 
    ... etc 

et il peut y avoir plusieurs appenders, chacun avec des filtres pour définir les niveaux de journalisation qu'ils utilisent.

  1. La première chose que je voudrais être en mesure de le faire serait de permettre aux administrateurs de se connecter à une page d'administration qui leur permet de (a) voir le niveau actuel de l'enregistreur de racine et (b) dynamiquement changes le. Je ne veux pas utiliser "ConfigureAndWatch" et écrire dans le fichier de configuration sur le disque car je ne veux pas que ces modifications persistent lorsque l'application est recyclée. Ensuite, je voudrais aller plus loin, et sur une page Admin, je peux afficher un TreeView avec tous les Loggers existants dans l'application, et leur niveau d'enregistrement actuel. Et permettre à l'administrateur de pouvoir modifier le niveau de consignation de manière sélective à n'importe quel niveau de la hiérarchie.

L'idée est de créer une page d'administration générique que je peux mettre dans toutes mes applications qui permet aux administrateurs d'activer sélectivement l'enregistrement de niveau DEBUG dynamique à des fins de dépannage. Je trouve les API Log4Net un peu déroutantes, quelqu'un peut-il pointer vers des échantillons ou montrer le meilleur moyen d'y parvenir.

Mise à jour:

Les deux réponses sont aussi bons, donc je l'ai accepté le premier - merci. Pour reprendre, je peux obtenir tous les enregistreurs actuels comme suit:

foreach (log4net.ILog log in log4net.LogManager.GetCurrentLoggers()) 
{ 
    log4net.Repository.Hierarchy.Logger logger = 
     (log4net.Repository.Hierarchy.Logger)log.Logger; 
    Debug.WriteLine(
     String.Format("{0} Parent {1} Level {2} EffectiveLevel {3}<br>", 
     logger.Name, 
     logger.Parent.Name, 
     logger.Level == null ? "<null>" : logger.Level.Name, 
     logger.EffectiveLevel 
     ) 
     ); 
} 
  • EffectiveLevel est le niveau efficace - même que niveau si celui-ci est non nul, autrement hérité du parent.

  • Au moins un des loggers renvoyés ci-dessus aura l'enregistreur racine en tant que parent, ce qui me permet d'obtenir une référence à l'enregistreur racine.

Avec ce qui précède, il devrait être possible de reconstruire la hiérarchie de l'enregistreur.

Update 2

Merci encore. J'ai implémenté un contrôle serveur ASP.NET qui affiche la hiérarchie du journal dans une TreeView avec des cases à cocher, et permet à l'utilisateur de modifier dynamiquement le niveau de journalisation à n'importe quel nœud de la hiérarchie. Fonctionne très bien et je vais le mettre sur la page d'administration dans toutes mes applications Web ASP.NET et Web Service!

Répondre

8

Vous cherchez quelque chose comme ceci (code non testé):

foreach (ILog logger in log4net.LogManager.GetCurrentLoggers()) 
{ 
    ((log4net.Repository.Hierarchy.Logger)logger).Level = 
     log4net.Core.Level.Error; 
} 

Vous pouvez évidemment retirer le nom de l'enregistreur, etc. de la même manière.

+0

J'ai testé le code ci-dessus et trouvé que je devais faire une boucle à travers tous les dépôts et vérifier le type. foreach (repo var dans LogManager.GetAllRepositories()) foreach (. Enregistreur de var dans repo.GetCurrentLoggers() OfType ()) = Niveau logger.level; –

+0

FYI: J'ai déjà rencontré des problèmes de concurrence lors de l'utilisation de l'API de configuration log4net dynamique - il ne semble pas être sûr pour les threads. – galaktor

+0

quelle version de log4net était-ce avec? Je ne vois aucune implémentation d'ILog qui peut être convertie en Repository.Hierarchy.Logger –

3

J'ai réussi à modifier par programme le niveau de journalisation d'un enregistreur log4net, mais il n'est pas évident de savoir comment le faire à partir de l'API publique. Compte tenu de ce logger:

private readonly log4net.ILog mylogger; 

Vous devez faire le jeu de jambes de fantaisie suivante pour définir à Debug:

((log4net.Repository.Hierarchy.Logger)mylogger.Logger).Level = 
log4net.Core.Level.Debug; 

Pour certaines situations - je ne sais pas ce qui cause cette exigence plus compliquée - vous devrez peut-être suivre les étapes supplémentaires indiquées dans l'article log4net and changing the logger levels.

2

Peut être pas tout à fait exactement ce que vous voulez, mais:

using System; 
using System.Collections.Generic; 
using System.Text; 
using log4net; 
using log4net.Config; 
using NUnit.Framework; 

namespace ExampleConsoleApplication 
{ 
    enum DebugLevel : int 
    { 
    Fatal_Msgs = 0 , 
    Fatal_Error_Msgs = 1 , 
    Fatal_Error_Warn_Msgs = 2 , 
    Fatal_Error_Warn_Info_Msgs = 3 , 
    Fatal_Error_Warn_Info_Debug_Msgs = 4 
    } 


    class TestClass 
    { 

     private static readonly ILog logger = 
       LogManager.GetLogger (typeof (TestClass)); 


     static void Main (string[] args) 
     { 
     TestClass objTestClass = new TestClass(); 

      Console.WriteLine (" START "); 

     int shouldLog = 4; //CHANGE THIS FROM 0 TO 4 integer to check the functionality of the example 
     //0 -- prints only FATAL messages 
     //1 -- prints FATAL and ERROR messages 
     //2 -- prints FATAL , ERROR and WARN messages 
     //3 -- prints FATAL , ERROR , WARN and INFO messages 
     //4 -- prints FATAL , ERROR , WARN , INFO and DEBUG messages 

     string srtLogLevel = String.Empty ; 
     switch (shouldLog) 
     { 
     case (int)DebugLevel.Fatal_Msgs : 
      srtLogLevel = "FATAL"; 
      break; 
     case (int)DebugLevel.Fatal_Error_Msgs: 
      srtLogLevel = "ERROR"; 
      break; 
     case (int)DebugLevel.Fatal_Error_Warn_Msgs : 
      srtLogLevel = "WARN"; 
      break; 
     case (int)DebugLevel.Fatal_Error_Warn_Info_Msgs : 
      srtLogLevel = "INFO"; 
      break; 
     case (int)DebugLevel.Fatal_Error_Warn_Info_Debug_Msgs : 
      srtLogLevel = "DEBUG" ; 
      break ; 
     default: 
      srtLogLevel = "FATAL"; 
      break; 
     } 

     objTestClass.SetLogingLevel (srtLogLevel); 


     objTestClass.LogSomething(); 


      Console.WriteLine (" END HIT A KEY TO EXIT "); 
      Console.ReadLine(); 
      } //eof method 

    /// <summary> 
    /// Activates debug level 
    /// </summary> 
    /// <sourceurl>http://geekswithblogs.net/rakker/archive/2007/08/22/114900.aspx</sourceurl> 
    private void SetLogingLevel (string strLogLevel) 
    { 
    string strChecker = "WARN_INFO_DEBUG_ERROR_FATAL" ; 

     if (String.IsNullOrEmpty (strLogLevel) == true || strChecker.Contains (strLogLevel) == false) 
     throw new Exception (" The strLogLevel should be set to WARN , INFO , DEBUG ,"); 



     log4net.Repository.ILoggerRepository[] repositories = log4net.LogManager.GetAllRepositories(); 

     //Configure all loggers to be at the debug level. 
     foreach (log4net.Repository.ILoggerRepository repository in repositories) 
     { 
     repository.Threshold = repository.LevelMap[ strLogLevel ]; 
     log4net.Repository.Hierarchy.Hierarchy hier = (log4net.Repository.Hierarchy.Hierarchy)repository; 
     log4net.Core.ILogger[] loggers = hier.GetCurrentLoggers(); 
     foreach (log4net.Core.ILogger logger in loggers) 
     { 
      ((log4net.Repository.Hierarchy.Logger)logger).Level = hier.LevelMap[ strLogLevel ]; 
     } 
     } 

     //Configure the root logger. 
     log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository(); 
     log4net.Repository.Hierarchy.Logger rootLogger = h.Root; 
     rootLogger.Level = h.LevelMap[ strLogLevel ]; 
    } 

    private void LogSomething() 
    { 
     #region LoggerUsage 
     DOMConfigurator.Configure(); //tis configures the logger 
     logger.Debug ("Here is a debug log."); 
     logger.Info ("... and an Info log."); 
     logger.Warn ("... and a warning."); 
     logger.Error ("... and an error."); 
     logger.Fatal ("... and a fatal error."); 
     #endregion LoggerUsage 

    } 
    } //eof class 

} //eof namespace 






#region TheAppConfig 
/* 
<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
     <section name="log4net" 
       type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> 
    </configSections> 
    <log4net> 
     <appender name="LogFileAppender" type="log4net.Appender.FileAppender"> 
      <param name="File" value="LogTest2.txt" /> 
      <param name="AppendToFile" value="true" /> 
      <layout type="log4net.Layout.PatternLayout"> 
       <param name="Header" value="[Header] \r\n" /> 
       <param name="Footer" value="[Footer] \r\n" /> 
       <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" /> 
      </layout> 
     </appender> 

     <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> 
      <mapping> 
       <level value="ERROR" /> 
       <foreColor value="White" /> 
       <backColor value="Red, HighIntensity" /> 
      </mapping> 
      <layout type="log4net.Layout.PatternLayout"> 
       <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 
      </layout> 
     </appender> 


     <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender"> 
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.2.10.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 
      <connectionString value="data source=ysg;initial catalog=DBGA_DEV;integrated security=true;persist security info=True;" /> 
      <commandText value="INSERT INTO [DBGA_DEV].[ga].[tb_Data_Log] ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" /> 

      <parameter> 
       <parameterName value="@log_date" /> 
       <dbType value="DateTime" /> 
       <layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" /> 
      </parameter> 
      <parameter> 
       <parameterName value="@thread" /> 
       <dbType value="String" /> 
       <size value="255" /> 
       <layout type="log4net.Layout.PatternLayout" value="%thread" /> 
      </parameter> 
      <parameter> 
       <parameterName value="@log_level" /> 
       <dbType value="String" /> 
       <size value="50" /> 
       <layout type="log4net.Layout.PatternLayout" value="%level" /> 
      </parameter> 
      <parameter> 
       <parameterName value="@logger" /> 
       <dbType value="String" /> 
       <size value="255" /> 
       <layout type="log4net.Layout.PatternLayout" value="%logger" /> 
      </parameter> 
      <parameter> 
       <parameterName value="@message" /> 
       <dbType value="String" /> 
       <size value="4000" /> 
       <layout type="log4net.Layout.PatternLayout" value="%messag2e" /> 
      </parameter> 
     </appender> 
     <root> 
      <level value="INFO" /> 
      <appender-ref ref="LogFileAppender" /> 
      <appender-ref ref="AdoNetAppender" /> 
      <appender-ref ref="ColoredConsoleAppender" /> 
     </root> 
    </log4net> 
</configuration> 
*/ 
#endregion TheAppconfig 

//this is the xml added replace here your log4net and Nunit paths 
//<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL"> 
     // <SpecificVersion>False</SpecificVersion> 
     // <HintPath>..\..\..\Log4Net\log4net-1.2.10\bin\net\2.0\release\log4net.dll</HintPath> 
     //</Reference> 
     //<Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />