When using LogWriter.Configure() is there a way to save original configuration and restore it?

Topics: Logging Application Block
Mar 18, 2014 at 4:38 PM
Edited Mar 18, 2014 at 10:04 PM
I'm successfully using LogWriter.Configure() to add trace listeners at runtime but I'd also like to be able to save the original configuration and later on restore the original configuration.

LogWriter.Configure() allows updating the current LoggingConfiguration, is there a way to first save a deep copy of the current LoggingConfiguration?

Is there a way to later overwrite the temporary LoggingConfiguration with the original LoggingConfiguration?

I don't see a copy constructor for LoggingConfiguration or any copy/import operator.
Mar 19, 2014 at 6:27 AM
Edited Mar 19, 2014 at 6:28 AM
Can you expand on the exact scenario? What are you trying to achieve? Also, how do you configure the block initially, how often do you need to configure and then revert the configuration, etc.?

One approach you could take is to use a factory to create a LogWriter but keep a reference to the factory. When you need to reconfigure use the LogWriter.Configure() method to change the configuration. In order to revert, Dispose of the LogWriter and create the original LogWriter using the factory. If you need to get back to some intermediate configuration you could keep track of a List<LoggingConfiguration> and re-apply each configuration. It's not particularly elegant but it should work.
LogWriter defaultWriter = null;

SystemConfigurationSource configSource = new SystemConfigurationSource();
LogWriterFactory factory = new LogWriterFactory(configSource);
LogWriter writer1 = factory.Create();

defaultWriter = writer1;

defaultWriter.Write("test", "General");

defaultWriter.Configure(config =>
    {
        config.AllTraceListeners.Where(t => t.Name == "Flat File Trace Listener").First().Dispose();

        config.LogSources.Clear();
        config.AddLogSource("General", SourceLevels.All, true)
            .AddTraceListener(new FlatFileTraceListener(
                @"FlatFile.log", 
                "----------------------------------------", 
                "----------------------------------------"));
    });

defaultWriter.Write("Test!", "General");
defaultWriter.Dispose();

// "Reset" to original
defaultWriter = factory.Create();

defaultWriter.Write("Another Test", "General");
Another alternative might be to create separate LogWriters and select the appropriate LogWriter at runtime based on some criteria (depending on the scenario)

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Mar 20, 2014 at 3:39 PM
For normal execution we don't need to alter the configuration but for various Unit Tests we first alter the configuration and then change it back. With Enterprise Library 5 we were able to do this via the Fluent Configuration API for logging.

We have a class that wraps LogWriter so our Unit Tests are not able to control creation of new LogWriter instances for various configurations.
Mar 21, 2014 at 1:36 AM
Edited Mar 21, 2014 at 1:36 AM
OK, that makes sense for unit testing.

Enterprise Library 6 still supports fluent configuration so I would think that you should be able to use the same approach as with Enterprise Library 5.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Mar 21, 2014 at 4:43 PM
Edited Mar 21, 2014 at 4:52 PM
Previously I was setting the programmatic configuration and later restoring the previous configuration via EnterpriseLibraryContainer which no longer exists in version 6. How would I do the following in Enterprise Library 6?

ConfigurationSourceBuilder builder = new ConfigurationSourceBuilder();

builder.ConfigureLogging()
   ... // Programmatic configuration calls omitted for brevity.
DictionaryConfigurationSource configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);

IServiceLocator previousEnterpriseLibraryContainer = EnterpriseLibraryContainer.Current;
EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);

...

EnterpriseLibraryContainer.Current = previousEnterpriseLibraryContainer;
Mar 22, 2014 at 6:22 AM
Not sure about your logger implementation. I'm going to assume that you are using the static Logger facade to get the LogWriter instead of the EnterpriseLibraryContainer.

So you could do a variation on what I posted above:
    public class MyLogger
    {
        public void LogIt(string message)
        {
            Logger.Write(message, "General");
        }
    }

    private LogWriterFactory Configure(string fileName)
    {
        ConfigurationSourceBuilder builder = new ConfigurationSourceBuilder();

        builder.ConfigureLogging()
                .WithOptions
                .LogToCategoryNamed("General")
                    .WithOptions.SetAsDefaultCategory()
                    .SendTo.FlatFile("Flat File")
                        .ToFile(fileName);

        DictionaryConfigurationSource configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);
        LogWriterFactory factory = new LogWriterFactory(configSource);

        return factory;
    }

    MyLogger myLogger = new MyLogger();

    LogWriterFactory originalFactory = Configure("trace.log");
    Logger.SetLogWriter(originalFactory.Create(), false);

    myLogger.LogIt("original file");

    LogWriterFactory newFactory = Configure("newTrace.log");
    Logger.SetLogWriter(newFactory.Create(), false);

    myLogger.LogIt("new file");

    Logger.SetLogWriter(originalFactory.Create(), false);
    
    myLogger.LogIt("back to original file");

How your logger class gets access to the LogWriter instance is the key to making it work.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to