Howto: Monitor EJBs with BeanSpy in SCOM 2012 on JBoss 5
Out-of-the-box, EJB discovery and monitoring are not supported by the SCOM 2012 JEE MPs (https://blogs.technet.com/b/random_happy_dev_thoughts/archive/2012/04/18/system-center-operations-manager-scom-2012-released.aspx). That said, there is nothing to preclude a customer to write their own management pack for doing so. In this blog post I will detail how one could do this for JBoss 5.
Introduction
Please note that this is provided as an instructional demonstration of the software capabilities and this management pack is not supported by Microsoft. And any other legal disclaimers I may have forgotten. :)
Most anything deployed to an application server (be it Tomcat, JBoss, WebSphere, or WebLogic) is represented as a MBean. The good news is that if it is a MBean, then BeanSpy can find and monitor it! That is the good news.
The other news (I would not call it bad), is that you need to facilitate this.
BeanSpy Output
Before you start writing a MP, first let's find the input were going after directly from BeanSpy. On Jboss 5, a query directly BeanSpy to list deployed EJB modules is:
https://localhost:8180/BeanSpy/MBeans?JMXQuery=jboss.management.local:j2eeType=EJBModule,*
I know this because I know this. :) If you don't already know what you're looking for, try a more general query and use find (i.e. Control + F on most browsers) to search for EJB to find what you're looking for - such as a specific application name. If all else fails, save the XML and open it in a fancy text editor that does syntax highlighting and code folding. Point being, figure out what exactly you're looking for first and the best JMX query to return that information
This will give XML that looks like below (note the MBean class returned will vary by Application Server and version of said Application Server):
<?xml version="1.0" encoding="UTF-8"?>
<MBeans version="7.3.2106.0">
<MBean Name="org.jboss.management.j2ee.EJBModule" objectName="jboss.management.local:J2EEApplication=null,J2EEServer=Local,j2eeType=EJBModule,name=profileservice-secured.jar">
<Properties>
<Property Name="jawsDeploymentDescriptor" type="java.lang.String"/>
<Property Name="eventProvider" type="java.lang.Boolean">true</Property>
<Property Name="javaVMs" type="[Ljava.lang.String;">
<Property Name="javaVMs" index="0">jboss.management.local:J2EEServer=Local,j2eeType=JVM,name=Oracle Corporation 1.7.0</Property>
</Property>
<Property Name="statisticsProvider" type="java.lang.Boolean">false</Property>
<objectName type="java.lang.String">jboss.management.local:J2EEApplication=null,J2EEServer=Local,j2eeType=EJBModule,name=profileservice-secured.jar</objectName>
<objectNameElements type="objectName">
<Domain>jboss.management.local</Domain>
<J2EEApplication>null</J2EEApplication>
<J2EEServer>Local</J2EEServer>
<j2eeType>EJBModule</j2eeType>
<name>profileservice-secured.jar</name>
</objectNameElements>
<Property Name="parent" type="java.lang.String">jboss.management.local:j2eeType=J2EEServer,name=Local</Property>
<Property Name="cmpDeploymentDescriptor" type="java.lang.String"/>
<Property Name="deploymentDescriptor" type="java.lang.String">
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar
xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<display-name>Secured ManagementView</display-name>
<enterprise-beans>
<session>
<ejb-name>SecureProfileService</ejb-name>
<ejb-class>org.jboss.profileservice.ejb.SecureProfileServiceBean</ejb-class>
<session-type>Stateless</session-type>
<resource-ref>
<res-ref-name>profileService</res-ref-name>
<res-type>org.jboss.profileservice.spi.ProfileService</res-type>
<mapped-name>ProfileService</mapped-name>
<injection-target>
<injection-target-class>org.jboss.profileservice.ejb.SecureProfileServiceBean</injection-target-class>
<injection-target-name>delegate</injection-target-name>
</injection-target>
</resource-ref>
</session>
<session>
<ejb-name>SecureManagementView</ejb-name>
<ejb-class>org.jboss.profileservice.ejb.SecureManagementView</ejb-class>
<session-type>Stateless</session-type>
<resource-ref>
<res-ref-name>profileService</res-ref-name>
<res-type>org.jboss.profileservice.spi.ProfileService</res-type>
<mapped-name>ProfileService</mapped-name>
<injection-target>
<injection-target-class>org.jboss.profileservice.ejb.SecureManagementView</injection-target-class>
<injection-target-name>profileService</injection-target-name>
</injection-target>
</resource-ref>
</session>
<session>
<ejb-name>SecureDeploymentManager</ejb-name>
<ejb-class>org.jboss.profileservice.ejb.SecureDeploymentManager</ejb-class>
<session-type>Stateless</session-type>
<resource-ref>
<res-ref-name>profileService</res-ref-name>
<res-type>org.jboss.profileservice.spi.ProfileService</res-type>
<mapped-name>ProfileService</mapped-name>
<injection-target>
<injection-target-class>org.jboss.profileservice.ejb.SecureDeploymentManager</injection-target-class>
<injection-target-name>profileService</injection-target-name>
</injection-target>
</resource-ref>
</session>
</enterprise-beans>
</ejb-jar>
</Property>
<Property Name="jbossDeploymentDescriptor" type="java.lang.String"/>
<Property Name="stateManageable" type="java.lang.Boolean">false</Property>
<Property Name="ejbs" type="[Ljava.lang.String;"/>
<Property Name="server" type="java.lang.String">unknown server name</Property>
<Property Name="EventTypes" type="[Ljava.lang.String;">
<Property Name="EventTypes" index="0">j2ee.object.created</Property>
<Property Name="EventTypes" index="1">j2ee.object.deleted</Property>
</Property>
</Properties>
</MBean>
</MBeans>
Management Pack
Now that we know what we want to find, we need to write a management pack to find the EJBs. First, we'll declare a class Microsoft.JEE.JBoss.5.EJB.Application.EAR that extends the existing JBoss 5 EAR class:
<ClassTypes>
<ClassType ID="Microsoft.JEE.JBoss.5.EJB.Application.EAR"
Abstract="false" Accessibility="Public" Hosted="true"
Base="JBoss5!Microsoft.JEE.JBoss.5.Application.EAR" />
</ClassTypes>
Next, we need a discovery. EJBs live in an application server, so we should target the monitored instance of the JEE applications servers. Depending on the application server, you may be able to target the generic classes. For this article, I will target a specific JBoss 5 class because I do not want this discovery to run against other versions of JBoss.
The discovery needs to use the query mentioned above:
jboss.management.local:j2eeType=EJBModule,*
As listed above, the XML returned from the BeanSpy query needs to be parsed. Depending on what you need to pull out, you could have some fun with XPaths. Luckily, we are promised by underlying datasource that each MBean will be separated into its own XML chunk (so you probably don't need to worry about an instance & more than likely you'll just be parsing one MBean.
Here is the full discovery:
<Discovery ID="Microsoft.JEE.JBoss.5.EJB.Application.EAR.Discovery"
Target="JBoss5!Microsoft.JEE.JBoss.5.Monitored.Configuration"
Remotable="true" Enabled="true">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="Microsoft.JEE.JBoss.5.EJB.Application.EAR" />
<DiscoveryRelationship TypeID="JEE!Microsoft.JEE.MonitoredApplicationServerHostsApplicationRelationship" />
</DiscoveryTypes>
<DataSource ID="DS" TypeID="JEE!Microsoft.JEE.Discovery.MBeans.DataSource">
<ApplicationServerGuid>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</ApplicationServerGuid>
<ComputerName>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</ComputerName>
<Protocol>$Target/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Protocol$</Protocol>
<Port>$Target/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Port$</Port>
<BaseURL />
<JMXQuery>jboss.management.local:j2eeType=EJBModule,*</JMXQuery>
<AdditionalArguments>&MaxDepth=0</AdditionalArguments>
<ReturnMultiplePropertyBags>true</ReturnMultiplePropertyBags>
<UseAttributesInKeysOfReturnedPropertyBags>false</UseAttributesInKeysOfReturnedPropertyBags>
<!-- Interval currently set to four hours -->
<IntervalSeconds>14400</IntervalSeconds>
<TimeoutSeconds>900</TimeoutSeconds>
<ClassId>$MPElement[Name="Microsoft.JEE.JBoss.5.EJB.Application.EAR"]$</ClassId>
<InstanceSettings>
<Settings>
<!-- The following properties are defined for the Application's parent classes -->
<Setting>
<Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectNameElements/name']$</Value>
</Setting>
<!-- These properties are for the JBoss Configuration-->
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Name>
<Value>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Name>
<Value>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Value>
</Setting>
<!-- The following properties are defined for the Application-->
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ApplicationName$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectNameElements/name']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/j2eeType$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectNameElements/j2eeType']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ObjectName$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectName']$</Value>
</Setting>
</Settings>
</InstanceSettings>
</DataSource>
</Discovery>
The only interesting piece in the discovery is mapping the object. A relic of how some of the work was done, the "XPath" is slightly different from the actual XML that is sent over. It turns out for several reasons it was necessary to slightly manage the XML returned by the discovery source. Rather than use the short name (MBean), the name attribute of the actual class is used by the logic that creates the individual discovery data items.
:
<ClassId>$MPElement[Name="Microsoft.JEE.JBoss.5.EJB.Application.EAR"]$</ClassId>
<InstanceSettings>
<Settings>
<!-- The following properties are defined for the Application's parent classes -->
<Setting>
<Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectNameElements/name']$</Value>
</Setting>
<!-- These properties are for the JBoss Configuration-->
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Name>
<Value>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Name>
<Value>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Value>
</Setting>
<!-- The following properties are defined for the Application-->
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ApplicationName$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectNameElements/name']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/j2eeType$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectNameElements/j2eeType']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ObjectName$</Name>
<Value>$Data/Property[@Name='/MBeans/org.jboss.management.j2ee.EJBModule/objectName']$</Value>
</Setting>
</Settings>
</InstanceSettings>
The trick is to make sure that the XPath matches (see above highlights).
The rest of the management pack is some rote state views and display strings - not too interesting. Since the EJB extends the existing JBoss Application class, EJBs will appear in that state view in addition to the new EJB state view that I created in this management pack.
As for monitoring, you are welcome to write your own monitors, but one blog post at a time. :)
For now, I would refer you to using the template wizard to generate some custom monitors (https://blogs.technet.com/b/random_happy_dev_thoughts/archive/2012/05/30/scomfaq-ch-scom-2012-jee-application-availability-monitor-template.aspx).
Comments
Anonymous
January 01, 2003
Note #1: the attached MP has keys for the Debug build of SCOM 2012. If you wanted to use this with the release/signed build of SCOM 2012 you'd need to update the PublicKeyToken fields - see systemcentertech.com/.../locating-the-public-key-token-for-a-management-packAnonymous
January 01, 2003
Note #2: If you want to use a different application server (such as WebSphere), there are a minimal set of changes to make such as:
- Update class to extend the appropriate platform (and adjust the References as necessary)
- Update the discovery's JMX Query
- Update the discovery's MBeans xpath with an appropriate class name (which will vary per application server)