I want to define a handful of (ADO.NET) appenders in my library, but allow users of my library to configure the use of those appenders. Something like this seems to be what I want:
XmlConfigurator.Configure(appenderStream1);
XmlConfigurator.Configure(appenderStream2);
XmlConfigurator.Configure();
But that doesn't seem to work, in spite of the debug output containing messages like this:
Configuration update mode [Merge].
What is the right way to do this? Or, is there an alternative to asking users to duplicate large chunks of XML configuration?
Solution: Thanks to Stephan's suggestion, I was able to implement the following log initialization method. It first reads the .config section into an XmlDocument
and then adds external appenders (which are in my case embedded resources) to the document, finally feeding the whole lot to log4net.
static readonly string[] AppenderConfigs =
{
"Logging.EntryPointAppender.xml",
"Logging.TracingAppender.xml",
"Logging.MessagesAppender.xml",
};
public static void Initialize()
{
// this first bit reads the log4net config in the application's config file
var section = (XmlElement)ConfigurationManager.GetSection("log4net");
if (section == null)
return;
XmlDocument xml = new XmlDocument();
using (var xml_reader = new XmlNodeReader(section))
xml.Load(xml_reader);
// then we augment the above XML with the content of our embedded resources
foreach (var appender_config in AppenderConfigs)
using (var stream = EmbeddedResource.Open("My.Assembly", appender_config))
AddToConfig(xml, stream);
XmlConfigurator.Configure(xml.DocumentElement);
}
static void AddToConfig(XmlDocument config, Stream xmlStream)
{
var fragment = config.CreateDocumentFragment();
using (var reader = new StreamReader(xmlStream))
fragment.InnerXml = reader.ReadToEnd();
config.LastChild.AppendChild(fragment);
}