JVM updates in WebSphere Application Server V8: Using wsadmin and Jython to easily collect and report WebSphere Application Server PMI data

This article describes how you can use wsadmin introspection with Jython to easily retrieve Performance Monitoring Infrastructure (PMI) metrics for IBM® WebSphere® Application Server. IBM Tivoli® Performance Viewer is used as a model for performance reporting. A high level review of PMI architecture is included. This content is part of the IBM WebSphere Developer Technical Journal.

Share:

Denis Guillemenot (denis_guillemenot@fr.ibm.com), Senior IT Consultant, IBM

Denis Guillemenot is a Senior IT Consultant for IBM with 10 years of experience working on monitoring solutions. He is currently working with a client's Level 3 WebSphere Support team.



07 December 2011

Also available in Japanese

Introduction

IBM WebSphere Application Server provides performance metrics through the Performance Monitoring Infrastructure (PMI). WebSphere Application Server uses PMI to collect performance (and statistical) metrics data when running. The number and scope of metrics collected depends on the level of information needed.

There are several important things you need to know and remember about WebSphere Application Server and PMI. On each WebSphere Application Server JVM, the PMI framework is composed of a:

  • PMI service, which must be activated to collect data (on NodeAgent also).
  • PMI module, which permits you to configure what data to collect.
  • Performance Mbean (PefMBean), which permits the configuration of the PMI service and the gathering of data.

Because PMI conforms to the Java™ Management eXtension (JMX) standard, PMI data is accessible via the JMX interface (Figure 1).

Figure 1. JMX interface
Figure 1. JMX interface

JMX is a management model where resources are managed by managed beans (Mbeans). Some Mbeans are statistics providers and have a Stats attribute. A PerfMbean can collect data from multiple Mbeans in one JMX call. For each application server, PMI data is collected and stored in a hierarchical tree-like structure with modules, submodules, and counters (Figure 2); if you ask the PMI data for the server Mbean, then you have all the PMI data of the server.

Figure 2. Hierarchy of data collections used for performance reporting to Tivoli Performance Viewer
Figure 2. Hierarchy of data collections used for peformance reporting to Tivoli Performance Viewer

Get more information

See the WebSphere Application Server Information Center documentation to get a better understanding of PMI data organization.

To access the final metrics, you need to select the applicable modules, submodules, and counters on which you want to report. IBM Tivoli Performance Viewer is an excellent and popular graphical tool to help you do this. Taking this a step further, it would be great if you could browse modules and access metrics using wsadmin or Jython as easily as you can with Tivoli Performance Viewer. The good news is that you can!

To show how you can do this, we'll start with the techniques described in an earlier article, Writing PMI applications using the JMX interface. The examples in that article were created for Java developers. Here, we'll use wsadmin Jython scripts to demonstrate how easy it can be using this method to read and understand performance metrics.

However, before you can retrieve PMI metrics, you first need to understand how to use introspection and how to call MBean JMX methods (via the PerfMBean). These topics are discussed in the next sections.


The power of introspection

In general, introspection refers to the ability to examine an element, component, or object to determine what it is, what it knows, or what it can do. Introspection plays an important part in successfully implementing both wsadmin and Jython.

wsadmin introspection

The wsadmin utility includes five scripting objects:

  • AdminControl to manage running objects.
  • AdminConfig to manage configuration objects.
  • AdminApp to manage application objects.
  • AdminTask to make repetitive or complex tasks easier.
  • Help to provide help about scripting objects.

To launch wsadmin using Jython, just type the command: <WAS_PATH>/wsadmin.sh -lang jython.

You can use the wsadmin Help object to display information about each object using these commands:

  • print Help()
  • print Help.help()
  • print Help.AdminControl()
  • print Help.AdminConfig()
  • print Help.AdminApp()
  • print Help.AdminTask()
  • print Help.operations( <object name string>)
  • print Help.attributes( <object name string>)

You can get almost all the known object types with by typing AdminConfig.types(); that's “almost” because all the possible types used in AdminControl.queryNames('type=...') are not listed with AdminConfig.types().

Listing 1 shows an example of Help.attributes() and Help.operations(), where all Mbeans of type JVM are listed and put in an Jython list, and then all attributes and methods of the JVM server1 are listed (jvmList[2]). The stats attribute and the getStats() method are important for PMI data.

Listing 1. wsadmin introspection: Help.attributes() and Help.operations()
$ /websphere/mywas/bin/wsadmin.sh -lang jython
WASX7209I: Connected to process "dmgr" on node Node01 using SOAP connector;  The type of 
process is: DeploymentManager
WASX7031I: For help, enter: "print Help.help()"
wsadmin>

wsadmin> jvmList = AdminControl.queryNames( 'type=JVM,*').split( lineSeparator)
['WebSphere:name=JVM,process=dmgr,platform=proxy,node=W2K300Dmgr,j2eeType=JVM,J2EEServer=
dmgr,version=7.0.0.5,type=JVM,mbeanIdentifier=JVM,cell=W2K300Cell,spec=1.0', 'WebSphere:
name=JVM,process=nodeagent,platform=proxy,node=W2K300Node01,j2eeType=JVM,J2EEServer=
nodeagent,version=7.0.0.5,type=JVM,mbeanIdentifier=JVM,cell=W2K300Cell,spec=1.0', 
'WebSphere:name=JVM,process=server1,platform=proxy,node=W2K300Node01,j2eeType=JVM,
J2EEServer=server1,version=7.0.0.5,type=JVM,mbeanIdentifier=JVM,cell=W2K300Cell,spec=1.0',
'WebSphere:name=JVM,process=server2,platform=proxy,node=W2K300Node01,j2eeType=JVM,
J2EEServer=server2,version=7.0.0.5,type=JVM,mbeanIdentifier=JVM,cell=W2K300Cell,spec=1.0']

wsadmin> print Help.attributes( jvmList[2])
Attribute                       Type                            Access
javaVendor                      java.lang.String                RO
javaVersion                     java.lang.String                RO
node                            java.lang.String                RO
heapSize                        java.lang.String                RO
freeMemory                      java.lang.String                RO
maxHeapDumpsOnDisk              java.lang.Integer               RW
maxMemory                       java.lang.String                RO
maxSystemDumpsOnDisk            java.lang.Integer               RW
stats                           javax.management.j2ee.statistics.Stats  RO
objectName                      java.lang.String                RO
stateManageable                 boolean                         RO
statisticsProvider              boolean                         RO
eventProvider                   boolean                         RO

wsadmin> print Help.operations( jvmList[2])
Operation
java.lang.String getJavaVendor()
java.lang.String getJavaVersion()
java.lang.String getJVMNode()
java.lang.String getTotalMemory()
java.lang.String getFreeMemory()
java.lang.Integer getMaxDumpsOnDisk()
void setMaxDumpsOnDisk(java.lang.Integer)
java.lang.String getMaxMemory()
java.lang.Integer getMaxSystemDumpsOnDisk()
void setMaxSystemDumpsOnDisk(java.lang.Integer)
void dumpThreads()
java.lang.String getProperty(java.lang.String)
java.lang.String getIPAddress(java.lang.String)
long getCurrentTimeInMillis()
java.lang.String generateSystemDump()
java.lang.String; generateSystemDump(java.lang.String)
java.lang.String generateHeapDump()
[Ljava.lang.String; generateHeapDumps()
[Ljava.lang.String; generateHeapDump(java.lang.String)
boolean isVerbose()
void setVerbose(boolean, java.lang.String)
javax.management.j2ee.statistics.Stats getStats()
java.lang.String getObjectNameStr()
boolean isStateManageable()
boolean isStatisticsProvider()
boolean isEventProvider()

wsadmin> jvmStr = AdminControl.queryNames( 'type=JVM,process=server1,*')
wsadmin> jvmStr
'WebSphere:name=JVM,process=server1,platform=proxy,node=W2K300Node01,j2eeType=JVM,
J2EEServer=server1,version=7.0.0.5,type=JVM,mbeanIdentifier=JVM,cell=W2K300Cell,spec=1.0'

Listing 2 shows an example of AdminConfig.types().

Listing 2. wsadmin introspection: AdminConfig.types()
wsadmin> print AdminConfig.types()
AccessPointGroup
ActivationSpec
ActivationSpecTemplateProps
ActivitySessionService
…
WorkManagerInfo
WorkManagerProvider
WorkManagerService
WorkloadManagementServer

wsadmin> [p for p in AdminConfig.types().split() if p.lower().find('pmi')>=0]
['PMIModule', 'PMIRMFilter', 'PMIRMFilterValue', 'PMIRequestMetrics', 'PMIService']

The Python syntax [var for var in …] is called list comprehension (see the Python tutorial in Resources).

Jython and Java introspection

As it is in Python, introspection is key when programming in Jython. Because Jython manipulates Python objects and Java objects, there are two ways to perform introspection:

  • Python objects: Python introspection with type() and dir().
  • Java objects: Java introspection with getClass() and getMethods().

Be sure to remember that all Java objects are created from the class java.lang.Object and java.lang.Class (see Resources) so you get access to all their methods from Jython.

Now, let's verify. In Listing 3, you launch wsadmin with Jython and then use dir() and type() to look at the available objects:

  • Get known objects: AdminApp, AdminConfig, … sys, …
  • Query an object: dir( AdminApp), dir( sys.version)
  • Get the type of an object: type( AdminApp), type( sys.version)
Listing 3. Jython introspection: dir() and type()
wsadmin> dir()
['AdminApp', 'AdminConfig', 'AdminControl', 'AdminTask', 'Help', 'LTPA_LDAPSecurityOff', 
'LTPA_LDAPSecurityOn', 'TypedProxy', '__doc__', '__name__', 'bsf', 'cellName', 
'checkuserpw', 'doAuthenticationMechanism', 'doGlobalSecurity', 
'doGlobalSecurityDisable', 'doLDAPUserRegistry', 'domainHostname', 'exportLTPAKey', 
'flag', 'forceSync', 'generateLTPAKeys', 'getLDAPUserRegistryId', 'getLTPAId', 
'getSecId', 'getSecurityAdminMbean', 'java', 'ldapPassword', 'ldapPort', 'ldapServer', 
'ldapServerId', 'ldapUserRegistryId', 'lineSeparator', 'ltpaId', 'nodeName', 
'secMbean', 'securityId', 'securityoff', 'securityon', 'sleep', 'sys', 'whatEnv']

wsadmin> dir( AdminApp)
[]

wsadmin> type( AdminApp)
<jclass org.python.core.PyJavaInstance at 522592038>

wsadmin> dir( sys)
['__delattr__', '__dict__', '__displayhook__', '__excepthook__', '__findattr__', 
'__setattr__', '__stderr__', '__stdin__', '__stdout__', '_getframe', 'add_classdir', 
'add_extdir', 'add_package', 'argv', 'builtin_module_names', 'builtins', 'cachedir', 
'classLoader', 'copyright', 'defaultencoding', 'displayhook', 'exc_info', 'excepthook', 
'exec_prefix', 'executable', 'exit', 'getClassLoader', 'getdefaultencoding', 
'hexversion', 'initialize', 'last_traceback', 'last_type', 'last_value', 'maxint', 
'minint', 'modules', 'packageManager', 'path', 'platform', 'prefix', 'profile', 
'profilefunc', 'ps1', 'ps2', 'registry', 'setClassLoader', 'setdefaultencoding', 
'setprofile', 'settrace', 'stderr', 'stdin', 'stdout', 'toString', 'trace', 
'tracefunc', 'version', 'version_info', 'warnoptions']

wsadmin> print sys.version
2.1

wsadmin> dir( sys.version)
[]

wsadmin> type( sys.version)
<jclass org.python.core.PyString at 469769216>

In Listing 4, getClass() and getMethods() are used to look at the JVM Mbean methods:

  • Search object string name: AdminControl.queryNames()
  • Get object reference: AdminControl.makeObjectName()
  • Query an object: <object>.getClass(), <object>.getMethods()

Be aware that getClass() and getMethods() only work on Jython objects of type org.python.core.PyJavaInstance and not on Jython objects of type org.python.core.PyString.

Listing 4. Java introspection: getClass() and getMethods()
wsadmin> type( jvmList)
<jclass org.python.core.PyList at 778972782>

wsadmin> type( jvmStr)
<jclass org.python.core.PyString at 1555061936>

wsadmin> jvmStr.getClass()
WASX7015E: Exception running command: "jvmList[2].getClass()"; exception information:
 com.ibm.bsf.BSFException: exception from Jython:
Traceback (innermost last):
  File "<input>", line 1, in ?
AttributeError: 'string' object has no attribute 'getClass'

wsadmin> jvmObj = AdminControl.makeObjectName( jvmStr)
wsadmin> jvmObj
WebSphere:name=JVM,process=server1,platform=proxy,node=W2K300Node01,j2eeType=JVM,
J2EEServer=server1,version=7.0.0.5,type=JVM,mbeanIdentifier=JVM,cell=W2K300Cell,spec=1.0

wsadmin> type( jvmObj)
<jclass org.python.core.PyJavaInstance at 2093776076>

wsadmin> jvmObj.getClass()
<jclass javax.management.ObjectName at 1904111998>

wsadmin> type( jvmObj.getClass())
<jclass org.python.core.PyJavaClass at 1378767406>

wsadmin> type( jvmObj.getClass().getMethods())
<jclass org.python.core.PyArray at 90441060>

wsadmin> for i in jvmObj.getClass().getMethods(): print i
public boolean javax.management.ObjectName.equals(java.lang.Object)
public int javax.management.ObjectName.hashCode()
public java.lang.String javax.management.ObjectName.toString()
public boolean javax.management.ObjectName.isPattern()
public boolean javax.management.ObjectName.isDomainPattern()
public boolean javax.management.ObjectName.isPropertyPattern()
public boolean javax.management.ObjectName.isPropertyListPattern()
public boolean javax.management.ObjectName.isPropertyValuePattern()
public boolean javax.management.ObjectName.isPropertyValuePattern(java.lang.String) 
throws java.lang.NullPointerException,java.lang.IllegalArgumentException
public java.lang.String javax.management.ObjectName.getCanonicalName()
public java.lang.String javax.management.ObjectName.getDomain()
public java.lang.String javax.management.ObjectName.getKeyProperty(java.lang.String) 
throws java.lang.NullPointerException
public java.util.Hashtable javax.management.ObjectName.getKeyPropertyList()
public java.lang.String javax.management.ObjectName.getKeyPropertyListString()
...
public final native java.lang.Class java.lang.Object.getClass()
...

Be careful: jvmObj is of type org.python.core.PyJavaInstance; that is, the Jython implementation of a Java class. The getClass() method gives the real Java class name javax.management.ObjectName.

Object name

Object name refers to an active JMX Mbean that can be controlled with one of the commands in the AdminControl scripting object. The syntax is the standard JMX object name syntax:

domain:key=value,key=value,key=value,...

For WebSphere Application Server, the domain is WebSphere:

WebSphere:key=value,key=value,key=value,...

To get an object name, you can use:

  • AdminControl.queryNames( <string>) returns a string
  • AdminControl.makeObjectName( <string>) returns an object name

Therefore, jvmObj is a Java object of type javax.management.ObjectName, which points to the desired Mbean. To get the methods of the Mbean, you cannot use the getMethods() method directly on the jvmObj object. Instead, you need to use Help.operations(), as shown in Listing 1.


Calling MBean JMX methods via the PerfMBean

To simplify, there are three kind of PMI related Mbeans:

  • PerfMBean to manage and control other MBeans
  • StatisticsProvider Mbeans for providing the stats attribute containing statistics.
  • Other MBeans without stats attribute.

The power of introspection enables you to retrieve all the information you need to call Mbeans methods by:

  • Listing the methods of a Mbean.
  • Figuring the parameters needed.
  • Constructing the signature.

As you can see in Listing 1, the JVM Mbean has a stats attribute and a getStats() method, but you cannot call this method directly (Listing 5).

Listing 5. Trying to get stats object directly
wsadmin> jvmObj.getStats()
WASX7015E: Exception running command: "jvmObj.getStats()"; exception information:
 com.ibm.bsf.BSFException: exception from Jython:
Traceback (innermost last):
  File "<input>", line 1, in ?
AttributeError: getStats

To execute Mbean methods, you must use one of these techniques:

  • AdminControl.invoke(<mbeanStr>, 'method', <parameters>), where 'method' is a call to a method of the <mbeanStr>.
  • AdminControl.invoke_jmx( <perfObj>, 'method', <parameters>, <signature>), where 'method' is a call to a method of the <perfObj> PerfMBean and <parameters> will contain the name of the target <mbeanObj>.

To use the AdminControl.invoke() method, you need to provide the string version of the Mbean and you get the string version of the stats object (Listing 6).

Listing 6. Getting the string stats object with AdminControl.invoke()
wsadmin>print statStr = AdminControl.invoke( jvmStr, 'getStats')
Stats name=jvmRuntimeModule, type=jvmRuntimeModule#
{
name=HeapSize, ID=1, description=The total memory (in KBytes) in the Java virtual 
machine run time., unit=KILOBYTE, type=BoundedRangeStatistic, lowWaterMark=51200, 
highWaterMark=70012, current=70012, integral=0.0, lowerBound=51200, upperBound=262144

name=UsedMemory, ID=3, description=The amount of used memory (in KBytes) in the Java 
virtual machine run time., unit=KILOBYTE, type=CountStatistic, count=69008

name=UpTime, ID=4, description=The amount of time (in seconds) that the Java virtual 
machine has been running., unit=SECOND, type=CountStatistic, count=77341

name=ProcessCpuUsage, ID=5, description=The CPU Usage (in percent) of the Java virtual 
machine., unit=N/A, type=CountStatistic, count=0
}

wsadmin>type( statStr)
<jclass org.python.core.PyString at 1555061936>

To use the AdminControl.invoke_jmx() method, you need to provide the object version of the MBean (type javax.management.ObjectName) and you will get the object version of the stats object. But for this, you need to use the PerfMBean associated with this JVM, and you'll use the getKeyPropertyList() method to get it (Listing 7).

Listing 7. Getting the PerfMBean of the server
wsadmin> jvmObj.getKeyPropertyList()
{version=7.0.0.5, j2eeType=JVM, platform=proxy, mbeanIdentifier=JVM, process=server1, 
type=JVM, name=JVM, node=W2K300Node01, spec=1.0, J2EEServer=server1, cell=W2K300Cell}

wsadmin> jvmObj.getKeyPropertyList()['process']
'server1'

wsadmin> perfStr = AdminControl.queryNames('type=Perf,process=%s,*' % 
jvmObj.getKeyPropertyList()['process'])
'WebSphere:name=PerfMBean,process=server1,platform=dynamicproxy,node=W2K300Node01,
version=7.0.0.5,type=Perf,mbeanIdentifier=PerfMBean,cell=W2K300Cell,spec=1.0'

wsadmin>type( perfStr)
<jclass org.python.core.PyString at 1555061936>

wsadmin>perfObj = AdminControl.makeObjectName( perfStr)
wsadmin>perfObj
WebSphere:name=PerfMBean,process=server1,platform=dynamicproxy,node=W2K300Node01,
version=7.0.0.5,type=Perf,mbeanIdentifier=PerfMBean,cell=W2K300Cell,spec=1.0

wsadmin>type( perfObj)
<jclass org.python.core.PyJavaInstance at 1467504504>

You can now list all the methods available with the PerfMBean (Listing 6).

Listing 8. Getting PerfMBean methods
wsadmin>print Help.attributes( perfStr)
Attribute                       Type                            Access

wsadmin>print Help.operations( perfStr)
Operation
com.ibm.websphere.pmi.PmiModuleConfig getConfig(javax.management.ObjectName)
com.ibm.websphere.pmi.PmiModuleConfig getConfig(java.lang.String)
[Lcom.ibm.websphere.pmi.PmiModuleConfig; getConfigs(java.util.Locale)
com.ibm.websphere.pmi.stat.WSStats getStatsObject(javax.management.ObjectName, 
java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.WSStats; getStatsArray([Ljavax.management.ObjectName;, 
java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.WSStats; getStatsArray([Lcom.ibm.websphere.pmi.stat.
StatDescriptor;, java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.MBeanLevelSpec; getInstrumentationLevel(javax.management.
ObjectName, java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.StatLevelSpec; getInstrumentationLevel(com.ibm.websphere.
pmi.stat.StatDescriptor, java.lang.Boolean)
java.lang.String getStatisticSet()
java.lang.String getCustomSetString()
[Lcom.ibm.websphere.pmi.stat.StatDescriptor; listStatMembers(com.ibm.websphere.pmi.stat.
StatDescriptor, java.lang.Boolean)
void setInstrumentationLevel(com.ibm.websphere.pmi.stat.MBeanLevelSpec, java.lang.Boolean)
void setInstrumentationLevel([Lcom.ibm.websphere.pmi.stat.MBeanLevelSpec;, 
java.lang.Boolean)
void setInstrumentationLevel([Lcom.ibm.websphere.pmi.stat.StatLevelSpec;, 
java.lang.Boolean)
void setStatisticSet(java.lang.String)
void setCustomSetString(java.lang.String, java.lang.Boolean)
void savePMIConfiguration()
[Lcom.ibm.websphere.pmi.PmiModuleConfig; getConfigs()
com.ibm.websphere.pmi.stat.WSStats getStatsObject(com.ibm.websphere.pmi.stat.
MBeanStatDescriptor, java.lang.Boolean)
com.ibm.websphere.pmi.stat.WSStats getStatsObject(com.ibm.ws.pmi.server.DataDescriptor, 
java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.WSStats; getStatsArray([Lcom.ibm.websphere.pmi.stat.
MBeanStatDescriptor;, java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.WSStats; getStatsArray([Lcom.ibm.ws.pmi.server.
DataDescriptor;, java.lang.Boolean)
java.lang.String getStatsString(javax.management.ObjectName, java.lang.Boolean)
  <deprecated>
java.lang.String getStatsString(javax.management.ObjectName, java.lang.String, 
java.lang.Boolean)  <deprecated>
void setInstrumentationLevel(java.lang.String, java.lang.Boolean)
void setInstrumentationLevel(com.ibm.ws.pmi.server.PerfLevelDescriptor, java.lang.Boolean)
void setInstrumentationLevel([Lcom.ibm.ws.pmi.server.PerfLevelDescriptor;, 
java.lang.Boolean)
[Lcom.ibm.websphere.pmi.stat.MBeanLevelSpec; getInstrumentationLevel
(com.ibm.websphere.pmi.
stat.MBeanStatDescriptor, java.lang.Boolean)
[Lcom.ibm.ws.pmi.server.PerfLevelDescriptor; getInstrumentationLevel
(com.ibm.ws.pmi.server.
DataDescriptor, java.lang.Boolean)
java.lang.String getInstrumentationLevelString()  <deprecated>
[Lcom.ibm.websphere.pmi.stat.MBeanStatDescriptor; listStatMembers(javax.management.
ObjectName)
[Lcom.ibm.websphere.pmi.stat.MBeanStatDescriptor; listStatMembers(com.ibm.websphere.pmi.
stat.MBeanStatDescriptor)
[Lcom.ibm.ws.pmi.server.DataDescriptor; listStatMembers(com.ibm.ws.pmi.server.
DataDescriptor)
java.lang.String listStatMemberNames(javax.management.ObjectName)  <deprecated>

Next, you are going to invoke the JMX getStatsObject() method from the PerfMBean to get a com.ibm.websphere.pmi.stat.WSStats object, which is the stats attribute of the JVM MBean.

The AdminControl.invoke_jmx() requires four parameters:

  1. PerfMbean object of the server managing the target Mbean.
  2. The method of PerfMBean to call.
  3. The parameters of the called method, obtained with Help.operations().
  4. The "signature" of the parameters; that is, the type of each parameter, also obtained with Help.operations().

You might have noticed that there are three versions of the getStatsObject(), with three differentes signatures; you can use whichever is easier for you, but be careful as some are deprecated.

Let's get the stats attribute in object format of the JVM MBean using the non-deprecated getStatsObject() method: com.ibm.websphere.pmi.stat.WSStats getStatsObject(javax.management.ObjectName, java.lang.Boolean (Listing 9).

Listing 9. Get the “object” stats attribute of the JVM Mbean
wsadmin> params = [ jvmObj, java.lang.Boolean ('true')]

wsadmin> sigs = ['javax.management.ObjectName', 'java.lang.Boolean']

wsadmin> jvmStats = AdminControl.invoke_jmx( perfObj, 'getStatsObject', params, sigs)
Stats name=jvmRuntimeModule, type=jvmRuntimeModule#
{
name=HeapSize, ID=1, description=The total memory (in KBytes) in the Java virtual 
machine run time., unit=KILOBYTE, type=BoundedRangeStatistic, lowWaterMark=51200, 
highWaterMark=60149, current=60149, integral=0.0, lowerBound=51200, upperBound=262144
name=UsedMemory, ID=3, description=The amount of used memory (in KBytes) in the Java 
virtual machine run time., unit=KILOBYTE, type=CountStatistic, count=59102
name=UpTime, ID=4, description=The amount of time (in seconds) that the Java virtual 
machine has been running., unit=SECOND, type=CountStatistic, count=19513005
name=ProcessCpuUsage, ID=5, description=The CPU Usage (in percent) of the Java virtual 
machine., unit=N/A, type=CountStatistic, count=0
}

You can check the type and methods of the stats object as shown in Listing 10.

Listing 10. Analyze the stats object with introspection
wsadmin> type (jvmStats)
<jclass org.python.core.PyJavaInstance at 1671979944>

wsadmin>jvmStats.getClass()
<jclass com.ibm.ws.pmi.stat.StatsImpl at 1708942812>

wsadmin> for i in jvmStats.getClass().getMethods(): print i

public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public java.lang.String com.ibm.ws.pmi.stat.StatsImpl.toString()
public java.lang.String com.ibm.ws.pmi.stat.StatsImpl.getName()
public int com.ibm.ws.pmi.stat.StatsImpl.numStatistics()
…
public com.ibm.websphere.pmi.stat.WSStatistic 
	com.ibm.ws.pmi.stat.StatsImpl.getStatistic(int)
public com.ibm.websphere.pmi.stat.WSStatistic 
	com.ibm.ws.pmi.stat.StatsImpl.getStatistic(java.lang.String)
public com.ibm.websphere.pmi.stat.WSStatistic[] 
	com.ibm.ws.pmi.stat.StatsImpl.getStatistics()
public com.ibm.websphere.pmi.stat.WSStatistic[] 
	com.ibm.ws.pmi.stat.StatsImpl.listStatistics()
public java.lang.String[] com.ibm.ws.pmi.stat.StatsImpl.listStatisticNames()
public java.lang.String[] com.ibm.ws.pmi.stat.StatsImpl.getStatisticNames()
public com.ibm.ws.pmi.stat.StatisticImpl 
	com.ibm.ws.pmi.stat.StatsImpl.getJ2EEStatistic(java.lang.String)
public com.ibm.ws.pmi.stat.StatisticImpl[] 
	com.ibm.ws.pmi.stat.StatsImpl.getJ2EEStatistics()
public java.lang.String[] com.ibm.ws.pmi.stat.StatsImpl.getJ2EEStatisticNames()
...

You can now retrieve information from the stats object using:

  • numStatistics(): number of PMI metrics available.
  • getJ2EEStatistics(): get all the PMI metrics available.
  • toXML(): get all the PMI metrics available in XML format.
Listing 11. Getting all the stats from the stats object
wsadmin> jvmStats.numStatistics()
4

wsadmin> jvmStats.listStatisticNames()
array(['HeapSize', 'UsedMemory', 'UpTime', 'ProcessCpuUsage'], java.lang.String)

wsadmin> print jvmStats.toXML()
<Stats name="jvmRuntimeModule" statType="jvmRuntimeModule#" il="-2" type="COLLECTION">
<BRS id="1" lWM="51200" hWM="60149" cur="60149" int="0.0" sT="1269269566329" 
	lST="1288782571946" lB="51200" uB="262144">
</BRS>
<CS id="3" sT="1269269566327" lST="1288867956052" ct="48753">
</CS>
<CS id="4" sT="1269269566327" lST="1288867956052" ct="19598389">
</CS>
<CS id="5" sT="1269269566319" lST="1288867956052" ct="0">
</CS>
</Stats>

wsadmin> jvmStats.getJ2EEStatistics()
array([name=HeapSize, ID=1, description=The total memory (in KBytes) in the Java virtual 
machine run time., unit=KILOBYTE, type=BoundedRangeStatistic, lowWaterMark=51200, 
highWaterMark=60149, current=60149, integral=0.0, lowerBound=51200, upperBound=262144, 
name=UsedMemory, ID=3, description=The amount of used memory (in KBytes) in the Java 
virtual machine run time., unit=KILOBYTE, type=CountStatistic, count=48753, name=UpTime, 
ID=4, description=The amount of time (in seconds) that the Java virtual machine has been 
running., unit=SECOND, type=CountStatistic, count=19598389, name=ProcessCpuUsage, ID=5, 
description=The CPU Usage (in percent) of the Java virtual machine., unit=N/A, 
type=CountStatistic, count=0], com.ibm.ws.pmi.stat.StatisticImpl)

The last method call, getJ2EEStatistics(), shows that there are different types of statistics. Indeed, there are five types of statistics objects (listed here with some of their methods):

  • Stats: getStatistics(), getStatistic(), getStatisticNames(), getSubStats()
  • CountStatistic: getCount()
  • TimeStatistic: getCount(), getMean()
  • RangeStatistic: getCurrent(), getMean()
  • BoundedRangeStatistic: getCurrent(), getMean()
Listing 12. Different kind of statistics

Click to see code listing

Listing 12. Different kind of statistics

wsadmin> for i in jvmStats.listStatisticNames(): 
wsadmin>   print i, jvmStats.getJ2EEStatistic( i).getClass()HeapSizecom.ibm.ws.pmi.stat.BoundedRangeStatisticImplUsedMemorycom.ibm.ws.pmi.stat.CountStatisticImplUpTimecom.ibm.ws.pmi.stat.CountStatisticImplProcessCpuUsagecom.ibm.ws.pmi.stat.CountStatisticImpl

Get more information

See the article Writing PMI applications using JMX interface for more details.

You can retrieve individual statistics from the stats object using:

  • getJ2EEStatistic(): get one PMI metric.
  • getStatistic():get one PMI metric.
  • getCurrent(), getMean(): get data for BoundedRangeStatistic metric.
  • getCount(): get data for CountStatistic metric.
Listing 13. Getting one statistic from the stats object
wsadmin> for i in jvmStats.listStatisticNames(): print i, jvmStats.getJ2EEStatistic( i)

HeapSizename=HeapSize, ID=1, description=The total memory (in KBytes) in the Java 
virtual machine run time., unit=KILOBYTE, type=BoundedRangeStatistic, lowWaterMark=
51200, highWaterMark=60149, current=51200, integral=2.6248472575011E13, lowerBound=
51200, upperBound=262144
UsedMemoryname=UsedMemory, ID=3, description=The amount of used memory (in KBytes) in 
the Java virtual machine run time., unit=KILOBYTE, type=CountStatistic, count=38213
UpTimename=UpTime, ID=4, description=The amount of time (in seconds) that the Java 
virtual machine has been running., unit=SECOND, type=CountStatistic, count=20028681
ProcessCpuUsagename=ProcessCpuUsage, ID=5, description=The CPU Usage (in percent) of the 
Java virtual machine., unit=N/A, type=CountStatistic, count=0

wsadmin> jvmStats.getJ2EEStatistic('HeapSize')
name=HeapSize, ID=1, description=The total memory (in KBytes) in the Java virtual 
machine run time., unit=KILOBYTE, type=BoundedRangeStatistic, lowWaterMark=51200, 
highWaterMark=60149, current=60149, integral=0.0, lowerBound=51200, upperBound=262144

wsadmin> jvmStats.getJ2EEStatistic('HeapSize').getClass()
<jclass com.ibm.ws.pmi.stat.BoundedRangeStatisticImpl at 250875636>

wsadmin> for i in jvmStats.getJ2EEStatistic( 'HeapSize').getClass().getMethods(): print i
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public java.lang.String com.ibm.ws.pmi.stat.BoundedRangeStatisticImpl.toString()
public int com.ibm.ws.pmi.stat.BoundedRangeStatisticImpl.getStatisticType()
public java.lang.String com.ibm.ws.pmi.stat.StatisticImpl.getName()
public java.lang.String com.ibm.ws.pmi.stat.StatisticImpl.getUnit()
public java.lang.String com.ibm.ws.pmi.stat.StatisticImpl.getDescription()
…
public java.lang.String com.ibm.ws.pmi.stat.BoundedRangeStatisticImpl.toXML()
…
public long com.ibm.ws.pmi.stat.RangeStatisticImpl.getCurrent()
…
public double com.ibm.ws.pmi.stat.RangeStatisticImpl.getMean()
…

wsadmin> jvmStats.getStatistic( 'HeapSize')
name=HeapSize, ID=1, description=The total memory (in KBytes) in the Java virtual machine 
run time., unit=KILOBYTE, type=BoundedRangeStatistic, lowWaterMark=51200, highWaterMark=
60149, current=51200, integral=2.6248472575011E13, lowerBound=51200, upperBound=262144

wsadmin> jvmStats.getStatistic( 'HeapSize').getClass()
<jclass com.ibm.ws.pmi.stat.BoundedRangeStatisticImpl at 165808610>

wsadmin> jvmStats.getStatistic( 'HeapSize').getCurrent()
51200L

wsadmin> jvmStats.getStatistic( 'HeapSize').getMean()
1315.7527162741048

wsadmin> jvmStats.getStatistic( 'UpTime')
name=UpTime, ID=4, description=The amount of time (in seconds) that the Java virtual 
machine has been running., unit=SECOND, type=CountStatistic, count=19598389

wsadmin>jvmStats.getStatistic( 'UpTime').getClass()
<jclass com.ibm.ws.pmi.stat.CountStatisticImpl at 1288981716>

wsadmin> jvmStats.getStatistic( 'UpTime').getCount()
19598389L

With introspection, you have been able to deep dive into the stats attribute of the JVM MBean and get all the information you need without any ugly string parsing.

Next, discover the simplicity of retrieving PMI data.


Collecting PMI metrics with wsadmin

Using Tivoli Performance Viewer as a guide, collecting PMI metrics with wsadmin and Jython can be very easy. Figure 3 shows a view of available servers using Tivoli Performance Viewer.

Figure 3. Viewing the servers available for PMI (TPV)
Figure 3. Viewing the servers available for PMI

The equivalent view in wsadmin shows that there are three available JMX Mbean of type Perf (Listing 14).

Listing 14. Viewing the servers available for PMI (wsadmin)
wsadmin>print AdminControl.queryNames('type=Perf,*')
WebSphere:name=PerfMBean,process=nodeagent,platform=dynamicproxy,node=W2K300Node01,
version=7.0.0.0,type=Perf,mbeanIdentifier=PerfMBean,cell=
W2K300Cell01,spec=1.0
WebSphere:name=PerfMBean,process=server1,platform=dynamicproxy,node=W2K300Node01,
version=7.0.0.0,type=Perf,mbeanIdentifier=PerfMBean,cell=W2
K300Cell01,spec=1.0
WebSphere:name=PerfMBean,process=server2,platform=dynamicproxy,node=W2K300Node01,
version=7.0.0.0,type=Perf,mbeanIdentifier=PerfMBean,cell=W2
K300Cell01,spec=1.0

As an example, let's select server1. You'll see the top level of the Performance modules hierarchy (Figure 4).

Figure 4. Viewing a server's top level modules (TPV)
Figure 4. Viewing a server's top level modules

To get the same view using wsadmin, you need to get the Object Name of server MBean and the Object Name of the corresponding PerfMBean. Finally, you can invoke the JMX method getStatsObject() to retrieve all PMI metrics for this server (with second parameter set to true), as shown in Listing 15.

Listing 15. Viewing a server's top level modules (wsadmin)
wsadmin> perfStr = AdminControl.queryNames( 'type=Perf,process=server1,
node=W2K300Node01,*')
wsadmin> perfStr
'WebSphere:name=PerfMBean,process=server1,platform=dynamicproxy,node=W2K300Node01,
version=7.0.0.0,type=Perf,mbeanIdentifier=PerfMBean,cell=W
2K300Cell01,spec=1.0'
wsadmin> perfObj = AdminControl.makeObjectName( perfStr)

wsadmin> srvrStr = AdminControl.queryNames( 'type=Server,name=server1, node=
W2K300Node01,*')
wsadmin> srvrStr
'WebSphere:name=server1,process=server1,platform=proxy,node=W2K300Node01,j2eeType=
J2EEServer,version=7.0.0.0,type=Server,mbeanIdentifier=cel
ls/W2K300Cell01/nodes/W2K300Node01/servers/server1/server.xml#Server_1300047119203,
cell=W2K300Cell01,spec=1.0,processType=ManagedProcess'
wsadmin> srvrObj = AdminControl.makeObjectName( srvrStr)

wsadmin> type( perfObj)

wsadmin> stats = AdminControl.invoke_jmx( perfObj, 'getStatsObject', [ srvrObj, 
java.lang.Boolean('true')], ['javax.management.ObjectName', 'java.lang.Boolean'])

wsadmin>for i in stats.subCollections(): print i.getName()
wsadmin>
DCSStats.Group
ExtensionRegistryStats.name
Security Authentication
Security Authorization
SipContainerModule
cacheModule
connectionPoolModule
hamanagerModule
jvmRuntimeModule
objectPoolModule
orbPerfModule
servletSessionsModule
threadPoolModule
transactionModule
webAppModule
wlmModule

You can go further and select the JDBC Connection Pools module in Tivoli Performance Viewer to see its submodules (Figure 5).

Figure 5. Viewing a server's submodules level (TPV)
Figure 5. Viewing a server's submodules level

As you have already retrieved all the metrics for the server, to get the same view using wsadmin is easy, as shown in Listing 16.

Listing 16. Viewing a server's submodules level (wsadmin)
wsadmin>for i in stats.getStats('connectionPoolModule').subCollections(): print 
i.getName()
wsadmin>
Derby JDBC Provider
Derby JDBC Provider (XA)

And you can dig one level further, as shown in Figure 6 (Tivoli Performance Viewer) and Listing 17 (wsadmin).

Figure 6. Viewing a server sub modules two level down (TPV)
Figure 6. TPV: viewing a server sub modules two level down
Listing 17. Viewing a server sub modules two level down (wsadmin)
wsadmin> for i in stats.getStats('connectionPoolModule').getStats('Derby JDBC 
Provider').subCollections(): print i.getName()
wsadmin>
DefaultDatasource

Now, it's time to collect metrics. This is shown first using Tivoli Performance Viewer (Figure 7).

Figure 7. Viewing a server module metrics (TPV)
Figure 7. TPV: viewing a server module metrics

The same view using wsadmin can be obtained with the listStatisticNames(), getStatistic(), getCount(), getName() methods (Listing 18).

Listing 18. Viewing a server module metrics (wsadmin)
wsadmin> stats.getStats('connectionPoolModule').getStats('Derby JDBC Provider').
getStats('DefaultDatasource').listStatisticNames()
array(['CreateCount', 'CloseCount', 'PoolSize', 'FreePoolSize', 'WaitingThreadCount', 
'PercentUsed', 'UseTime', 'WaitTime'], java.lang.String)

wsadmin> stats.getStats('connectionPoolModule').getStats('Derby JDBC Provider').
getStats('DefaultDatasource').getStatistic('CreateCount')
name=CreateCount, ID=1, description=Nombre total de connexions créées., unit=N/A, 
type=CountStatistic, count=0

wsadmin> stats.getStats('connectionPoolModule').getStats('Derby JDBC Provider').
getStats('DefaultDatasource').getStatistic('CreateCount').getCount()
0L

wsadmin> stats.getStats('connectionPoolModule').getStats('Derby JDBC Provider').
getStats('DefaultDatasource').getStatistic('CreateCount').getName()
'CreateCount'

Simple, isn't it ?

To wrap up our discussion of PMI , let's look finally at PMIService and PMIModule

PMIService and PMIModule

PMIService and PMIModule are both configuration entities:

  • PMIService is a service entity for WebSphere Application Server that is defined in the server.xml config file.
  • PMIModule is part of PMIService and is the PMI configuration for that server (that is, what you see in the console > PMI > Configuration tree).

PMIService is available on each WebSphere Application Server. Its configuration file is server.xml, and its attributes include enable, statisticset, and so on. If itPMIService is enabled, the PMI service is started for that application server.

PMIModule's configuration file is pmi-config.xml. When PMIService starts, it reads PMIModule information indicated in the pmi-config.xml file.

Listing 19. List of all PMIService
wsadmin> print AdminConfig.list( 'PMIService')
(cells/W2K300Cell/nodes/nodedmgr/servers/dmgr|server.xml#PMIService_1)
(cells/W2K300Cell/nodes/node1/servers/server1|server.xml#PMIService_1264758602928)
(cells/W2K300Cell/nodes/node1/servers/nodeagent|server.xml#PMIService_1264758899663)

In Listing 20, you can see that the PMIService is not enabled on the dmgr (enable false) and you also have the level of metrics collected (statiscticSet basic).

Listing 20. Status of PMIService for Deployment Manager
wsadmin> print AdminConfig.show( '(cells/W2K300Cell/nodes/nodedmgr/servers/dmgr|
server.xml#PMIService_1)')
[context dmgr(cells/W2K300Cell/nodes/nodedmgr/servers/dmgr|server.xml#Server_1)]
[enable false]
[initialSpecLevel []]
[properties []]
[statisticSet basic]
[synchronizedUpdate false]
Listing 21. Status of PMIService for Application Server
wsadmin> print AdminConfig.show( '(cells/W2K300Cell/nodes/node1/servers/server1|
server.xml#PMIService_1264758602928)')
[context server1(cells/W2K300Cell/nodes/node1/servers/server1|server.xml
#Server_1264758602924)]
[enable true]
[initialSpecLevel []]
[properties []]
[statisticSet basic]
[synchronizedUpdate false]
Listing 22. Status of PMIService NodeAgent
wsadmin> print AdminConfig.show( '(cells/W2K300Cell/nodes/node1/servers/nodeagent|
server.xml#PMIService_1264758899663)')
[context nodeagent(cells/W2K300Cell/nodes/node1/servers/nodeagent|server.xml
#Server_1264758899663)]
[enable true]
[initialSpecLevel []]
[properties []]
[statisticSet basic]
[synchronizedUpdate false]

PMIModule is available on the two servers where the PMIService is enabled (Listing 23).

Listing 23. List of all PMIModule
wsadmin> print AdminConfig.list( 'PMIModule')
(cells/W2K300Cell/nodes/node1/servers/server1|pmi-config.xml#PMIModule_1075747243635)
(cells/W2K300Cell/nodes/node1/servers/nodeagent|pmi-config.xml#PMIModule_1)

All the attributes of a PMIModule can be displayed using either:

  • AdminConfig.show: first information level.
  • AdminConfig.showall: all informations level.
Listing 24. All attributes of a PMIModule
wsadmin> pmimodule = '(cells/W2K300Cell/nodes/node1/servers/server1|pmi-config.xml
#PMIModule_1075747243635)'

wsadmin> print AdminConfig.show( pmimodule)
[enable []]
[moduleName pmi]
[pmimodules "[(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|
pmi-config.xml#PMIModule_101) 
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_102)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_103)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_104)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_105)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_127)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_106)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_111)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_114)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_115)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_116)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_117)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_128)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_129)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_118)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_119)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_120)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_121)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_122)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_123)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_124)
(cells/CEDmgr01/nodes/NDclay111p6Node01/servers/ASNode01-01|pmi-config.xml#PMIModule_126)
]"]
[type []]

wsadmin> print AdminConfig.showall( pmimodule)
[enable []]
[moduleName pmi]
[pmimodules "[[[enable []]
[moduleName alarmManagerModule]
[pmimodules []]
[type alarmManagerModule]] [[enable 35,34,9,1,26,11,12,2,25]
[moduleName beanModule]
[pmimodules []]
[type beanModule#]] [[enable []]
[moduleName cacheModule]
[pmimodules "[[[enable []]
[moduleName *]
[pmimodules "[[[enable []]
[moduleName cacheModule.template]
[pmimodules []]
[type com.ibm.websphere.pmi.xml.cacheModule_template]] [[enable []]
...

Conclusion

This article had two main purposes. First, to show that introspection is a real advantage when using wsadmin with Jython. And second, to shake up the Performance and Monitoring Infrastructure to find and easy and efficient way to collect PMI data with wsadmin and Jython.


Acknowledgements

The author would like to extend special thanks Robert (Bob) Gibson and Vishal Charegaonkar for their reviews of this article.

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=778947
ArticleTitle=JVM updates in WebSphere Application Server V8: Using wsadmin and Jython to easily collect and report WebSphere Application Server PMI data
publish-date=12072011