Microsoft Open Sources BeanSpy

This post is a bit belated, but I am proud to announce that my team has open sourced the Java component for monitoring MBeans on remote applications servers.  The project is called BeanSpy and it is available on github.

Platforms

Microsoft released BeanSpy under the Apache 2.0 license on January 2nd, 2012.  The EAR/WAR file should be deployed to one of the following supported application servers:

  • Tomcat: 5.5, 6, 7
  • JBoss: 4.2, 5.1, 6
  • WebLogic: 10gR3, 11gR1
  • WebSphere: 6.1, 7

BeanSpy HTTP GET operations

The following HTTP Get operations can be performed in a web browser such as Internet Explorer.

 

a) To query JVM stats for memory, Garbage Collection, class loading, and threads, use:
       https://<host:port>/BeanSpy/Stats  

For example, a query to a Tomcat 7 by https://localhost:8080/BeanSpy/Stats will generate output similar to:

 <?xml version="1.0" encoding="UTF-8" ?> <Stats version="7.4.1002.0"> <JmxStores>   <Properties>     <JmxStoreNames type="class java.lang.String">com.interopbridges.scx.jmx.TomcatJMXAbstraction</JmxStoreNames>   </Properties></JmxStores> <JmxStores>   <Properties>     <JmxStoreNames type="class java.lang.String">com.interopbridges.scx.jmx.JdkJMXAbstraction</JmxStoreNames>   </Properties> </JmxStores> <ClassLoader>   <Properties>     <LoadedClassCount type="int">2851</LoadedClassCount>     <UnloadedClassCount type="long">192688</UnloadedClassCount>     <TotalLoadedClassCount type="long">195539</TotalLoadedClassCount>   </Properties> </ClassLoader> <Thread>   <Properties>     <PeakThreadCount type="int">30</PeakThreadCount>     <ThreadCount type="int">22</ThreadCount>     <TotalStartedThreadCount type="long">8430</TotalStartedThreadCount>   </Properties> </Thread> <JITCompiler>   <Properties>     <TotalCompilationTime type="long">98866</TotalCompilationTime>   </Properties> </JITCompiler>   <GC>     <Properties>       <GCCollectionCount type="long">5892</GCCollectionCount>       <GCCollectionTime type="long">299742</GCCollectionTime>       <GCName type="class java.lang.String">PS Scavenge</GCName>     </Properties> </GC> <GC>   <Properties>     <GCCollectionCount type="long">1321</GCCollectionCount>     <GCCollectionTime type="long">260844</GCCollectionTime>     <GCName type="class java.lang.String">PS MarkSweep</GCName>   </Properties> </GC> <Memory>   <Properties>     <HeapInitialMemoryAllocated type="long">33547136</HeapInitialMemoryAllocated>     <HeapUsedMemory type="long">38520664</HeapUsedMemory>     <HeapCommittedMemory type="long">55443456</HeapCommittedMemory>     <HeapMaximumMemory type="long">477233152</HeapMaximumMemory>     <NonHeapInitialMemoryAllocated type="long">24313856</NonHeapInitialMemoryAllocated>     <NonHeapUsedMemory type="long">24809424</NonHeapUsedMemory>     <NonHeapCommittedMemory type="long">25755648</NonHeapCommittedMemory>     <NonHeapMaximumMemory type="long">136314880</NonHeapMaximumMemory>     <PendingFinalizationCount type="int">0</PendingFinalizationCount>     <PercentHeapMemoryUsed type="int">8</PercentHeapMemoryUsed>   </Properties> </Memory>   <Runtime>     <Properties>       <StartTime type="long">1323463776869</StartTime>       <UpTime type="long">4755504058</UpTime>     </Properties>   </Runtime> </Stats>

 

b) To query configuration and version info about the Java EE application server or web container, use:
       https://<host:port>/BeanSpy/Stats/Info 

For example, a query to a Tomcat 7 by https://localhost:8080/BeanSpy/Stats/Info will generate output similar to:

 <?xml version="1.0" encoding="UTF-8" ?>
 <Info version="7.4.1002.0">
 <JVMMemory>
 <Properties>
 <MaxHeapSize type="class java.lang.String">455 MB</MaxHeapSize>
 </Properties>
 </JVMMemory>
 <OperatingSystem>
 <Properties>
 <Name type="class java.lang.String">Windows Server 2008 R2</Name>
 <Version type="class java.lang.String">6.1</Version>
 <Architecture type="class java.lang.String">amd64</Architecture>
 </Properties>
 </OperatingSystem>
 <JavaVirtualMachine>
 <Properties>
 <Name type="class java.lang.String">Java HotSpot(TM) 64-Bit Server VM</Name>
 <ClassPath type="class java.lang.String">C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\resources.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\rt.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\sunrsasign.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\jsse.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\jce.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\charsets.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\lib\modules\jdk.boot.jar;C:\PROGRA~1\Java\jdk1.6.0_25\jre\classes</ClassPath>
 <LibraryPath type="class java.lang.String">C:\PROGRA~1\Java\jdk1.6.0_25\bin;.;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\teamtool;C:\teamtool\TTRemoteInstall;C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\;C:\PROGRA~1\Java\jdk1.6.0_25\bin</LibraryPath>
 <StartupTime type="class java.lang.String">Mon Feb 06 10:57:59 PST 2012</StartupTime>
 <Version type="class java.lang.String">1.6.0_25</Version>
 <VendorName type="class java.lang.String">Sun Microsystems Inc.</VendorName>
 <BuildVersion type="class java.lang.String">20.0-b11</BuildVersion>
 <StartupOption type="class java.lang.String">-Djava.util.logging.config.file=C:\AppServers\Tomcat\apache-tomcat-7.0.11-windows-x64\apache-tomcat-7.0.11\conf\logging.properties, -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager, -Djava.endorsed.dirs=C:\AppServers\Tomcat\apache-tomcat-7.0.11-windows-x64\apache-tomcat-7.0.11\endorsed, -Dcatalina.base=C:\AppServers\Tomcat\apache-tomcat-7.0.11-windows-x64\apache-tomcat-7.0.11, -Dcatalina.home=C:\AppServers\Tomcat\apache-tomcat-7.0.11-windows-x64\apache-tomcat-7.0.11, -Djava.io.tmpdir=C:\AppServers\Tomcat\apache-tomcat-7.0.11-windows-x64\apache-tomcat-7.0.11\temp</StartupOption>
 <JavaInstallDirectory type="class java.lang.String">C:\PROGRA~1\Java\jdk1.6.0_25\jre</JavaInstallDirectory>
 </Properties>
 </JavaVirtualMachine>
 <JEEServer>
 <Properties>
 <AppServerName type="class java.lang.String">Apache Tomcat/7.0.11</AppServerName>
 </Properties>
 </JEEServer>
 </Info>

 

c) To query specific MBeans, use:
       https://<host:port>/BeanSpy/MBeans?JMXQuery=<BeanObjectName>

       For instance, on Tomcat 7 to get a list of the deployed WebModules use the following (note: MaxDepth=0 displays only the Object Names of the MBeans)use https://localhost:8080/BeanSpy/MBeans?JMXQuery=Catalina:j2eeType=WebModule,*&MaxDepth=0.  I will not do the full output of the JMX Query b/c Tomcat MBeans are quite verbose:

 <?xml version="1.0" encoding="UTF-8" ?>
 <MBeans version="7.4.1002.0">
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/examples">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/examples</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/examples</name>
 </objectNameElements>
 </MBean>
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/CustomOrderService">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/CustomOrderService</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/CustomOrderService</name>
 </objectNameElements>
 </MBean>
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/BeanSpy">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/BeanSpy</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/BeanSpy</name>
 </objectNameElements>
 </MBean>
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/docs">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/docs</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/docs</name>
 </objectNameElements>
 </MBean>
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/host-manager">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/host-manager</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/host-manager</name>
 </objectNameElements>
 </MBean>
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/manager">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/manager</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/manager</name>
 </objectNameElements>
 </MBean>
 <MBean Name="org.apache.catalina.mbeans.ContextMBean" objectName="Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/">
 <objectName type="java.lang.String">Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/</objectName>
 <objectNameElements type="objectName">
 <Domain>Catalina</Domain>
 <J2EEApplication>none</J2EEApplication>
 <J2EEServer>none</J2EEServer>
 <j2eeType>WebModule</j2eeType>
 <name>//localhost/</name>
 </objectNameElements>
 </MBean>
 </MBeans>

BeanSpy HTTP POST operations

Some MBean information is not available by through properties, instead a method call to the MBean is necessary. To invoke a method on a MBean, use HTTP POST:
       https://<host:port>/BeanSpy/MBeans/Invoke

The HTTP post body should look like this:

  <Invoke>
 <BeanObjectName>com.contoso:name=CustomMBeanName</BeanObjectName>
 <Method name="FooMethod">
 <Param name="p0" type="java.lang.Integer">400</Param>
 <Param name="p1" type="java.lang.String">bar</Param>
 </Method>
 </Invoke>

The Result XML should look like:

 <?xml version="1.0" encoding="UTF-8"?>
<InvokeResponse>
 <Result>SUCCESS</Result>
 <Response type="java.lang.Integer">2</Response>
</InvokeResponse>