If I wanted to add this additional snippet to my configuration which would
automatically call Flush on some buffered appenders at the given interval:
<flushBufferingAppendersTimer>
<interval value="5000" />
<appender-ref ref="BufferingAppender1" />
<appender-ref ref="BufferingAppender2" />
</flushBufferingAppendersTimer>
my code would look something like this (I need two classes because the
Hierarchy and the way its configured are currently two seperate classes):
// untested
public class FlushBufferingAppendersTimerHierarchy : Hierarchy
{
private Timer timer = null;
private FlushBufferingAppendersTimerXmlHierarchyConfigurator
configurator;
// this method was added to allow a custom configuration instance
public override XmlHierarchyConfigurator
CreateXmlHierarchyConfigurator(Hierarchy hierarchy)
{
hierarchy.ConfigurationChanged += new
LoggerRepositoryConfigurationChangedEventHandler(hierarchy_ConfigurationChanged);
configurator = new
FlushBufferingAppendersTimerXmlHierarchyConfigurator(hierarchy);
return configurator;
}
private void hierarchy_ConfigurationChanged(object sender, EventArgs e)
{
if (timer != null)
{
timer.Stop();
}
timer = new Timer();
timer.Interval = configurator.Interval;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
foreach (BufferingAppenderSkeleton bufferingAppender in
configurator.BufferingAppendersToFlush)
{
bufferingAppender.Flush();
}
}
}
public class FlushBufferingAppendersTimerXmlHierarchyConfigurator :
XmlHierarchyConfigurator
{
private AppenderCollection bufferingAppendersToFlush = new
AppenderCollection();
private double interval = 5000;
public FlushBufferingAppendersTimerXmlHierarchyConfigurator(Hierarchy
hierarchy)
: base(hierarchy)
{
// empty
}
public override void ParseUnknownElement(XmlElement xmlElement,
Hierarchy hierarchy)
{
if (xmlElement.LocalName == "flushBufferingAppendersTimer")
{
foreach (XmlNode currentNode in xmlElement.ChildNodes)
{
if (currentNode.NodeType == XmlNodeType.Element)
{
// TODO: add code to parse the <interval> node
XmlElement appenderRef = (XmlElement) currentNode;
BufferingAppenderSkeleton bufferingAppender =
FindAppenderByReference(appenderRef) as
BufferingAppenderSkeleton;
if (bufferingAppender != null)
{
bufferingAppendersToFlush.Add(bufferingAppender);
}
}
}
}
else
{
base.ParseUnknownElement(xmlElement, hierarchy);
}
}
public AppenderCollection BufferingAppendersToFlush
{
get { return this.bufferingAppendersToFlush; }
}
public double Interval
{
get { return this.interval; }
}
}
You could write something similiar to automatically delete, move, compress,
etc. old log files at a given interval on a different thread within log4net
without the application having to worry about that.
The code is quite long :-( If things were done with plugins it would be
possible to retrieve the plugin from the repository and change its properties
during the application's lifetime similiar to how you can retrieve an
IHttpModule by name and call methods on it:
// might appear in an admin area for an ASP.Net application
GZippedPageOutput gZippedPageOutput =
(GZippedPageOutput)Context.ApplicationInstance.Modules["GZippedPageOutput"];
gZippedPageOutput.CompressionLevel = 2;
// might appear on an admin screen for your application
FlushBufferingAppendersPlugin flusher =
(FlushBufferingAppendersPlugin)LogManager.GetRepository().PluginMap["FlushBufferingAppendersPlugin"];
// calls Stop, sets Timer.Interval to the new value, then calls Start
flusher.SetInterval(10000);
The plugin architecture would allow you to add multiple plugins (compress old
log files, flush buffers at a given internval, retrieve logging statistics,
etc.) and easily retrieve them by name. Going back my recent post on
plugins...I can't figure out a good way to allow plugins to hook into the
configuration process parse the raw configuration file.
Comments?
----- Original Message ----
From: Igor Trofimov <[EMAIL PROTECTED]>
To: Log4NET User <[email protected]>
Sent: Friday, December 22, 2006 2:08:57 AM
Subject: Re: XmlHierarchyConfigurator
Yes! It would be great!
And what about this small modification? :)
2006/12/22, Ron Grabowski <[EMAIL PROTECTED]>: The call to SetParameter
(XmlHierarchyConfigurator.cs:185) in the foreach loop inside the Configure
method could be replaced with a call to ParseUnknownElement:
protected virtual ParseUnknownElement(XmlElement xmlElement, Hierarchy
hierarchy)
{
SetParameter(xmlElement, hierarchy);
}
to match ParseLogger, ParseRenderer, etc. That would allow you do extend
XmlHierarchyConfigurator and do custom processing on user defined top level
elements. The default behavior of calling SetParameter would remain the same.
----- Original Message ----
From: Igor Trofimov <[EMAIL PROTECTED]>
To: Log4NET User <[email protected] >
Sent: Sunday, December 17, 2006 1:37:21 PM
Subject: Re: XmlHierarchyConfigurator
Well, i want to add recognition of my specific elements in hierarchy
configuration, similar to <logger>.
And this elements can contain <appender-ref> elements (just as logger do)
with reference to some appender - so, i can't use default capabilities of
SetParameter - there can't be sutable add-method for "appender-ref".
---------------
You wrote to "Log4NET User" < [email protected]> on Sun, 17 Dec
2006 10:02:22 -0800 (PST):
RG> XmlHierarchyConfigurator seems like a fairly complex class that was
RG> designed to parse a particular file structure without much thought for
RG> extensibility (its probably not a good thing to encourage people to use
RG> their own slightly different configuration file structure). Take the
RG> SetParameter method for example...making that virtual (~250 lines)
RG> would allow you to change how parameters are set but my guess is that
RG> you'd still need to copy and paste a lot of that code to get your
RG> override to perform similiar to the base method.
RG> What parts of XmlHierarchyConfigurator do you want to override?