You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by wo...@apache.org on 2004/03/13 06:58:31 UTC
cvs commit: jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers MonitorAccumModel.java ServerPanel.java MonitorStats.java MonitorModel.java MonitorHealthPanel.java MonitorTabPane.java MonitorPerformancePanel.java MonitorHealthVisualizer.java MonitorGuiListener.java MonitorListener.java MonitorGraph.java
woolfel 2004/03/12 21:58:31
Added: src/monitor/components/org/apache/jmeter/monitor/util
Stats.java
src/monitor/components/org/apache/jmeter/visualizers
MonitorAccumModel.java ServerPanel.java
MonitorStats.java MonitorModel.java
MonitorHealthPanel.java MonitorTabPane.java
MonitorPerformancePanel.java
MonitorHealthVisualizer.java
MonitorGuiListener.java MonitorListener.java
MonitorGraph.java
Log:
Adding the source to CVS, but I'm going to wait to add the build
task to compile and package the monitor. Once I get the custom
parser ready I will add the ANT task.
peter lin
Revision Changes Path
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/monitor/util/Stats.java
Index: Stats.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.monitor.util;
import javax.xml.bind.*;
import org.apache.jorphan.tomcat.manager.*;
/**
*
* Description:<p>
* Stats is responsible for calculating the load and
* health of a given server. It uses tomcat's status
* servlet results. A schema was generated for the
* XML output and JAXB was used to generate classes.
* <p>
* The equations are:<p>
* memory weight = (int)(33 * (used/max))<br>
* thread weight = (int)(67 * (current/max))<p>
* The load factors are stored in the properties
* files. Simply change the values in the properties
* to change how load is calculated. The defaults
* values are memory (33) and threads (67). The sum
* of the factors must equal 100.
*/
public class Stats
{
public static final int DEAD = 0;
public static final int ACTIVE = 2;
public static final int WARNING = 1;
public static final int HEALTHY = 3;
public static int DEFAULT_MEMORY_FACTOR = 50;
public static int DEFAULT_THREAD_FACTOR = 50;
public static double HEALTHY_PER = 0.00;
public static double ACTIVE_PER = 0.25;
public static double WARNING_PER = 0.67;
/**
* The method is responsible for taking a status
* object and calculating an int value from 1 to
* 100. We use a combination of free memory and
* free threads. Since memory is a bigger risk,
* it counts for 2/3.<p>
* @param stat
* @return
*/
public static int calculateLoad(Status stat){
if (stat != null){
// equation for calculating the weight
// w = (int)(33 * (used/max))
long totMem = stat.getJvm().getMemory().getTotal();
long usedMem = stat.getJvm().getMemory().getFree();
double memdiv = (double)usedMem/(double)totMem;
double memWeight = DEFAULT_MEMORY_FACTOR * memdiv;
Connector cntr = (Connector)stat.getConnector().get(0);
int maxThread = cntr.getThreadInfo().getMaxThreads();
int curThread = cntr.getThreadInfo().getCurrentThreadsBusy();
double thdiv = (double)curThread/(double)maxThread;
double threadWeight = DEFAULT_THREAD_FACTOR * thdiv;
return (int)(memWeight + threadWeight);
} else {
return 0;
}
}
/**
* Method should calculate if the server is:
* dead, active, warning or healthy. We do
* this by looking at the current busy threads.
* <ol>
* <li> free > spare is healthy
* <li> free < spare is active
* <li> busy threads > 75% is warning
* <li> none of the above is dead
* </ol>
* @param stat
* @return
*/
public static int calculateStatus(Status stat){
if (stat != null){
Connector cntr = (Connector)stat.getConnector().get(0);
int max = cntr.getThreadInfo().getMaxThreads();
int current = cntr.getThreadInfo().getCurrentThreadsBusy();
int spare = cntr.getThreadInfo().getMaxSpareThreads();
double per = (double)current/(double)max;
if (per > WARNING_PER){
return WARNING;
} else if (per >= ACTIVE_PER && per <= WARNING_PER){
return ACTIVE;
} else if (per < ACTIVE_PER && per > HEALTHY_PER){
return HEALTHY;
} else {
return DEAD;
}
} else {
return DEAD;
}
}
/**
* Method will calculate the memory load:
* used / max = load. The load value is an
* integer between 1 and 100. It is the
* percent memory used.
* @param stat
* @return
*/
public static int calculateMemoryLoad(Status stat){
double load = 0;
if (stat != null){
double total = (double)stat.getJvm().getMemory().getTotal();
double used = (double)stat.getJvm().getMemory().getFree();
load = (used/total);
}
return (int)(load * 100);
}
/**
* Method will calculate the thread load:
* busy / max = load. The value is an
* integer between 1 and 100. It is the
* percent busy.
* @param stat
* @return
*/
public static int calculateThreadLoad(Status stat){
int load = 0;
if (stat != null){
Connector cntr = (Connector)stat.getConnector().get(0);
double max = (double)cntr.getThreadInfo().getMaxThreads();
double current =
(double)cntr.getThreadInfo().getCurrentThreadsBusy();
load = (int)((current/max) * 100);
}
return load;
}
/**
* Simple unit test to make sure it works correctly.
* Will write a JUnit test later for this.
* @param args
*/
public static void main(String[] args)
{
try {
JAXBContext jxbc = new ObjectFactory();
// ObjectFactory.newInstance("org.apache.jorphan.tomcat.manager");
Unmarshaller mar = jxbc.createUnmarshaller();
Object ld = mar.unmarshal(new java.io.File("status3.xml"));
System.out.println("successfully unmarshalled sample status");
if (ld instanceof Status){
System.out.println("status is " + calculateStatus((Status)ld));
System.out.println("load is " + calculateLoad((Status)ld));
System.out.println("mem load is " + calculateMemoryLoad((Status)ld));
System.out.println("th load is " + calculateThreadLoad((Status)ld));
}
} catch (JAXBException e){
e.printStackTrace();
}
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorAccumModel.java
Index: MonitorAccumModel.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import java.io.ByteArrayInputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jorphan.tomcat.manager.*;
import org.apache.jmeter.monitor.util.Stats;
import org.apache.jmeter.protocol.http.sampler.HTTPSampleResult;
public class MonitorAccumModel implements Clearable, Serializable
{
private HashMap MAP;
private MonitorModel CURRENT;
private List listeners;
/**
* By default, we set the default to 800
*/
private int DEFAULT_BUFFER = 800;
/**
*
*/
public MonitorAccumModel()
{
MAP = new HashMap();
listeners = new LinkedList();
}
public int getBufferSize(){
return DEFAULT_BUFFER;
}
public void setBufferSize(int buffer){
DEFAULT_BUFFER = buffer;
}
/**
* Method will look up the server in the map. The
* MonitorModel will be added to an existing list,
* or a new one will be created.
* @param model
*/
public void addSample(MonitorModel model){
this.CURRENT = model;
if (MAP.containsKey(model.getURL())){
List newlist = updateArray(model,(List)MAP.get(model.getURL()));
MAP.put(model.getURL(),newlist);
} else {
List samples = Collections.synchronizedList(new LinkedList());
samples.add(model);
MAP.put(model.getURL(),samples);
}
}
/**
* We want to keep only 240 entries for each server,
* so we handle the object array ourselves.
* @param model
*/
private List updateArray(MonitorModel model, List list){
if (list.size() < DEFAULT_BUFFER){
list.add(model);
} else {
list.add(model);
list.remove(0);
}
return list;
}
/**
* Get all MonitorModels matching the URL.
* @param url
* @return
*/
public List getAllSamples(String url){
if (!MAP.containsKey(url)){
return Collections.synchronizedList(new LinkedList());
} else {
return (List)MAP.get(url);
}
}
/**
* Get the MonitorModel matching the url.
* @param url
* @return
*/
public MonitorModel getSample(String url){
if (MAP.containsKey(url)){
ArrayList list = (ArrayList)MAP.get(url);
return (MonitorModel)list.get(0);
} else {
return null;
}
}
/**
* Method will try to parse the response data. If the
* request was a monitor request, but the response was
* incomplete, bad or the server refused the connection,
* we will set the server's health to "dead". If the
* request was not a monitor sample, the method will
* ignore it.
* @param sample
*/
public void addSample(SampleResult sample){
URL surl = null;
if (sample instanceof HTTPSampleResult){
surl = ((HTTPSampleResult)sample).getURL();
}
String rescontent = new String(sample.getResponseData());
if (sample.getResponseCode().equals("200") &&
((HTTPSampleResult)sample).isMonitor()){
try {
JAXBContext jxbc = new ObjectFactory();
Unmarshaller mar = jxbc.createUnmarshaller();
String resdata = new String(sample.getResponseData());
// we trim because SAX still has a problem if there
// extra linebreaks at the beginning. That has been
// around for a long time.
resdata = resdata.trim();
resdata = resdata.replaceAll("\"?\"","\"0\"");
StreamSource ss = new StreamSource(
new ByteArrayInputStream(resdata.getBytes()));
Object ld =
mar.unmarshal(ss);
if (ld instanceof Status){
Status st = (Status)ld;
MonitorStats stat =
new MonitorStats(Stats.calculateStatus(st),
Stats.calculateLoad(st),
0,
Stats.calculateMemoryLoad(st),
Stats.calculateThreadLoad(st),
surl.getHost(),
String.valueOf(surl.getPort()),
surl.getProtocol(),
System.currentTimeMillis());
MonitorModel mo = new MonitorModel(stat);
this.addSample(mo);
notifyListeners(mo);
}
} catch (JAXBException e){
// we don't log the errors
// e.printStackTrace();
noResponse(surl);
}
} else if (((HTTPSampleResult)sample).isMonitor() ){
noResponse(surl);
}
}
/**
* If there is no response from the server, we
* create a new MonitorStats object with the
* current timestamp and health "dead".
* @param url
*/
public void noResponse(URL url){
notifyListeners(createNewMonitorModel(url));
}
public MonitorModel createNewMonitorModel(URL url){
MonitorStats stat = new MonitorStats(Stats.DEAD,
0,
0,
0,
0,
url.getHost(),
String.valueOf(url.getPort()),
url.getProtocol(),
System.currentTimeMillis());
MonitorModel mo = new MonitorModel(stat);
return mo;
}
/**
* Clears everything.
*/
public void clear(){
listeners.clear();
this.MAP.clear();
}
/**
* notify the listeners with the MonitorModel object.
* @param model
*/
public void notifyListeners(MonitorModel model)
{
for (int idx=0; idx < listeners.size(); idx++){
MonitorListener ml = (MonitorListener)listeners.get(idx);
ml.addSample(model);
}
}
/**
* Add a listener. When samples are added, the class will
* notify the listener of the change.
* @param listener
*/
public void addListener(MonitorListener listener){
listeners.add(listener);
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/ServerPanel.java
Index: ServerPanel.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JLabel;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.monitor.util.Stats;
/**
* The purpose of ServerPanel is to display an unique
* server and its current status. The server label
* consist of the protocol, host and port. For example,
* a system with multiple Tomcat's running on different
* ports would be different ServerPanel.
*/
public class ServerPanel extends JPanel
implements MonitorGuiListener
{
private JLabel serverField;
private JLabel timestampField;
/**
* Preference size for the health icon
*/
private Dimension prefsize = new Dimension(25,75);
private JLabel healthIcon;
private JLabel loadIcon;
/**
* Health Icons
*/
public static final ImageIcon HEALTHY =
JMeterUtils.getImage("monitor-healthy.gif");
public static final ImageIcon ACTIVE =
JMeterUtils.getImage("monitor-active.gif");
public static final ImageIcon WARNING =
JMeterUtils.getImage("monitor-warning.gif");
public static final ImageIcon DEAD =
JMeterUtils.getImage("monitor-dead.gif");
/**
* Load Icons
*/
public static final ImageIcon LOAD_1 =
JMeterUtils.getImage("monitor-load-1.gif");
public static final ImageIcon LOAD_2 =
JMeterUtils.getImage("monitor-load-2.gif");
public static final ImageIcon LOAD_3 =
JMeterUtils.getImage("monitor-load-3.gif");
public static final ImageIcon LOAD_4 =
JMeterUtils.getImage("monitor-load-4.gif");
public static final ImageIcon LOAD_5 =
JMeterUtils.getImage("monitor-load-5.gif");
public static final ImageIcon LOAD_6 =
JMeterUtils.getImage("monitor-load-6.gif");
public static final ImageIcon LOAD_7 =
JMeterUtils.getImage("monitor-load-7.gif");
public static final ImageIcon LOAD_8 =
JMeterUtils.getImage("monitor-load-8.gif");
public static final ImageIcon LOAD_9 =
JMeterUtils.getImage("monitor-load-9.gif");
public static final ImageIcon LOAD_10 =
JMeterUtils.getImage("monitor-load-10.gif");
private MonitorModel DATA;
/**
*
*/
public ServerPanel(MonitorModel model)
{
super();
DATA = model;
init(model);
}
/**
* Init will create the JLabel widgets for the
* host, health, load and timestamp.
* @param model
*/
private void init(MonitorModel model)
{
this.setLayout(new FlowLayout());
serverField = new JLabel(model.getURL());
this.add(serverField);
healthIcon = new JLabel(getHealthyImageIcon(model.getHealth()));
healthIcon.setPreferredSize(prefsize);
this.add(healthIcon);
loadIcon = new JLabel(getLoadImageIcon(model.getLoad()));
this.add(loadIcon);
timestampField = new JLabel(model.getTimestampString());
this.add(timestampField);
}
/**
* Static method for getting the right ImageIcon for
* the health.
* @param health
* @return
*/
public static ImageIcon getHealthyImageIcon(int health){
ImageIcon i = null;
switch(health){
case Stats.HEALTHY:
i = HEALTHY;
break;
case Stats.ACTIVE:
i = ACTIVE;
break;
case Stats.WARNING:
i = WARNING;
break;
case Stats.DEAD:
i = DEAD;
break;
}
return i;
}
/**
* Static method looks up the right ImageIcon from
* the load value.
* @param load
* @return
*/
public static ImageIcon getLoadImageIcon(int load){
if (load <= 10){
return LOAD_1;
} else if (load > 10 && load <= 20){
return LOAD_2;
} else if (load > 20 && load <= 30){
return LOAD_3;
} else if (load > 30 && load <= 40){
return LOAD_4;
} else if (load > 40 && load <= 50){
return LOAD_5;
} else if (load > 50 && load <= 60){
return LOAD_6;
} else if (load > 60 && load <= 70){
return LOAD_7;
} else if (load > 70 && load <= 80){
return LOAD_8;
} else if (load > 80 && load <= 90){
return LOAD_9;
} else {
return LOAD_10;
}
}
/**
* Method will update the ServerPanel's health, load,
* and timestamp. For efficiency, it uses the static
* method to lookup the images.
*/
public void updateGui(MonitorModel stat){
this.DATA = null;
this.DATA = stat;
loadIcon.setIcon(getLoadImageIcon(stat.getLoad()));
healthIcon.setIcon(getHealthyImageIcon(stat.getHealth()));
timestampField.setText(stat.getTimestampString());
this.updateGui();
}
/**
* update the gui
*/
public void updateGui(){
this.repaint();
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorStats.java
Index: MonitorStats.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import java.io.Serializable;
public class MonitorStats implements Serializable
{
public int health;
public int load;
public int cpuload;
public int memload;
public int threadload;
public String host;
public String port;
public String protocol;
public long timestamp;
/**
*
*/
public MonitorStats()
{
super();
}
/**
* Default constructor
* @param health
* @param load
* @param cpuload
* @param memload
* @param threadload
* @param host
* @param port
* @param protocol
* @param time
*/
public MonitorStats(int health,
int load,
int cpuload,
int memload,
int threadload,
String host,
String port,
String protocol,
long time){
this.health = health;
this.load = load;
this.cpuload = cpuload;
this.memload = memload;
this.threadload = threadload;
this.host = host;
this.port = port;
this.protocol = protocol;
this.timestamp = time;
}
/**
* For convienance, this method returns the protocol,
* host and port as a URL.
* @return
*/
public String getURL(){
return protocol + "://" + host + ":" + port;
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorModel.java
Index: MonitorModel.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import java.io.Serializable;
import org.apache.jmeter.samplers.Clearable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class MonitorModel implements Clearable, Serializable, Cloneable
{
private String name;
private List listeners;
private MonitorStats current =
new MonitorStats(0,0,0,0,0,"","","",System.currentTimeMillis());
/**
*
*/
public MonitorModel()
{
super();
listeners = new LinkedList();
}
public MonitorModel(MonitorStats stat){
this.current = stat;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.getURL();
}
public int getHealth(){
return this.current.health;
}
public int getLoad(){
return this.current.load;
}
public int getCpuload(){
return this.current.cpuload;
}
public int getMemload(){
return this.current.memload;
}
public int getThreadload(){
return this.current.threadload;
}
public String getHost(){
return this.current.host;
}
public String getPort(){
return this.current.port;
}
public String getProtocol(){
return this.current.protocol;
}
public long getTimestamp(){
return this.current.timestamp;
}
public String getURL(){
return this.current.getURL();
}
public String getTimestampString(){
Date date = new Date(this.current.timestamp);
SimpleDateFormat ft = new SimpleDateFormat();
return ft.format(date);
}
/**
* Method is used by DefaultMutableTreeNode to get
* the label for the node.
*/
public String toString(){
return getURL();
}
/* (non-Javadoc)
* @see org.apache.jmeter.samplers.Clearable#clear()
*/
public void clear()
{
current =
new MonitorStats(0,0,0,0,0,"","","",System.currentTimeMillis());
}
/**
* notify the listeners with the MonitorModel object.
* @param model
*/
public void notifyListeners(MonitorModel model)
{
for (int idx=0; idx < listeners.size(); idx++){
MonitorListener ml = (MonitorListener)listeners.get(idx);
ml.addSample(model);
}
}
public void addListener(MonitorListener listener){
listeners.add(listener);
}
public Object clone(){
MonitorStats newstats =
new MonitorStats(current.health,
current.load,
current.cpuload,
current.memload,
current.threadload,
current.host,
current.port,
current.protocol,
current.timestamp);
return new MonitorModel(newstats);
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorHealthPanel.java
Index: MonitorHealthPanel.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.util.HashMap;
import java.util.Random;
import javax.swing.JScrollPane;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.samplers.Clearable;
/**
* The health panel is responsible for showing the health
* of the servers. It only uses the most current information
* to show the status.
*/
public class MonitorHealthPanel extends JPanel
implements MonitorListener, Clearable
{
private HashMap SERVERMAP = new HashMap();
private JPanel SERVERS = null;
private MonitorAccumModel MODEL;
private JScrollPane SCROLL = null;
Font plainText = new Font("plain", Font.PLAIN, 9);
public static final String INFO_H =
JMeterUtils.getResString("monitor_equation_healthy");
public static final String INFO_A =
JMeterUtils.getResString("monitor_equation_active");
public static final String INFO_W =
JMeterUtils.getResString("monitor_equation_warning");
public static final String INFO_D =
JMeterUtils.getResString("monitor_equation_dead");
public static final String INFO_LOAD =
JMeterUtils.getResString("monitor_equation_load");
/**
*
*/
public MonitorHealthPanel(MonitorAccumModel model)
{
this.MODEL = model;
this.MODEL.addListener(this);
init();
}
private void init(){
this.setLayout(new BorderLayout());
ImageIcon legend = JMeterUtils.getImage("monitor-legend.gif");
JLabel label = new JLabel(legend);
label.setPreferredSize(new Dimension(550,25));
this.add(label,BorderLayout.NORTH);
this.SERVERS = new JPanel();
this.SERVERS.setLayout(new BoxLayout(SERVERS, BoxLayout.Y_AXIS));
this.SERVERS.setAlignmentX(Component.LEFT_ALIGNMENT);
SCROLL = new JScrollPane(this.SERVERS);
SCROLL.setPreferredSize(new Dimension(300,300));
this.add(SCROLL,BorderLayout.CENTER);
// the equations
String eqstring1 = " " + INFO_H + " | " + INFO_A;
String eqstring2 = " " + INFO_W + " | " + INFO_D;
String eqstring3 = " " + INFO_LOAD;
JLabel eqs = new JLabel();
eqs.setLayout(new BorderLayout());
eqs.setPreferredSize(new Dimension(500,60));
eqs.add(new JLabel(eqstring1),BorderLayout.NORTH);
eqs.add(new JLabel(eqstring2),BorderLayout.CENTER);
eqs.add(new JLabel(eqstring3),BorderLayout.SOUTH);
this.add(eqs,BorderLayout.SOUTH);
}
public void createTestData(){
Random ran = new Random(System.currentTimeMillis());
for (int idx = 0; idx < 21; idx++){
MonitorStats stat = new MonitorStats();
stat.host = "localhost" + idx;
stat.port = "8080";
stat.protocol = "http";
stat.health = ran.nextInt(3);
stat.load = ran.nextInt(100);
stat.timestamp = (System.currentTimeMillis() - ran.nextLong());
MonitorModel mm = new MonitorModel(stat);
ServerPanel sp = new ServerPanel(mm);
this.SERVERMAP.put(stat.getURL(),sp);
this.SERVERS.add(sp);
}
}
/**
*
* @param stats
*/
public void addSample(MonitorModel model){
if (SERVERMAP.containsKey(model.getURL())){
ServerPanel pane = null;
if(SERVERMAP.get(model.getURL()) != null){
pane = (ServerPanel)SERVERMAP.get((model.getURL()));
} else {
pane = new ServerPanel(model);
SERVERMAP.put(model.getURL(),pane);
}
pane.updateGui(model);
this.SERVERS.updateUI();
} else {
ServerPanel newpane = new ServerPanel(model);
SERVERMAP.put(model.getURL(),newpane);
this.SERVERS.add(newpane);
newpane.updateGui(model);
this.SERVERS.updateUI();
}
}
public void clear(){
this.SERVERS.removeAll();
this.SERVERS.updateUI();
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorTabPane.java
Index: MonitorTabPane.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import javax.swing.JTabbedPane;
public class MonitorTabPane extends JTabbedPane
{
/**
*
*/
public MonitorTabPane()
{
super(TOP);
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorPerformancePanel.java
Index: MonitorPerformancePanel.java
===================================================================
/*
* Created on Mar 8, 2004
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package org.apache.jmeter.visualizers;
import java.util.HashMap;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import org.apache.jmeter.gui.util.JMeterColor;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.util.JMeterUtils;
public class MonitorPerformancePanel extends JSplitPane
implements TreeSelectionListener, MonitorListener, Clearable
{
private JScrollPane TREEPANE;
private JPanel GRAPHPANEL;
private JTree SERVERTREE;
private DefaultTreeModel TREEMODEL;
private MonitorGraph GRAPH;
private DefaultMutableTreeNode ROOTNODE;
private HashMap SERVERMAP;
private MonitorAccumModel MODEL;
private SampleResult ROOTSAMPLE;
public static final String LEGEND_HEALTH =
JMeterUtils.getResString("monitor_legend_health");
public static final String LEGEND_LOAD =
JMeterUtils.getResString("monitor_legend_load");
public static final String LEGEND_MEM =
JMeterUtils.getResString("monitor_legend_memory_per");
public static final String LEGEND_THREAD =
JMeterUtils.getResString("monitor_legend_thread_per");
public static ImageIcon LEGEND_HEALTH_ICON =
JMeterUtils.getImage("monitor-green-legend.gif");
public static ImageIcon LEGEND_LOAD_ICON =
JMeterUtils.getImage("monitor-blue-legend.gif");
public static ImageIcon LEGEND_MEM_ICON =
JMeterUtils.getImage("monitor-orange-legend.gif");
public static ImageIcon LEGEND_THREAD_ICON =
JMeterUtils.getImage("monitor-red-legend.gif");
public static final String GRID_LABEL_TOP =
JMeterUtils.getResString("monitor_label_left_top");
public static final String GRID_LABEL_MIDDLE =
JMeterUtils.getResString("monitor_label_left_middle");
public static final String GRID_LABEL_BOTTOM =
JMeterUtils.getResString("monitor_label_left_bottom");
public static final String GRID_LABEL_HEALTHY =
JMeterUtils.getResString("monitor_label_right_healthy");
public static final String GRID_LABEL_ACTIVE =
JMeterUtils.getResString("monitor_label_right_active");
public static final String GRID_LABEL_WARNING =
JMeterUtils.getResString("monitor_label_right_warning");
public static final String GRID_LABEL_DEAD =
JMeterUtils.getResString("monitor_label_right_dead");
public static final String PERF_TITLE =
JMeterUtils.getResString("monitor_performance_title");
public static final String SERVER_TITLE =
JMeterUtils.getResString("monitor_performance_servers");
protected Font plaintext = new Font("plain", Font.TRUETYPE_FONT, 10);
/**
*
*/
public MonitorPerformancePanel(MonitorAccumModel model, MonitorGraph graph)
{
super();
this.SERVERMAP = new HashMap();
this.MODEL = model;
this.MODEL.addListener(this);
this.GRAPH = graph;
init();
}
public void init(){
ROOTSAMPLE = new SampleResult();
ROOTSAMPLE.setSampleLabel(SERVER_TITLE);
ROOTSAMPLE.setSuccessful(true);
ROOTNODE = new DefaultMutableTreeNode(ROOTSAMPLE);
TREEMODEL = new DefaultTreeModel(ROOTNODE);
SERVERTREE = new JTree(TREEMODEL);
SERVERTREE.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
SERVERTREE.addTreeSelectionListener(this);
SERVERTREE.setShowsRootHandles(true);
TREEPANE = new JScrollPane(SERVERTREE);
TREEPANE.setPreferredSize(new Dimension(150,200));
this.add(TREEPANE,JSplitPane.LEFT);
this.setDividerLocation(0.18);
JPanel right = new JPanel();
right.setLayout(new BorderLayout());
JLabel title = new JLabel(" " + PERF_TITLE);
title.setPreferredSize(new Dimension(200,40));
GRAPHPANEL = new JPanel();
GRAPHPANEL.setLayout(new BorderLayout());
GRAPHPANEL.setMaximumSize(
new Dimension(MODEL.getBufferSize(),MODEL.getBufferSize()));
GRAPHPANEL.setBackground(JMeterColor.WHITE);
GRAPHPANEL.add(GRAPH,BorderLayout.CENTER);
right.add(GRAPHPANEL,BorderLayout.CENTER);
right.add(title,BorderLayout.NORTH);
right.add(createLegend(),BorderLayout.SOUTH);
right.add(createLeftGridLabels(),BorderLayout.WEST);
right.add(createRightGridLabels(),BorderLayout.EAST);
this.add(right,JSplitPane.RIGHT);
}
public JPanel createLegend(){
Dimension lsize = new Dimension(130,18);
JPanel legend = new JPanel();
legend.setLayout(new FlowLayout());
JLabel health = new JLabel(LEGEND_HEALTH);
health.setFont(plaintext);
health.setPreferredSize(lsize);
health.setIcon(LEGEND_HEALTH_ICON);
legend.add(health);
JLabel load = new JLabel(LEGEND_LOAD);
load.setFont(plaintext);
load.setPreferredSize(lsize);
load.setIcon(LEGEND_LOAD_ICON);
legend.add(load);
JLabel mem = new JLabel(LEGEND_MEM);
mem.setFont(plaintext);
mem.setPreferredSize(lsize);
mem.setIcon(LEGEND_MEM_ICON);
legend.add(mem);
JLabel thd = new JLabel(LEGEND_THREAD);
thd.setFont(plaintext);
thd.setPreferredSize(lsize);
thd.setIcon(LEGEND_THREAD_ICON);
legend.add(thd);
return legend;
}
public JPanel createLeftGridLabels(){
Dimension lsize = new Dimension(33,20);
JPanel labels = new JPanel();
labels.setLayout(new BorderLayout());
JLabel top = new JLabel(" " + GRID_LABEL_TOP);
top.setFont(plaintext);
top.setPreferredSize(lsize);
labels.add(top,BorderLayout.NORTH);
JLabel mid = new JLabel(" " + GRID_LABEL_MIDDLE);
mid.setFont(plaintext);
mid.setPreferredSize(lsize);
labels.add(mid,BorderLayout.CENTER);
JLabel bottom = new JLabel(" " + GRID_LABEL_BOTTOM);
bottom.setFont(plaintext);
bottom.setPreferredSize(lsize);
labels.add(bottom,BorderLayout.SOUTH);
return labels;
}
public JPanel createRightGridLabels(){
JPanel labels = new JPanel();
labels.setLayout(new BorderLayout());
labels.setPreferredSize(new Dimension(40,GRAPHPANEL.getWidth() - 100));
Dimension lsize = new Dimension(40,20);
JLabel h = new JLabel(GRID_LABEL_HEALTHY);
h.setFont(plaintext);
h.setPreferredSize(lsize);
labels.add(h,BorderLayout.NORTH);
JLabel d = new JLabel(GRID_LABEL_DEAD);
d.setFont(plaintext);
d.setPreferredSize(lsize);
labels.add(d,BorderLayout.SOUTH);
return labels;
}
public void addSample(MonitorModel model){
if (!SERVERMAP.containsKey(model.getURL())){
DefaultMutableTreeNode newnode =
new DefaultMutableTreeNode(model);
newnode.setAllowsChildren(false);
SERVERMAP.put(model.getURL(),newnode);
ROOTNODE.add(newnode);
TREEPANE.updateUI();
}
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) SERVERTREE.getLastSelectedPathComponent();
Object usrobj = node.getUserObject();
if (usrobj instanceof MonitorModel){
GRAPH.updateGui((MonitorModel)usrobj);
}
}
/**
* When the user selects a different node in the
* tree, we get the selected node. From the node,
* we get the UserObject used to create the
* treenode in the constructor.
*/
public void valueChanged(TreeSelectionEvent e)
{
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) SERVERTREE.getLastSelectedPathComponent();
Object usrobj = node.getUserObject();
if (usrobj instanceof MonitorModel && usrobj != null){
MonitorModel mo = (MonitorModel)usrobj;
GRAPH.updateGui(mo);
this.updateUI();
}
TREEPANE.updateUI();
}
public void clear(){
this.SERVERMAP.clear();
ROOTNODE.removeAllChildren();
SERVERTREE.updateUI();
GRAPH.clear();
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorHealthVisualizer.java
Index: MonitorHealthVisualizer.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.Image;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.visualizers.gui.AbstractVisualizer;
/**
* For performance reasons, I am using tabs for the
* visualizers. Since a visualizer is heavy weight,
* I don not want to have two separate result
* collectors rather the same information. Instead,
* I would rather have the visualizer be the
* container for the data and simply pass the data
* to child JComponents.
*/
public class MonitorHealthVisualizer extends AbstractVisualizer
implements ImageVisualizer, ItemListener, GraphListener, Clearable
{
private MonitorTabPane TABPANE;
private MonitorHealthPanel HEALTHPANE;
private MonitorPerformancePanel PERFPANE;
private MonitorAccumModel MODEL;
private MonitorGraph GRAPH;
/**
* Constructor for the GraphVisualizer object.
*/
public MonitorHealthVisualizer()
{
MODEL = new MonitorAccumModel();
GRAPH = new MonitorGraph(MODEL);
init();
}
public String getStaticLabel()
{
return JMeterUtils.getResString("monitor_health_title");
}
/**
* Because of the unique requirements of a monitor
* We have to handle the results differently than
* normal GUI components. A monitor should be able
* to run for a very long time without eating up
* all the memory.
*/
public void add(SampleResult res)
{
MODEL.addSample(res);
}
public Image getImage()
{
Image result = GRAPH.createImage(this.getWidth(),this.getHeight());
Graphics image = result.getGraphics();
GRAPH.paintComponent(image);
return result;
}
public void itemStateChanged(ItemEvent e)
{
}
public synchronized void updateGui()
{
this.repaint();
}
public synchronized void updateGui(Sample s)
{
this.repaint();
}
/**
* Initialize the GUI.
*/
private void init()
{
this.setLayout(new BorderLayout());
// MAIN PANEL
Border margin = new EmptyBorder(10, 10, 5, 10);
this.setBorder(margin);
// Add the main panel and the graph
this.add(this.makeTitlePanel(), BorderLayout.NORTH);
this.createTabs();
}
protected void createTabs(){
TABPANE = new MonitorTabPane();
createHealthPane(TABPANE);
createPerformancePane(TABPANE);
this.add(TABPANE, BorderLayout.CENTER);
}
/**
* Create the JPanel
* @param pane
*/
public void createHealthPane(MonitorTabPane pane){
HEALTHPANE = new MonitorHealthPanel(MODEL);
pane.addTab(JMeterUtils.getResString("monitor_health_tab_title"),
HEALTHPANE);
}
/**
* Create the JSplitPane for the performance history
* @param pane
*/
public void createPerformancePane(MonitorTabPane pane){
PERFPANE = new MonitorPerformancePanel(MODEL,GRAPH);
pane.addTab(JMeterUtils.getResString("monitor_performance_tab_title"),
PERFPANE);
}
protected Container makeTitlePanel()
{
VerticalPanel titlePanel = new VerticalPanel();
titlePanel.add(createTitleLabel());
titlePanel.add(getNamePanel());
return titlePanel;
}
/**
* Clear will clear the MonitorAccumModel and create a
* new instance.
*/
public void clear(){
this.MODEL.clear();
this.HEALTHPANE.clear();
this.PERFPANE.clear();
}
public TestElement createTestElement()
{
if (collector == null)
{
collector = new ResultCollector();
}
modifyTestElement(collector);
return (TestElement) collector.clone();
}
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorGuiListener.java
Index: MonitorGuiListener.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
public interface MonitorGuiListener
{
void updateGui(MonitorModel event);
void updateGui();
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorListener.java
Index: MonitorListener.java
===================================================================
// $Header:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.visualizers;
public interface MonitorListener
{
public void addSample(MonitorModel model);
}
1.1 jakarta-jmeter/src/monitor/components/org/apache/jmeter/visualizers/MonitorGraph.java
Index: MonitorGraph.java
===================================================================
/*
* Created on Mar 9, 2004
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package org.apache.jmeter.visualizers;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;
import org.apache.jmeter.gui.util.JMeterColor;
import org.apache.jmeter.samplers.Clearable;
public class MonitorGraph
extends JComponent
implements MouseListener, MonitorGuiListener, Clearable
{
private static int width = 500;
private MonitorAccumModel MODEL;
private MonitorModel CURRENT;
private boolean CPU = false;
private boolean HEALTH = true;
private boolean LOAD = true;
private boolean MEM = true;
private boolean THREAD = true;
private boolean YGRID = true;
private boolean XGRID = true;
private int COUNT = 0;
private int GRAPHMAX = 0;
/**
*
*/
public MonitorGraph(MonitorAccumModel model)
{
this.MODEL = model;
GRAPHMAX = model.getBufferSize();
init();
}
private void init(){
repaint();
}
public void setCpu(boolean cpu){
this.CPU = cpu;
}
public void setHealth(boolean health){
this.HEALTH = health;
}
public void setLoad(boolean load){
this.LOAD = load;
}
public void setMem(boolean mem){
this.MEM = mem;
}
public void setThread(boolean thread){
this.THREAD = thread;
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
*/
public void mouseClicked(MouseEvent e)
{
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
public void mouseEntered(MouseEvent e)
{
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
*/
public void mouseExited(MouseEvent e)
{
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
*/
public void mousePressed(MouseEvent e)
{
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
*/
public void mouseReleased(MouseEvent e)
{
}
/* (non-Javadoc)
* @see org.apache.jmeter.visualizers.MonitorGuiListener#updateGui(org.apache.jmeter.visualizers.MonitorModel)
*/
public void updateGui(final MonitorModel model)
{
if (this.isShowing()){
this.CURRENT = model;
repaint();
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (this.CURRENT != null){
synchronized(MODEL){
List samples = MODEL.getAllSamples(this.CURRENT.getURL());
int size = samples.size();
synchronized (samples)
{
Iterator e;
if (size > getWidth()){
e = samples.listIterator(size - getWidth());
} else {
e = samples.iterator();
}
MonitorModel last = null;
for (int i = 0; e.hasNext(); i++)
{
MonitorModel s = (MonitorModel) e.next();
if (last == null){
last = s;
}
drawSample(i, s, g, last);
last = s;
}
}
}
}
}
/* (non-Javadoc)
* @see org.apache.jmeter.visualizers.MonitorGuiListener#updateGui()
*/
public void updateGui()
{
repaint();
}
/* (non-Javadoc)
* @see org.apache.jmeter.samplers.Clearable#clear()
*/
public void clear()
{
paintComponent(getGraphics());
this.repaint();
}
private void drawSample(int x, MonitorModel model,
Graphics g, MonitorModel last)
{
double width = (double)getWidth();
double height = (double)getHeight() - 10.0;
// int xaxis = (int)(x % width);
// int lastx = (int)((x - 1) % width);
int xaxis = (int)(width * (x /width));
int lastx = (int)(width * ((x - 1)/width));
// draw grid
if (YGRID && x == 1){
int q1 = (int)(height * 0.25);
int q2 = (int)(height * 0.50);
int q3 = (int)(height * 0.75);
g.setColor(JMeterColor.lightGray);
g.drawLine(0,q1,getWidth(),q1);
g.drawLine(0,q2,getWidth(),q2);
g.drawLine(0,q3,getWidth(),q3);
}
if (XGRID && x == 1){
int x1 = (int)(width * 0.25);
int x2 = (int)(width * 0.50);
int x3 = (int)(width * 0.75);
g.drawLine(x1,0,x1,getHeight());
g.drawLine(x2,0,x2,getHeight());
g.drawLine(x3,0,x3,getHeight());
g.drawLine(getWidth(),0,getWidth(),getHeight());
}
if (HEALTH)
{
int hly =
(int)(height - (height * ((double)model.getHealth()/3.0)));
int lasty =
(int)(height - (height * ((double)last.getHealth()/3.0)));
g.setColor(JMeterColor.GREEN);
g.drawLine(lastx,lasty,xaxis,hly);
}
if (LOAD)
{
int ldy =
(int)(height - (height * ((double)model.getLoad()/100.0)));
int lastldy =
(int)(height - (height * ((double)last.getLoad()/100.0)));
g.setColor(Color.BLUE);
g.drawLine(lastx,lastldy,xaxis,ldy);
}
if (MEM)
{
int mmy =
(int)(height - (height * ((double)model.getMemload()/100.0)));
int lastmmy =
(int)(height - (height * ((double)last.getMemload()/100.0)));
g.setColor(JMeterColor.ORANGE);
g.drawLine(lastx,lastmmy,xaxis,mmy);
}
if (THREAD)
{
int thy =
(int)(height - (height * ((double)model.getThreadload()/100.0)));
int lastthy =
(int)(height - (height * ((double)last.getThreadload()/100.0)));
g.setColor(Color.RED);
g.drawLine(lastx,lastthy,xaxis,thy);
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org