At this point, I have not used WMI to monitor applications either. I have done a fair amount of experimenting from the application architect / developer perspective. We are in the process of standardizing our .NET infrastructure, both at the code level (i.e. log4net) and at the service level (i.e. monitoring). Hence there is a natural synergy in this specific area.
In general, I agree with the direction you outline below. However, I have a couple of observations regarding it. 1. Introducing an appender that can fire WMI events creates a dependency on the System.Management assembly. Further, adding a standard WMI event class that can be fired requires installation of the assembly (via InstallUtil.exe or MSI for instance) as well as creates a dependency on the System.Configuration.Install assembly. 2. What is the relationship between the standard and custom events? Should custom events be derived from or aggregate a standard event so that they will contain the standard logging information? If a custom event does neither, then it would likely not contain standard information like date/time, thread id, application name, etc. Another alternative might be to raise two events (custom and standard), but this would likely be hard to correlate and understand from a monitoring perspective. At this point, I think this would be best attempted as a standard extension to log4net rather than trying to bake it in. Do you have standard for how something like this should be done? I would like to go ahead an prototype this a little further. - Tom -----Original Message----- From: Nicko Cadell [mailto:[EMAIL PROTECTED] Sent: Thursday, January 20, 2005 9:14 AM To: Log4NET Dev Subject: RE: WMI Appender - More ramblings I should point out that I have very little experience with using WMI to manage application reporting, especially in a larger environment. If the user wants to log additional data then it is reasonable to use an extension or for them to pass a custom object as the message. If you want to log a specific set of additional data via WMI then it is reasonable to create a custom object with the data and pass that to log4net. There are many situations where the user does not want to log additional data, but just wants to publish it via WMI. In this case I don't see why the calling app should need to know about WMI or WMIing an object. Also there is a requirement to WMI enable an existing application. For example, an administrator may want application errors notified via WMI so that IT staff may take appropriate action. In general appenders should make use of additional data if it is supplied, but not rely on it, they should have a reasonable default behaviour when that data is not available. For the WMI appender reasonable behaviour seems to be: If the calling app passes in a custom object that can be passed to WMI then this object should be fired directly. If the message object is not compatible with WMI then the appender should create some standard event that can be published via WMI. This means that the calling app has fine control if they need it, but in the general case it is possible to use WMI for other types of event. This is similar to the EventLogAppender which will publish the event to the event log with or without the Event Id. Is that the right way to go? Nicko > -----Original Message----- > From: Whitner, Tom [mailto:[EMAIL PROTECTED] > Sent: 18 January 2005 21:40 > To: Log4NET Dev > Subject: 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:[EMAIL PROTECTED] > 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:[EMAIL PROTECTED] > > Sent: 18 January 2005 17:17 > > To: [email protected] > > 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."); > > } > > } > > } > > } > > > > > >
