How do I dynamically reload the app.config in a .net Windows application? I need to turn logging on and off dynamically and not just based upon the value at application sta
Following is the hack which you can put this will make config to read from disk.
You just need to save the config file in Modified Mode and then refresh this will make application to read the file agian from the disk.
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
I wrote this implementation to change the log level at runtime and persist the new treshold back to the app.config (actually the Application.exe.config).
The interface:
internal interface ILoggingConfiguration
{
void SetLogLevel(string level);
string GetLogLevel();
}
The implementation:
internal sealed class LoggingConfigurationImpl : ILoggingConfiguration
{
#region Members
private static readonly ILog _logger =
ObjectManager.Common.Logger.GetLogger();
private const string DEFAULT_NAME_SPACE = "Default.Name.Space";
#endregion
#region Implementation of ILoggingConfiguration
public void SetLogLevel(string level)
{
Level threshold = Log4NetUtils.ConvertToLevel(level);
ILoggerRepository[] repositories = LogManager.GetAllRepositories();
foreach (ILoggerRepository repository in repositories)
{
try
{
SetLogLevelOnRepository(repository, threshold);
}
catch (Exception ex)
{
_logger.ErrorFormat("Exception while changing log-level: {0}", ex);
}
}
PersistLogLevel(level);
}
public string GetLogLevel()
{
ILoggerRepository repository = LogManager.GetRepository();
Hierarchy hierarchy = (Hierarchy) repository;
ILogger logger = hierarchy.GetLogger(DEFAULT_NAME_SPACE);
return ((Logger) logger).Level.DisplayName;
}
private void SetLogLevelOnRepository(ILoggerRepository repository,
Level threshold)
{
repository.Threshold = threshold;
Hierarchy hierarchy = (Hierarchy)repository;
ILogger[] loggers = hierarchy.GetCurrentLoggers();
foreach (ILogger logger in loggers)
{
try
{
SetLogLevelOnLogger(threshold, logger);
}
catch (Exception ex)
{
_logger.ErrorFormat("Exception while changing log-level for
logger: {0}{1}{2}", logger, Environment.NewLine, ex);
}
}
}
private void SetLogLevelOnLogger(Level threshold, ILogger logger)
{
((Logger)logger).Level = threshold;
}
private void PersistLogLevel(string level)
{
XmlDocument config = new XmlDocument();
config.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
string xpath =
String.Format("configuration/log4net/logger[@name='{0}']/level",
DEFAULT_NAME_SPACE);
XmlNode rootLoggerNode = config.SelectSingleNode(xpath);
try
{
rootLoggerNode.Attributes["value"].Value = level;
config.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("log4net");
}
catch(Exception ex)
{
_logger.ErrorFormat("error while persisting new log-level: {0}", ex);
}
}
#endregion
}
The helper class Log4NetUtils:
public sealed class Log4NetUtils
{
private static readonly ILoggerRepository _loggerRepository =
LoggerManager.GetAllRepositories().First();
public static Level ConvertToLevel(string level)
{
return _loggerRepository.LevelMap[level];
}
}
The XAML code:
<ComboBox Name="cbxLogLevel" Text="{Binding LogLevel}">
<ComboBoxItem Content="DEBUG" />
<ComboBoxItem Content="INFO" />
<ComboBoxItem Content="WARN" />
<ComboBoxItem Content="ERROR" />
</ComboBox>
<Button Name="btnChangeLogLevel"
Command="{Binding SetLogLevelCommand}"
CommandParameter="{Binding ElementName=cbxLogLevel, Path=Text}" >
Change log level
</Button>
Actually using an:
Application.restart();
Has worked pretty good for me.
Regards
Jorge
I think I read in the log4net documentation that this is not possible.
Try having the logging in an external logfile that can be watched with a filesystemwatcher
Update: Found it again.. http://logging.apache.org/log4net/release/manual/configuration.html#.config%20Files
There is no way to reload the app.config during runtime.