I have been experimenting with WMI and log4net. I noticed that work on the WMI Appender is postponed. "Because of the way that a managed WMI schema must be registered with the system (using assembly attributes) there seems little scope for a generic appender for WMI. The immediate plan is to look at generating a sample appender that does WMI."
I have created a generic appender class that "Fires" WMI Events and does not require registering as mentioned previously. The WMI Events themselves must be published, but they exist in client/consumer code not within log4net. Essentially, this class looks at the original object that was logged (loggingEvent.MessageObject) and using reflection, determines if it is a WMI Instrumentation class. If it is, it fires it. I have included the code below for review. Is this a viable approach to providing WMI functionality to log4net? I am concerned that my approach may violate principles that I am not aware of. BTW, I am aware that there are improvements that must be made such as caching and exception handling. This was intended to demonstrate the concept.
Thanks,
Tom Whitner
/// <summary>
/// A log4net appender that fires WMI Events
/// </summary>
public class WMIAppender : AppenderSkeleton
{
/// <summary>
/// Default Constructor
/// </summary>
public WMIAppender()
{
}
/// <summary>
/// "Appends" WMI events by firing them.
/// </summary>
/// <param name="loggingEvent">The logging event to append.</param>
/// <remarks>Non-Wmi events will not be fired.</remarks>
protected override void Append(LoggingEvent loggingEvent)
{
if (IsWmiEvent(loggingEvent.MessageObject))
{
// TODO: Add exception handling in case schema
// was not published.
Instrumentation.Fire(loggingEvent.MessageObject);
}
}
/// <summary>
/// Verifies that <see cref="Append(LoggingEvent)"/> should occur.
/// </summary>
/// <returns></returns>
protected override bool PreAppendCheck()
{
// PreAppendCheck() should return false for non-WMI event objects.
// However, if does not have access to the loggingEvent.
// Therefore, the check must currently be done in Append().
return base.PreAppendCheck ();
}
/// <summary>
/// Determine if the specified object is a WMI Event.
/// </summary>
/// <param name="o">The object to test.</param>
/// <returns></returns>
protected bool IsWmiEvent(object o)
{
// TODO: Lookup class in cache; return and exit if found.
// This attribute may only occur once.
object[] attributes = o.GetType().GetCustomAttributes(typeof(InstrumentationClassAttribute), true);
switch (attributes.Length)
{
case 0:
{
// no attribute present = non wmi class
return false;
}
case 1:
{
bool isWmiEvent = false;
// we have one attribute. Now test for instumentation type.
// only events can be fired.
InstrumentationClassAttribute ica = (InstrumentationClassAttribute)attributes[0];
if (ica.InstrumentationType == InstrumentationType.Event)
{
isWmiEvent = true;
}
// TODO: Cache results for next time.
return isWmiEvent;
}
default:
{
// by definition, this attrbiute can only appear once.
throw new ApplicationException("Multiple InstrumentationClassAttributes attached.");
}
}
}
}
