You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4net-dev@logging.apache.org by "Whitner, Tom" <To...@FMR.com> on 2005/01/18 22:40:27 UTC

RE: WMI Appender - More ramblings

Yeah, this really is a challenge.  Sooner or later something needs to be
aware of WMI.  With respect to some of the questions you raise, it is
interesting to note that Microsoft themselves don't have a great
solution either.  They attempted to produce a somewhat standardized
event schema with their EIF offering, but EIF is not really recommended
any longer.  In PAG's latest effort Enterprise Library, they take the
approach of a single WMI Event class which essentially mirrors log4net's
LoggingEvent class in principle.  Either way, both the WMI Event
producer and consumer must be aware of the WMI event schema.  This
probably means that you can't dynamically define WMI Events that are
useful to anyone else.  I think there is value in allowing different
event classes to be fired.  From a WMI Event consumer perspective, you'd
probably want to receive as few events as possible (filtering can be
done via WMI infrastructure based on event type) rather than receiving
all events and then filtering based on event data.  

We are seeing a similar problem with the Event Id for the Windows Event
log.  The solutions that I have seen so far require you to place an
additional layer on top of log4net in order to pass data through it.
Here again, I thought that passing a specialized object through log4net
targeted at a particular appender might solve the problem more
elegantly.  In either case, the client is aware that it must pass an
Event Id.  The basic issue seems to be that certain appenders provide
functionality that is not represented in the basic logging interface.

The more I think about this, the more it seems reasonable for the client
code to know about the extra information that it is attempting to log.
It is, in fact, the originator of the logging request.  If a particular
appender can not support a certain piece of data, so be it.  What would
happen to any standard object if it were passed to log4net.  I assume
that it would either call ToString() or an appropriate layout would be
used.  Either of these methods will work with WMI Event objects.  In
fact, I have used the ConsoleAppender and XmlLayout in testing the code
I sent earlier.  They log the WMI Event classes just fine.

-----Original Message-----
From: Nicko Cadell [mailto:nicko@neoworks.com] 
Sent: Tuesday, January 18, 2005 1:42 PM
To: Log4NET Dev
Subject: RE: WMI Appender

Tom, Thanks for sharing the code and ideas. I think WMI is an area where
we could do a lot more integration work.

I think that your approach is valid, but does still run into the same
problems.

Basically using your appender the caller has to construct their WMIable
object and pass it to log4net. If the event is delivered to the appender
then Instrumentation.Fire is called with the message object. Log4net is
being used only as a configurable switch.
The message object is not necessarily compatible with other appenders -
this could be overcome with custom ObjectRenderers. The biggest drawback
is that the appender does not work with any other type of message data,
therefore it cannot be use in conjunction with exiting applications that
have logging.

There are a number of possible approaches that need to be considered:

* There is the method that you have proposed where the caller has to
generate an WMI aware object, pack it with the right data, and then log
it.

* Another approach is to have a single WMI aware type within the
appender. For each event the appender creates a new (or maybe reuses)
one of these object, populates it with all the data from the logging
event, then fires it. This means that the layout of the WMI event will
be the same for all users and event types. Depending on the way WMI is
used this may not be appropriate.

* Yet another approach is to have the appender accept any message, then
pass it to a 3rd party factory object that will convert the logging
event into a WMI compatible object. The appender would need to be
configured with the type of the 3rd party converter object. This would
give the flexibility required, but it does require custom code to get
the base case working.

* An ideal solution would be to specify the format of the WMI message in
the config for the appender. The appender would perform the mapping from
the logging event into the WMI message similarly to the way in which the
AsoNetAppender uses the PatternLayout to setup the stored procedure
parameters. The difficulty with this is that it can't use the
Instrumentation.Fire method to raise the event, we would need to get in
at a lower level where the WMI message exists as data rather than as an
object.

Are there any WMI experts out there who would know if an app should fire
different types of object for different events? Are there standard WMI
schemas that the application needs to conform to?

In the long term I would prefer a solution that used a 3rd party factory
to convert the event into a WMI object, rather than one that required
the user to change all their logging calls to pass WMI objects.

What are your thoughts on this?

Nicko

> -----Original Message-----
> From: Whitner, Tom [mailto:Tom.Whitner@FMR.com] 
> Sent: 18 January 2005 17:17
> To: log4net-dev@logging.apache.org
> Subject: WMI Appender
> 
> 
>         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(InstrumentationClassAtt
> ribute), 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."); 
>                         } 
>                 } 
>         }
> } 
> 
>