Extending Discovery Of Java Applications in SCOM 2012

The solution to monitoring JEE Application Servers and Applications in SCOM 2012 is a good starting point, but sometimes you may want to do more.  The good news is that the structure of theses MPs are extendable and this blog post will detail how to do that.

For instance, let’s suppose that I am a customer with my own Contoso (see https://blogs.technet.com/b/random_happy_dev_thoughts/archive/2012/03/26/sample-jee-application-contoso-order-service.aspx) application that I want to uniquely identify.  There is not a way to change the default JEE discovery exclude certain applications; however, what you can do is create a discovery to create your own extended version of the existing JEE objects.

For the example below I have written a custom discovery that targets the Microsoft.JEE.Application objects from the Microsoft.JEE.Library MP.  The discovery uses a simple condition detection module to filter on the name of the discovered application. The new class can be as simple as this:

 <ClassType 
 ID="Contoso.JEE.SampleApplication" 
 Abstract="false" 
 Accessibility="Public" Hosted="true"
 Base="JEE!Microsoft.JEE.Application" />
 

 The filtering is done in this library module where the TargetApplicationName is the application name that I want to find and ApplicationName is the name as reported from the object found by the existing Microsoft.JEE management packs.  There is a discovery that has the hardcode name of the application I want:

 

  <Discovery ID="Contoso.JEE.CustomOrderService.Discovery" Target="JEE!Microsoft.JEE.Application"
 Remotable="true" Enabled="true">
 <Category>Discovery</Category>
 <DiscoveryTypes>
 <DiscoveryClass TypeID="Contoso.JEE.SampleApplication" />
 </DiscoveryTypes>
 <DataSource ID="DS" TypeID="Contoso.JEE.SampleApplication.Discovery.DataSource">
 <ClassId>$MPElement[Name="Contoso.JEE.SampleApplication"]$</ClassId>
 <TargetApplicationName>CustomOrderService</TargetApplicationName>
 <ApplicationName>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ApplicationName$</ApplicationName>
 <DisplayName>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ApplicationName$</DisplayName>
 <ObjectName>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ObjectName$</ObjectName>
 <PrincipalName>$Target/Host/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</PrincipalName>
 <Id>$Target/Host/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Id>
 <j2eeType>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/j2eeType$</j2eeType>
 <IntervalSeconds>14400</IntervalSeconds>
 </DataSource>
 </Discovery>

 

And the discovery call this module that does the dirty work of filtering.

 

  <DataSourceModuleType ID="Contoso.JEE.SampleApplication.Discovery.DataSource" Accessibility="Public">
 <Configuration>
 <IncludeSchemaTypes>
 <SchemaType>System!System.ExpressionEvaluatorSchema</SchemaType>
 </IncludeSchemaTypes>
 <xsd:element name="ClassId" type="xsd:string" />
 <xsd:element name="TargetApplicationName" type="xsd:string" />
 <xsd:element name="ApplicationName" type="xsd:string" />
 <xsd:element name="DisplayName" type="xsd:string" />
 <xsd:element name="ObjectName" type="xsd:string" />
 <xsd:element name="PrincipalName" type="xsd:string" />
 <xsd:element name="Id" type="xsd:string" />
 <xsd:element name="j2eeType" type="xsd:string" />
 <xsd:element name="IntervalSeconds" type="xsd:integer" />
 </Configuration>
 <OverrideableParameters>
 <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" />
 </OverrideableParameters>
 <ModuleImplementation>
 <Composite>
 <MemberModules>
 <DataSource TypeID="Contoso.SpecializedClass.Discovery.DataSource" ID="Specializer">
 <ClassId>$Config/ClassId$</ClassId>
 <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
 <Expression>
  <RegExExpression> 
  <ValueExpression> 
  <Value>$Config/ApplicationName$</Value> 
  </ValueExpression> 
  <Operator>MatchesRegularExpression</Operator> 
  <Pattern>$Config/TargetApplicationName$</Pattern> 
  </RegExExpression> 
 </Expression>
 <InstanceSettings>
 <Settings>
 <!-- These properties are for the Application Server Instance -->
 <Setting>
 <Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Name>
 <Value>$Config/Id$</Value>
 </Setting>
 <Setting>
 <Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Name>
 <Value>$Config/PrincipalName$</Value>
 </Setting>
 <!-- The following properties are defined for the Application-->
 <Setting>
 <Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ApplicationName$</Name>
 <Value>$Config/ApplicationName$</Value>
 </Setting>
 <Setting>
 <Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/j2eeType$</Name>
 <Value>$Config/j2eeType$</Value>
 </Setting>
 <Setting>
 <Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ObjectName$</Name>
 <Value>$Config/ObjectName$</Value>
 </Setting>
 </Settings>
 </InstanceSettings>
 </DataSource>
 </MemberModules>
 <Composition>
 <Node ID="Specializer" />
 </Composition>
 </Composite>
 </ModuleImplementation>
 <OutputType>System!System.Discovery.Data</OutputType>
 </DataSourceModuleType>

  

Now that there is a discovery for my specific application, I can write rules specific to my new class.  Since this order service that I have already exposes some metrics that I want to a MBean, I’ll just write my own rule that will capture this performance data and store it in the Perf Store.

 

  <Rule ID="Contoso.JEE.SampleApplication.PerformanceData.AverageTransactionTime" Target="Contoso.JEE.SampleApplication"
 Enabled="true" Remotable="true">
 <Category>PerformanceCollection</Category>
 
 <DataSources>
 <DataSource ID="DS" TypeID="JEE!Microsoft.JEE.Monitoring.UrlProbe.MBeans.DataSource">
 <ComputerName>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/HostName$</ComputerName>
 <Protocol>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Protocol$</Protocol>
 <Port>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Port$</Port>
 <BaseURL />
 <JMXQuery>com.contoso:Name=CustomPerformance,*</JMXQuery>
 <AdditionalArguments>&amp;MaxDepth=1</AdditionalArguments>
 <IntervalSeconds>300</IntervalSeconds>
 <TimeoutSeconds>100</TimeoutSeconds>
 </DataSource>
 </DataSources>
 
 <ConditionDetection TypeID="Performance!System.Performance.DataGenericMapper" ID="PerfMapper">
 <ObjectName>AverageTransactionTime</ObjectName>
 <CounterName>AverageTransactionTime</CounterName>
 <InstanceName />
 <Value>$Data/MBeans/MBean[@Name='com.contoso.ws.CustomPerformance']/Properties/Property[@Name='AverageTransactionTime']$</Value>
 </ConditionDetection>
 
 <WriteActions>
 <WriteAction ID="WriteToDB" TypeID="SC!Microsoft.SystemCenter.CollectPerformanceData"/>
 <WriteAction ID="WriteToDW" TypeID="SCDW!Microsoft.SystemCenter.DataWarehouse.PublishPerformanceData"/>
 </WriteActions>
 </Rule>
 

 

Finally, this application will appear in the view with all of the rest of the (application server specific) applications (i.e. there is not a new view created for only the Contoso applications. Of course you could do this by simply defining a view that targets your new class.

CustomOrderServiceMonitor.xml