When to use which XPath replacements

The reason I’m given that Microsoft has not documented the XML schemas for all the data types is that they are massively complex and simply hard to document.  Baelson once told me that "the schema document is this big" holding his hands about 14 inches apart to show the size of the stack of the paper on which the schema document could be printed.

Part of the problem is that different terms are overloaded (such as "Context") and part of it is the way data types are embedded on the fly in other data types.  When you map one data type to another using the mapper modules, the original data item is preserved inside an XML tag of the resultant data item.  For example, the WMI Event Provider has several lower-level modules under the covers, including a scheduler, a WMI probe, and a mapper module that "converts" the data returned from the WMI probe from PropertyBag data to Event data.  Mappers allow you to use values from the source data (WMI-based PropertyBag) in the output datatype.  You might use a WMI object property called "LoginName" and use that in your UserName property commonly found in Windows event.

As I mentioned, though, the PropertyBag data is not discarded, it’s embedded.

System.Event.Data represents an event.  The schema seems simple.  Just some properties you would expect in an event, and their values.  There’s no room in here for all the depth of properties you can get from a WMI object.

<DataItem type="System.Event.Data" time="2008-09-11T11:40:27.6416741-07:00" sourceHealthServiceId="093355C8-0283-EED8-A6BB-393E82B1FA19">
    <EventOriginId>{3EBC852F-A43A-D242-83C4-BFA1A9C1137E}</EventOriginId>
    <PublisherId>{84353FF2-9586-C4C3-C231-1D80818E57CB}</PublisherId>
    <PublisherName>WmiEventProvider</PublisherName>
    <EventSourceName>WmiEventProvider</EventSourceName>
    <Channel>WmiEventProvider</Channel>
    <LoggingComputer />
    <EventNumber>0</EventNumber>
    <EventCategory>3</EventCategory>
    <EventLevel>0</EventLevel>
    <UserName />
    <RawDescription />
    <CollectDescription Type="Boolean">true</CollectDescription>
    <EventData>
Trimmed for readability
    </EventData>
    <EventDisplayNumber>0</EventDisplayNumber>
    <EventDescription />
</DataItem>

The sticky thing happens when you drill into Trimmed for readability.  You see, a whole other data item can go in there, such as an event, or in the case of the XML I am using, a PropertyBag returned by the WMI event provider.  The full thing looks like this.

<DataItem type="System.Event.Data" time="2008-09-11T11:40:27.6416741-07:00" sourceHealthServiceId="093355C8-0283-EED8-A6BB-393E82B1FA19">
    <EventOriginId>{3EBC852F-A43A-D242-83C4-BFA1A9C1137E}</EventOriginId>
    <PublisherId>{84353FF2-9586-C4C3-C231-1D80818E57CB}</PublisherId>
    <PublisherName>WmiEventProvider</PublisherName>
    <EventSourceName>WmiEventProvider</EventSourceName>
    <Channel>WmiEventProvider</Channel>
    <LoggingComputer />
    <EventNumber>0</EventNumber>
    <EventCategory>3</EventCategory>
    <EventLevel>0</EventLevel>
    <UserName />
    <RawDescription />
    <CollectDescription Type="Boolean">true</CollectDescription>
    <EventData>
        <DataItem type="System.PropertyBagData" time="2008-09-11T11:40:27.6416741-07:00" sourceHealthServiceId="093355C8-0283-EED8-A6BB-393E82B1FA19">
            <Property Name="__CLASS" VariantType="8">AUDIT_LOGIN</Property>
            <Property Name="__DERIVATION" VariantType="8">TRC_SECURITY_AUDIT,TRC_ALL_EVENTS,ALL_EVENTS,__ExtrinsicEvent,__Event,__IndicationRelated,__SystemClass</Property>
            <Property Name="__DYNASTY" VariantType="8">__SystemClass</Property>
            <Property Name="__GENUS" VariantType="3">2</Property>
            <Property Name="__PROPERTY_COUNT" VariantType="3">24</Property>
            <Property Name="__SUPERCLASS" VariantType="8">TRC_SECURITY_AUDIT</Property>
            <Property Name="ApplicationName" VariantType="8">Microsoft (r) Windows Script Host</Property>
            <Property Name="BinaryData" VariantType="8">’ 32 (0x20),0 (0x0),0 (0x0),(‘ 40 (0x28),8′ 56 (0x38),ô’ 244 (0xF4),1 (0x1),0 (0x0),0 (0x0),0 (0x0),0 (0x0),0 (0x0)</Property>
            <Property Name="ClientProcessID" VariantType="3">3428</Property>
            <Property Name="ComputerName" VariantType="8">DBServer</Property>
            <Property Name="DatabaseID" VariantType="3">1</Property>
            <Property Name="DatabaseName" VariantType="8">master</Property>
            <Property Name="EventSequence" VariantType="3">3262</Property>
            <Property Name="HostName" VariantType="8">DBServer</Property>
            <Property Name="IntegerData" VariantType="3">4096</Property>
            <Property Name="IsSystem" VariantType="3">0</Property>
            <Property Name="LoginName" VariantType="8">MANAGE\administrator</Property>
            <Property Name="LoginSid" VariantType="8">1 (0x1),5 (0x5),0 (0x0),0 (0x0),0 (0x0),0 (0x0),0 (0x0),5 (0x5),21 (0x15),0 (0x0),0 (0x0),0 (0x0),¾’ 190 (0xBE),¾’ 190 (0xBE),Q’ 81 (0x51),‚’ 130 (0x82),¶’ 182 (0xB6),u’ 117 (0x75),19 (0x13),J’ 74 (0x4A),3′ 51 (0x33),³’ 179 (0xB3),*’ 42 (0x2A),1 (0x1),ô’ 244 (0xF4),1 (0x1),0 (0x0),0 (0x0)</Property>
            <Property Name="NTDomainName" VariantType="8">MANAGE</Property>
            <Property Name="NTUserName" VariantType="8">administrator</Property>
            <Property Name="PostTime" VariantType="7">09/11/2008 11:40:08</Property>
            <Property Name="RequestID" VariantType="3">0</Property>
            <Property Name="SessionLoginName" VariantType="8" />
            <Property Name="SPID" VariantType="3">53</Property>
            <Property Name="SQLInstance" VariantType="8">MSSQLSERVER</Property>
            <Property Name="StartTime" VariantType="7">09/11/2008 11:40:08</Property>
            <Property Name="Success" VariantType="3">1</Property>
            <Property Name="TextData" VariantType="8">– network protocol: TCP/IP set quoted_identifier on set arithabort off set numeric_roundabort off set ansi_warnings on set ansi_padding on set ansi_nulls on set concat_null_yields_null on set cursor_close_on_commit off set implicit_transactions off set language us_english set dateformat mdy set datefirst 7 set transaction isolation level read committed</Property>
            <Property Name="TIME_CREATED" VariantType="8">128656320086870915</Property>
        </DataItem>
    </EventData>
    <EventDisplayNumber>0</EventDisplayNumber>
    <EventDescription />
</DataItem>

So you see, the System.Event.Data dataitem contains a System.PropertyBag.Data dataitem.  The property bag is returned from an event class in the SQL Server namespace.  How the heck is anyone supposed to document how to get to a piece of detail data (such as the SPID property) when the propertybag contents are dependent on a WMI class, and therefore the event detail data is dependent on the WMI class?

The <DataItem> tag appears twice in the above XML, but you don’t use it in your XML path in OpsMgr.  The first one is always replaced with "$Data/".  After that, the path follows the document path identified in BoldBlue in the XML above.  To have the SPID number 53 in your alert text, you would use

$Data/EventData/DataItem/Property[@Name="SPID"]$

Notice that the second <DataItem> tag is actually in the path, while the first is not.

What makes it more fun is when you start to use XPathQuery’s for things like rules and monitors.  Now you drop the first <DataItem> entirely.  The WMI Event Provider module outputs System.Event.Data, so your query in the <XPathQuery> tags would be

EventData/DataItem/Property[@Name=’SPID’]

No dollar signs.  No leading $Data path component. 

 

As another example, Marius blogged about the Application log data type here.  In his example, System.ApplicationLog.GenericLogDataEntry was mapped into System.Event.Data.  If you were doing the mapping, you could map the "ERROR" property captured from the application text log and stuff it into the ErrorLevel property of the Windows-style Event.  You can still get to the original property using

$Data/EventData/DataItem/Params/Param[2]$

Parameters are generally reliably ordinal, so you can hardcode the ordinal number this way.  I ran into a lot of interesting issues with regard to this when I was doing a lot of work with the OleDB data providers.

Getting this data is often difficult.  One way to figure out what your datatype looks like is to create a rule on it at a provider level.  In other words, create an alert rule that will raise an alert on the source of your data without doing any filtering.  To get the WMI PropertyBag example, I created an alert rule that did nothing more than use the namespace

root\Microsoft\SqlServer\ServerEvents\MSSQLSERVER

and the very basic WMI query

select * from AUDIT_LOGIN

That created an alert in OpsMgr.  The information does show up in relatively friendly display in the alerts view details, but tells nothing about the XPath.  From here, it’s off to the database!

The Alerts table contains all alerts, as you might suspect.  The Context column contains the dataitem that raised the alert.  With that detail, you could start to drill into XPathQuery syntax for filtering, and XPath for parameter replacement in the alert description.

In nearly all cases, there is a Context component of the path when the alert was raised when a monitor changed state.  Usually this is in the form of

$Data/Context/EventData/DataItem/Property[@Name=’SPID’]$

But in the case of some other things like MonitorTaskDataType, Context is buried a little further down in the path because of the multiple levels of embedding that have happened by the time this datatype is created.  See Marius’ note on this for the XML.

Feel free to post questions.  I’m interested in getting this article a little more fleshed out.

 

Update: Useful link to Kevin Holman’s site: http://blogs.technet.com/kevinholman/archive/2007/12/12/adding-custom-information-to-alert-descriptions-and-notifications.aspx

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

4 Responses to When to use which XPath replacements

  1. Unknown says:

    Nice write-up.  I had not thought to look at the raw data in the database.  I had wondered how people were getting their hands on the raw xml to write the xpath queries.Chad

  2. Tim McColl says:

    The way I’ve found as useful to see what the DataItem XML will look like from a data source is to have a rule call the data source and use the System.Event.GenericDataMapper condition and then write to the event collection. If you view the events in the console there will be a hyperlink in the event details view that shows the full data item XML in IE. This is very useful when dealing with the Microsoft.SystemCenter.WebApplication.UrlProbe and System.OleDbProbe probes.

  3. Pingback: OpsMgr 2007 Base Concepts and Helpful Links « windowsmasher

  4. Pingback: OpsMgr 2007 Base Concepts and Helpful Links « Vinachip

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s