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.
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
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.
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.
<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>)
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().
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()
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
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.
- Listing the methods of a Mbean.
- Figuring the parameters needed.
- Constructing the signature.
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>.
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:
- PerfMbean object of the server managing the target Mbean.
- The method of PerfMBean to call.
- The parameters of the called method, obtained with Help.operations().
- The "signature" of the parameters; that is, the type of each parameter, also obtained with Help.operations().
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 |
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.
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).
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 []] ... |
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.
The author would like to extend special thanks Robert (Bob) Gibson and Vishal Charegaonkar for their reviews of this article.
Resources
Learn
- Python
Tutorial
- IBM
WebSphere scripting with wsadmin: containment paths, configuration IDs and
object names
- Writing
PMI applications using the JMX interface
- Guide to
Python introspection
- Book: WebSphere
Application Server Administration Using Jython, Robert A. Gibson, Arthur
Kevin, McGrath, Noel J. Bergman, IBM Press, 2010
- How Do
You Specify the MBean You Want?
- Class Object: java.lang.Object,
java.lang.Class
- Information Center: PMI
data organization
- IBM developerWorks WebSphere
About the author
댓글 없음:
댓글 쓰기