2012년 3월 19일 월요일

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

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


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



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


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
       
      
wsadmin> for i in jvmStats.listStatisticNames(): 
wsadmin>   print i, jvmStats.getJ2EEStatistic( i).getClass()

HeapSizecom.ibm.ws.pmi.stat.BoundedRangeStatisticImpl
UsedMemorycom.ibm.ws.pmi.stat.CountStatisticImpl
UpTimecom.ibm.ws.pmi.stat.CountStatisticImpl
ProcessCpuUsagecom.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)



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)


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)



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)



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)



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
About the author
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

댓글 없음:

댓글 쓰기