Beruflich Dokumente
Kultur Dokumente
The WebLogic Diagnostic Framework (WLDF) is a collection of services for monitoring the runtime
behavior of applications, such as
Logging
Instrumentation - apply instrumentation monitors to arbitrary points in application code.
Harvester - schedule tasks to record metric data from a configurable set of JMX MBeans.
Watches and Notifications - WLDF watch rules can be used to monitor log messages,
instrumentation events, or harvested metric data.
The WLDF services are designed to complement each other. To get a feeling of the different services,
we use an example application. It consists of a stateless session bean, a message driven bean and a
test servlet. The session bean and message driven bean are presented below; the servlet is
presented later on in this article. The stateless session bean:
package datamodel.logic;
import datamodel.entities.Bestelling;
import datamodel.entities.Klant;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import
import
import
import
import
import
import
import
import
import
javax.jms.Connection;
javax.jms.ConnectionFactory;
javax.jms.JMSException;
javax.jms.MessageProducer;
javax.jms.ObjectMessage;
javax.jms.Queue;
javax.jms.Session;
javax.naming.Context;
javax.naming.InitialContext;
javax.naming.NamingException;
javax.jms.JMSException;
javax.jms.Message;
javax.jms.MessageListener;
javax.jms.ObjectMessage;
"javax.jms.Queue")
})
public class BedrijfMDB implements MessageListener {
public BedrijfMDB() {
}
public void onMessage(Message message) {
ObjectMessage objectMessage = (ObjectMessage) message;
Klant klant = null;
try {
klant = (Klant) objectMessage.getObject();
message.acknowledge();
} catch (JMSException e) {
e.printStackTrace();
}
System.out.println("MESSAGING KLANT " + klant);
}
}
Instrumentation
Say we are interested in the performance of adding a customer. In particular, we want to know how
long it takes the session bean to produce a message and send to a JMS queue, further we are
interested in how long the processing of the message takes by the message driven bean. To add
instrumentation, we create an application-specific diagnostic module, for example,
<?xml version="1.0" encoding="UTF-8"?>
<wldf-resource xmlns="http://xmlns.oracle.com/weblogic/weblogic-diagnostics"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-diagnostics
http://xmlns.oracle.com/weblogic/weblogic-diagnostics/1.0/weblogicdiagnostics.xsd">
<instrumentation>
<enabled>true</enabled>
<wldf-instrumentation-monitor>
<name>AddKlantInstrumentationEJB</name>
<action>MethodInvocationStatisticsAction</action>
<location-type>around</location-type>
<pointcut>execution(* datamodel.logic.BedrijfBean addKlant(...))</pointcut>
</wldf-instrumentation-monitor>
<wldf-instrumentation-monitor>
<name>OnMessageInstrumentationMDB</name>
<action>MethodInvocationStatisticsAction</action>
<location-type>around</location-type>
<pointcut>execution(* datamodel.logic.BedrijfMDB onMessage(...))</pointcut>
</wldf-instrumentation-monitor>
</instrumentation>
</wldf-resource>
This should be named weblogic-diagnostics.xml, and packaged in the application archive below the
META-INF directory.
The module defines two monitors. The code instrumented by each monitor is determined by a
pointcut expression. Each monitor generates an event whenever the instrumented code is called. The
monitored points are specified using declarative rules (pointcuts), and implemented using byte code
modification. The events that are captured include a diagnostic context identifier, which allows a
stream of related events to be correlated whether they occur within a server, or across JMS
messages, remote RMI, or SOAP calls.
In addition to the instrumentation point, each monitor configures an action. There are several types of
actions, such as record elapsed time, take a stack or thread dump, or record the number of times the
monitored code has been called. Three types of monitors can be defined: before, after or around.
Note that the MethodInvocationStatisticsAction aggregates information for each monitor and stores it
in an in-memory JMX MBean that can be queried.
A diagnostic system module is also required. Diagnostic application modules only contain application
scoped monitors. System modules contain system-scoped monitors and other WLDF configuration
data, such as that for the harvester, watches, and notifications. Note that instrumentation must be
enabled in a system module that is targeted to each server. This allows it to be easily switched on or
off. Each server can have at most one targeted diagnostic system module. To create a diagnostic
system module use the WebLogic Console. We simply need to target the module to the appropriate
server and enable instrumentation using the Enabled checkbox on the Instrumentation Configuration
tab.
The information recorded by the MethodInvocationStatisticsAction is available through the
application's WLDFInstrumentationRuntime MBean. This MBean has a MethodInvocationStatistics
attribute that returns a nested set of maps containing of all the recorded statistics for the application. It
also has an getMethodInvocationStatisticsData() operation that allows you to query for a subset of the
data. The example WLST script queries the WLDFInstrumentationRuntimeMBean and displays the
results
connect('username','password');
cd('serverRuntime:/WLDFRuntime/WLDFRuntime/WLDFInstrumentationRuntimes/<application-name>');
def formatTime(t):
return "%.2f" % (t/1e6)
print('OBTAINING STATISTICS');
for classStats in cmo.getMethodInvocationStatistics().entrySet():
print('OBTAINED THE CLASS STATISTICS');
for methodStats in classStats.value.entrySet():
print('OBTAINED THE METHOD STATISTICS');
for signatureStats in methodStats.value.entrySet():
print('PRINTING SOME OUTPUT');
print "%s.%s(): %d %s %s %s %s" % (
classStats.key,
methodStats.key,
signatureStats.value['count'],
formatTime(signatureStats.value['min']),
formatTime(signatureStats.value['avg']),
formatTime(signatureStats.value['max']),
formatTime(signatureStats.value['std_deviation']),)
PATH=${JAVA_HOME}/bin:${PATH}
export PATH
# Memory arguments for optimizing the throughput using JRockit
USER_MEM_ARGS="-Xms512m -Xmx512m -Xss128k -Xgcprio:throughput"
export USER_MEM_ARGS
startConsole.sh
#!/bin/sh
. /home/oracle/grinder/grinder-3.4/setGrinderEnv.sh
java ${USER_MEM_ARGS} -cp ${CLASSPATH} net.grinder.Console
startAgent.sh
#!/bin/sh
. /home/oracle/grinder/grinder-3.4/setGrinderEnv.sh
java ${USER_MEM_ARGS} -cp ${CLASSPATH} net.grinder.Grinder ${GRINDERPROPERTIES}
The Grinder uses a python script to define which test to run, the http.py script defined in the properties
looks as follows:
# An example using the HTTP plugin that shows the retrieval of a single page via HTTP.
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
test1 = Test(1, "Request resource")
request1 = test1.wrap(HTTPRequest())
class TestRunner:
def __call__(self):
result = request1.GET("http://localhost:7001/Bedrijf/testservlet")
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import
import
import
import
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
return bestelling;
}
private Bedrijf getBedrijf() {
Context context = null;
Bedrijf bedrijf = null;
try {
context = new InitialContext();
bedrijf = (Bedrijf)context.lookup("ejb/Bedrijf#datamodel.logic.Bedrijf");
} catch (NamingException e) {
e.printStackTrace();
}
return bedrijf;
}
}
To start the test run the startConsole script and subsequently run the startAgent script (use the
grinder console to send a start event to the agent). If we let the test run for a while and then run the
WLST script to get the instrumentation results, we have:
datamodel.logic.BedrijfBean.addKlant(): 33994 0.28 1.44 2196.76 12.76
datamodel.logic.BedrijfMDB onMessage(): 33994 0.07 0.82 2197.10 12.32
Harvesting
A harvester is configured in a diagnostics system module. By using the WebLogic Console we can
access the diagnostic system module's Collected Metrics Configuration tab. Here we see that we can
specify the sampling period, which defaults to 5 minutes. On the page we can also add harvesting
rules to collect data from built-in MBeans. For example, we might want to record the number of JDBC
connections in use. By using the WebLogic Console we define a new harvesting metric that collects
the value of the ActiveConnectionsCurrentCount attribute of the JDBCDataSourceRuntime MBean by
selecting the MBean and the attribute from the provided lists. To configure a harvester:
We can also capture the statistics from the application WLDFInstrumentationRuntime MBean. In this
case, we have to provide an attribute expression in a particular form, for example,
MethodInvocationStatistics(*)(*)(*)(count|avg|min|max). This expression harvests the count, average,
minimum, and maximum statistics from monitors that use the MethodInvocationStatisticsAction.
The listing below shows the configuration file for the diagnostic system module having configured it to
harvest from the JDBCDataSourceRuntime and WLDFInstrumentationRuntime MBeans.
<wldf-resource ...>
<name>MySystemModule</name>
<instrumentation>
<enabled>true</enabled>
</instrumentation>
<harvester>
<harvested-type>
<name>weblogic.management.runtime.JDBCDataSourceRuntimeMBean</name>
<harvested-attribute>ActiveConnectionsCurrentCount</harvestedattribute>
<harvestedinstance>com.bea:Name=VideotheekDataSource,ServerRuntime=AdminServer,Type=JDBCDataSourceRuntim
e</harvested-instance>
<namespace>ServerRuntime</namespace>
</harvested-type>
<harvested-type>
<name>weblogic.management.runtime.WLDFInstrumentationRuntimeMBean</name>
<harvestedattribute>MethodInvocationStatistics(*)(*)(*)(avg,count,min,max)</harvested-attribute>
</harvested-type>
</harvester>
</wldf-resource>
The servers to which the diagnostic module is targeted are now recording information in their
diagnostic archives. By using the WLDF console extension, we can see the information captured from
the JDBCDataSourceRuntime MBean. To enable the WLDF console extension, copy the file
diagnostics-console-extension.jar located in the directory ${WL_HOME}/server/lib/console-ext, and
copy this file to the directory ${DOMAIN_HOME}/console-ext. Click in the admin console on
Preferences, select the Extensions tab and enable diagnostics-console-extension. Restart the admin
server.
Due to its complex format, the WLDF console extension cannot display the data from the
WLDFInstrumentationRuntime MBean. To get at the data, we have to export it from the archive, for
example, by using the following WLST commands,
# connect to the appropriate server
connect('username','password', 't3://hostname:port');
# use the exportDiagnosticDataFromServer command to export the data
# valid values for logicalName are: HarvestedDataArchive, EventsDataArchive, ServerLog,
DomainLog, HTTPAccessLog, WebAppLog, ConnectorLog, and JMSMessageLog.
exportDiagnosticDataFromServer(logicalName="HarvestedDataArchive",
exportFileName="export.xml");
The data is exported in an XML format that represents a set of tabular rows.
Each WebLogic server has a persistent diagnostic archive that is used to store captured data. The
archive can be persisted using either a file-based or JDBC-based persistent store. Be wary of
instrumenting too many methods, harvesting too many metrics, or using a very short sampling period.
This will quickly fill up the archive, and the overhead of the instrumentation may become measurable.
The data in the archive obviously cannot be allowed to grow indefinitely. WebLogic Server allows data
retirement policies to be set for a each class of data in the diagnostic archive that regularly deletes
data of a certain age. Data retirement policies can be used for both file- and database-based stores.
For file stores, a preferred maximum size can also be configured - WebLogic Server will regularly
remove old records to keep the file below the configured size.
Click the tab Watches and Notifications, Notifications and click New.
Select as Type: JMS Message and click Next.
Enter a Notification Name, for example JVMNotification and click Next.
Enter the JNDI's of the destination and the connection factory and click Finish.
Click the tab Watches and click New.
Enter a Watch Name and select as Watch Type: Collected Metrics, click Next.
Click Add Expressions, MBean Server: ServerRuntime, Next, MBean Type:
JVMRuntimeMBean, Next, Select the same server instance as the chosen in the harvester,
Next, select Message Attribute: HeapFreeCurrent, select operator: <, enter as value:
10000000, click Finish.
Click Next and click Use an automatic reset alarm, for example of 60 seconds.
Click Next and select the configured notification.
Click Finish.
Last but not least we can also create scripts that perform checks on WebLogic servers and deployed
applications, for example
class DeploymentInfo:
def __init__(self,name,target):
self.name = name;
self.target = target;
def getName(self):
return self.name;
def getTarget(self):
return self.target;
print 'CONNECT TO ADMIN SERVER';
connect('username', 'password');
print 'OBTAINING DEPLOYMENT INFORMATION';
deploymentsInfo = [];
applications = cmo.getAppDeployments();
for application in applications:
name = application.getName();
target = application.getTargets()[0].getName();
deploymentsInfo.append(DeploymentInfo(name, target));
libraries = cmo.getLibraries();
for library in libraries:
name = library.getName();
target = library.getTargets()[0].getName();
deploymentsInfo.append(DeploymentInfo(name, target));
print 'CHANGE TO DOMAIN RUNTIME ENVIRONMENT';
domainRuntime();
print 'SERVER LIFE CYCLE INFORMATION';
serverLifeCycles = cmo.getServerLifeCycleRuntimes();
for serverLifeCycle in serverLifeCycles:
print 'Server: ' + serverLifeCycle.getName() + ', State: ' +
serverLifeCycle.getState();
if (serverLifeCycle.getState() == 'RUNNING'):
cd('ServerRuntimes/' + serverLifeCycle.getName());
jvm = cmo.getJVMRuntime();
print 'Java VM Vendor: ' + jvm.getJavaVMVendor();
print 'Heap Free Space: ' + repr(jvm.getHeapFreePercent()) + '%';
print 'Heap Size Current: ' + repr(jvm.getHeapSizeCurrent());
print 'Maximum Heap Size: ' + repr(jvm.getHeapSizeMax());
cd('/');
if (serverLifeCycle.getState() != 'RUNNING'):
start(serverLifeCycle.getName(), 'Server');
print 'APPLICATION LIFE CYCLE INFORMATION';
applicationRuntime = cmo.getAppRuntimeStateRuntime();
for deploymentInfo in deploymentsInfo:
state = applicationRuntime.getCurrentState(deploymentInfo.getName(),
deploymentInfo.getTarget())
print 'Application: ' + deploymentInfo.getName() + ', State: ' + state;
if (state != 'STATE_ACTIVE'):
startApplication(deploymentInfo.getName());
The script prints information about the heap usage of the JVM. It also checks if the servers are still
running and if they are not the script starts them. The same is done for all the deployed applications
and libraries on the WebLogic servers.
WebLogic rules!