custom plugin

200 views
Skip to first unread message

mrbr...@gmail.com

unread,
Jul 25, 2011, 10:38:29 AM7/25/11
to jmeter-plugins
Hi all
writing a plugin, that will show threads of Tomcat and i have several
questions
The first is, which graph to extend better? My plugin will show only 1
line - actual http threads running on Tomcat server.
Suggestions?
Left src on work computer, so i will write out tomorrow with next
questions and issues if got some.
Sorry about mistakes, if any.
Thanks.

Andrey Pohilko

unread,
Jul 25, 2011, 10:44:56 AM7/25/11
to jmeter-...@googlegroups.com
Hmm, Jmeter has its native tomcat monitoring...

Take the "hits per second" graph, it draws just single line.

Brik

unread,
Jul 25, 2011, 2:06:32 PM7/25/11
to jmeter-plugins
> Hmm, Jmeter has its native tomcat monitoring...
Which of native graphs will show me actual number of threads on
tomcat?
>
> Take the "hits per second" graph, it draws just single line.
Thank for that. I will check it out

Andrey Pohilko

unread,
Jul 25, 2011, 2:15:56 PM7/25/11
to jmeter-...@googlegroups.com
I never used Tomcat, I just heard about "Monitor" features in JMeter:Ā http://jakarta.apache.org/jmeter/usermanual/component_reference.html#Monitor_Results


Brik

unread,
Jul 26, 2011, 1:24:22 AM7/26/11
to jmeter-plugins
Monitor Results is not what i need.
Can't add panel with host+port+login+password fields to the "Hits per
second" like it is in Perfmon plugin... Plugin is not visible in list
or jmeter throws exeptions.

Brik

unread,
Jul 26, 2011, 2:14:36 AM7/26/11
to jmeter-plugins
package kg.apc.jmeter.vizualizers;

import java.awt.*;
import java.lang.management.ThreadMXBean;
import javax.swing.*;
import javax.swing.event.TableModelListener;
import kg.apc.jmeter.JMeterPluginsUtils;
import kg.apc.jmeter.charting.AbstractGraphRow;
import kg.apc.jmeter.gui.ButtonPanelAddCopyRemove;
import org.apache.jmeter.gui.util.PowerTableModel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;

//TODO: add panel with server info, add the way to obtain info and
connect to server
// Find the way of getting tomcat threads, not sure of
getThreadCount() usage.


public class TomcatThreads
extends AbstractOverTimeVisualizer implements Clearable
{
public static final String[] columnIdentifiers = new String[]{
"Host / IP", "Port"
};

public static final Class[] columnClasses = new Class[]{
String.class, String.class
};
private static Object[] defaultValues = new Object[]{
"localhost", "4444", "", ""
};

private PowerTableModel tableModel;
JTable grid;
private JScrollPane scrollPan;
/**
*
*/
public TomcatThreads()
{
super();
setGranulation(1000);
graphPanel.getGraphObject().setyAxisLabel("Live threads");
init();
}

private void init()
{
setBorder(makeBorder());

// JPanel topContainer = new JPanel();
// topContainer.setLayout(new BorderLayout());

// JPanel containerPanel = new VerticalPanel();

// add(JMeterPluginsUtils.addHelpLinkToPanel(makeTitlePanel(),
getWikiPage()), BorderLayout.NORTH);
add(createParamsPanel(), BorderLayout.CENTER);
setSize(100, 50);

// scrollPan = new JScrollPane();
// scrollPan.setMinimumSize(new Dimension(100, 50));
// scrollPan.setPreferredSize(new Dimension(100, 50));
//
// topContainer.add(containerPanel, BorderLayout.CENTER);
// topContainer.add(scrollPan, BorderLayout.SOUTH);
}


private JPanel createParamsPanel() {

JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Server
info"));
panel.setPreferredSize(new Dimension(150, 150));

JScrollPane scroll = new JScrollPane();
scroll.setPreferredSize(scroll.getMinimumSize());
panel.add(scroll, BorderLayout.CENTER);
panel.add(new ButtonPanelAddCopyRemove(grid, tableModel,
defaultValues), BorderLayout.SOUTH);
grid = new JTable();
tableModel = new PowerTableModel(columnIdentifiers,
columnClasses);
grid.setMinimumSize(new Dimension(200, 100));
grid.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
return panel;
}


private void addHit(String threadGroupName, long time, int
threadCount)
{
//modify
AbstractGraphRow row = model.get(threadGroupName);

if (row == null)
{
row = getNewRow(model, AbstractGraphRow.ROW_SUM_VALUES,
threadGroupName, AbstractGraphRow.MARKER_SIZE_SMALL, false, false,
false, true, true);
}

if (getGranulation() > 0)
{
row.add(time, threadCount * 1000.0d / getGranulation());
}
}



@Override
public String getLabelResource()
{
return this.getClass().getSimpleName();
}

@Override
public String getStaticLabel()
{
return JMeterPluginsUtils.prefixLabel("Tomcat Thread
Monitor");
}

@Override
public void add(SampleResult res)
{
super.add(res);

ThreadMXBean threadMB = null;
int threadCount = threadMB.getThreadCount();

addHit("Live threads", normalizeTime(res.getStartTime()),
threadCount);
updateGui(null);
}

@Override
protected JSettingsPanel createSettingsPanel()
{
return new JSettingsPanel(this,
JSettingsPanel.TIMELINE_OPTION |
JSettingsPanel.GRADIENT_OPTION |
JSettingsPanel.FINAL_ZEROING_OPTION |
JSettingsPanel.LIMIT_POINT_OPTION |
JSettingsPanel.RELATIVE_TIME_OPTION);
}

@Override
public String getWikiPage() {
return "404";
}
}
my code. Didn't change the core(ctrl+c & ctrl +v from Hits per
second), for now I'm trying to make UI
Doesn't work properly...I just don't understand it

Brik

unread,
Jul 26, 2011, 2:47:27 AM7/26/11
to jmeter-plugins
package kg.apc.jmeter.vizualizers;

import java.awt.*;
import java.lang.management.ThreadMXBean;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.TableModelListener;
import kg.apc.jmeter.JMeterPluginsUtils;
import kg.apc.jmeter.charting.AbstractGraphRow;
import kg.apc.jmeter.gui.ButtonPanelAddCopyRemove;
import org.apache.jmeter.gui.util.PowerTableModel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;

//TODO: add panel with server info, add the way to obtain info and
connect to server
// Find the way of getting tomcat threads, not sure of
getThreadCount() usage.


public class TomcatThreads
extends AbstractOverTimeVisualizer implements Clearable,
SettingsInterface
{
public static final String[] columnIdentifiers = new String[]{
"Host / IP", "Port", "Login", "Password"
};

public static final Class[] columnClasses = new Class[]{
String.class, String.class, String.class, String.class
};
private static Object[] defaultValues = new Object[]{
"localhost", "4444", "", ""
};

private PowerTableModel tableModel;
JTable grid;
private JScrollPane scrollPan;
/**
*
*/
public TomcatThreads()
{
super();
setGranulation(1000);
graphPanel.getGraphObject().setyAxisLabel("Live threads");
init();
}

private void init()
{
setBorder(makeBorder());

JPanel topContainer = new JPanel();
topContainer.setLayout(new BorderLayout());


JPanel containerPanel = new VerticalPanel();


containerPanel.add(JMeterPluginsUtils.addHelpLinkToPanel(makeTitlePanel(),
getWikiPage()), BorderLayout.NORTH);
containerPanel.add(createParamsPanel(), BorderLayout.CENTER);


scrollPan = new JScrollPane();
scrollPan.setMinimumSize(new Dimension(100, 50));
scrollPan.setPreferredSize(new Dimension(100, 50));

topContainer.add(containerPanel, BorderLayout.CENTER);
topContainer.add(scrollPan, BorderLayout.SOUTH);

setLayout(new BorderLayout());
add(topContainer, BorderLayout.NORTH);
add(createGraphPanel(), BorderLayout.CENTER);

scrollPan.setVisible(false);

}


private JPanel createParamsPanel() {

JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Server
info"));
panel.setPreferredSize(new Dimension(150, 150));

JScrollPane scroll = new JScrollPane();
scroll.setPreferredSize(scroll.getMinimumSize());

panel.add(scroll, BorderLayout.CENTER);

panel.add(new ButtonPanelAddCopyRemove(grid, tableModel,
defaultValues), BorderLayout.SOUTH);

Upd. This is how it should look like, i finally did it, but buttons
don't work. Trying to add " tableModel = new
PowerTableModel(columnIdentifiers, columnClasses);" makes jmeter
throwing exceptions
Need help, i don't understand why the same code works in 1 plugin and
doesn't work in another(i wanted to copy part of code from
AbstractPerformanceMonitoringGui.java)

Andrey Pohilko

unread,
Jul 26, 2011, 3:10:05 AM7/26/11
to jmeter-...@googlegroups.com
Maybe you missed some parameters that passed to buttons panel to work?

Actually I think you're using bad way to implement things... I'd use PerfMon Metrics Collector approach, just extending it and changing its createtestelement method to custom data provider...

Brik

unread,
Jul 26, 2011, 4:03:56 AM7/26/11
to jmeter-plugins
PerfMon is so...I can't find words to say. Too complicated structure.
And i'm not sure if SIGAR API can provide the info i need.
Btw, aren't you russian? I think i saw your post on forum, don't
remember which one...If so, you may reply on russian, if convinient.

Andrey Pohilko

unread,
Jul 26, 2011, 4:35:05 AM7/26/11
to jmeter-...@googlegroups.com
Perfmon is not complicated, it has much better structure than Server Performance Monitoring. And using SIGAR API would leave everything in its way... But it's your choice, of course.

I'm russian, but we'll stay in English for everyone else to understand the discussion.

Brik

unread,
Jul 26, 2011, 5:33:23 AM7/26/11
to jmeter-plugins
Can't use SIGAR, it doesn't provide methods of getting HTTP(!)
threads, that currently running on Tomcat Server, like it does
jconsole. In jconsole source i have found smthn like ThreadMXBean .
getThreadCount();
So I have to use it.

Brik

unread,
Jul 26, 2011, 5:35:20 AM7/26/11
to jmeter-plugins
if I add methods createGrid and createTableModel in my plugin, jmeter
shows this on startup

Warning: The flag MaxLiveObjectEvacuationRatio=20 has been EOL'd as of
6.0_24 an
d will be ignored
Exception in thread "AWT-EventQueue-0"
java.lang.ExceptionInInitializerError
at
org.apache.jmeter.control.gui.WorkBenchGui.createPopupMenu(WorkBenchG
ui.java:86)
at
org.apache.jmeter.gui.tree.JMeterTreeNode.createPopupMenu(JMeterTreeN
ode.java:114)
at
org.apache.jmeter.gui.action.EditCommand.doAction(EditCommand.java:44
)
at
org.apache.jmeter.gui.action.ActionRouter.performAction(ActionRouter.
java:82)
at org.apache.jmeter.gui.action.ActionRouter.access
$000(ActionRouter.jav
a:42)
at org.apache.jmeter.gui.action.ActionRouter
$1.run(ActionRouter.java:61)

at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext
$1.doIntersectionPrivilege(Unknown
Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown
Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown
Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown
Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.ClassCastException:
kg.apc.jmeter.vizualizers.TomcatThreads
cannot be cast to javax.swing.event.CellEditorListener
at
kg.apc.jmeter.vizualizers.TomcatThreads.createGrid(TomcatThreads.java
:73)
at
kg.apc.jmeter.vizualizers.TomcatThreads.createParamsPanel(TomcatThrea
ds.java:64)
at
kg.apc.jmeter.vizualizers.TomcatThreads.init(TomcatThreads.java:49)
at
kg.apc.jmeter.vizualizers.TomcatThreads.<init>(TomcatThreads.java:40)

at
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at
sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)

at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Sou
rce)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at
org.apache.jmeter.gui.util.MenuFactory.initializeMenus(MenuFactory.ja
va:439)
at
org.apache.jmeter.gui.util.MenuFactory.<clinit>(MenuFactory.java:154)

... 20 more

Andrey Pohilko

unread,
Jul 26, 2011, 6:05:39 AM7/26/11
to jmeter-...@googlegroups.com
So you have your exceptionĀ 
java.lang.ClassCastException:Ā kg.apc.jmeter.vizualizers.TomcatThreadsĀ Ā cannot be cast to javax.swing.event.CellEditorListenerĀ 

Do you use Unit Tests?

Brik

unread,
Jul 26, 2011, 7:26:09 AM7/26/11
to jmeter-plugins
> Do you use Unit Tests?
No, i don't. I'm not a programmer, actually. Just have to do this.
For now, I decided to make it without this tables and etc.
Just 2 simple fields "host" and "port"
But can't figure out issues with layout.
It's just horrible, everything has messed up or isn't shown

Brik

unread,
Jul 26, 2011, 8:01:53 AM7/26/11
to jmeter-plugins
package kg.apc.jmeter.vizualizers;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import kg.apc.jmeter.JMeterPluginsUtils;
import kg.apc.jmeter.charting.AbstractGraphRow;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.SampleResult;


public class TomcatThreads
extends AbstractOverTimeVisualizer
{
JTextField host;
JTextField port;
private JTextField loginField;
private JTextField passField;

public TomcatThreads()
{
super();
setGranulation(1000);
graphPanel.getGraphObject().setyAxisLabel("Live Threads");
init();

}

private void init()
{
this.setLayout(new BorderLayout());

JPanel mainPanel = new VerticalPanel();
Border margin = new EmptyBorder(10, 10, 5, 10);

this.setBorder(margin);

mainPanel.add(makeTitlePanel());

JPanel infoPanel = new JPanel();

infoPanel.setBorder(BorderFactory.createTitledBorder("Server
info"));
GridBagLayout g = new GridBagLayout();

infoPanel.setLayout(g);
GridBagConstraints c = new GridBagConstraints();

c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(0, 0, 0, 0);
c.gridwidth = 1;
infoPanel.add(new JLabel("Host:"));

host = new JTextField(25);
host.setEditable(true);
c.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(host, c);
infoPanel.add(host);

c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(0, 0, 0, 0);
c.gridwidth = 1;
infoPanel.add(new JLabel("Port:"));

port = new JTextField(25);
port.setEditable(true);
c.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(port, c);
infoPanel.add(port);

c.gridwidth = 1;
infoPanel.add(new JLabel("Login:"));

loginField = new JTextField(25);
loginField.setEditable(true);
c.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(loginField, c);
infoPanel.add(loginField);

c.gridwidth = 1;
infoPanel.add(new JLabel("Password:"));

passField = new JTextField(25);
passField.setEditable(true);
c.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(passField, c);
infoPanel.add(passField);

mainPanel.add(infoPanel);

this.add(mainPanel, BorderLayout.WEST);


}

private void addHit(String threadGroupName, long time, int count)
{
AbstractGraphRow row = model.get(threadGroupName);

if (row == null)
{
row = getNewRow(model, AbstractGraphRow.ROW_SUM_VALUES,
threadGroupName, AbstractGraphRow.MARKER_SIZE_SMALL, false, false,
false, true, true);
}

//fix to have trans/sec values in all cases
if (getGranulation() > 0)
{
row.add(time, count * 1000.0d / getGranulation());
}
}

@Override
public String getLabelResource()
{
return this.getClass().getSimpleName();
}

@Override
public String getStaticLabel()
{
return JMeterPluginsUtils.prefixLabel("Tomcat HTTP Threads
Monitor");
}

@Override
public void add(SampleResult res)
{
super.add(res);

int count = res.getSubResults().length;
if(count == 0)
{
count++;
} else if(!isFromTransactionControler(res))
{
count++;
}
addHit("Tomcat Threads", normalizeTime(res.getStartTime()),
count);
updateGui(null);
}

@Override
protected JSettingsPanel createSettingsPanel()
{
return new JSettingsPanel(this,
JSettingsPanel.TIMELINE_OPTION |
JSettingsPanel.GRADIENT_OPTION |
JSettingsPanel.FINAL_ZEROING_OPTION |
JSettingsPanel.LIMIT_POINT_OPTION |
JSettingsPanel.RELATIVE_TIME_OPTION);
}

@Override
public String getWikiPage() {
return "404";
}
}
now it looks like that. But again - where is my graph?! What's wrong
with that plugin...Head is boiling.
I hope you know how to fix it. Just put my "plugin" to
JmeterPlugins.jar and take a look.

Andrey Pohilko

unread,
Jul 26, 2011, 8:31:45 AM7/26/11
to jmeter-...@googlegroups.com
You've replaced the graph component with your GUI panel, that's why you don't see it.

Pal, you're going completely wrong way to solve your issue... Extends or copy PerfMonGui andĀ PerfMonCollector, that's right way to do it...

Brik

unread,
Jul 26, 2011, 9:05:47 AM7/26/11
to jmeter-plugins
svn/ trunk/ src/ kg/ apc/ jmeter/ perfmon/
ServerPerfMonitoringGUI.java
svn/ trunk/ src/ kg/ apc/ jmeter/ perfmon/ PerfMonCollector.java
those?
Agents editing will be required for sure...Ok i'll check this out
tomorrow, my work day is over for today :)

Andrey Pohilko

unread,
Jul 26, 2011, 10:06:03 AM7/26/11
to jmeter-...@googlegroups.com
Yep, those.

Don't change agent. Just implement anotherĀ PerfMonCollector which able to get your metric data and anotherĀ ServerPerfMonitoringGUI which just createTestElement of "anotherĀ PerfMonCollector"

Brik

unread,
Jul 27, 2011, 12:35:31 AM7/27/11
to jmeter-plugins

Well, i copied the GUI, it's still extending
AbstractPerformanceMonitoringGui from perfmon package, so there are 5
radio buttons, which i don't need.
Copied that AbstractPerformanceMonitoringGui to my new package,
removed buttons and told my ServerPerfMonitoringGUI to extend it.
After that my jmeter doesn't wanna see this plugin
Why it can be so?

Andrey Pohilko

unread,
Jul 27, 2011, 2:30:36 AM7/27/11
to jmeter-...@googlegroups.com
Hmmm, sorry... I told to extend wrong GUI. You need PerfMonGui instead ofĀ ServerPerfMonitoringGUI

Override getStaticLabel method and use distinctive label like "==== My Plugin ====" to see it in lists.

I presume you know how to buid and install JAR into JMeter.

Brik

unread,
Jul 27, 2011, 3:28:42 AM7/27/11
to jmeter-plugins
> Hmmm, sorry... I told to extend wrong GUI. You need PerfMonGui instead of
> ServerPerfMonitoringGUI
>
> Override getStaticLabel method and use distinctive label like "==== My
> Plugin ====" to see it in lists.
Doesn't work for me. Copied the code, corrected imports and saved via
NetBeans, got PerfMonGui.class file and just put it into
JMeterPlugins.jar kg/apc/jmeter/vizualizers and my JMeter throws
exceptions again, all about createConnectionsPanel(), init() and other
gui stuff
Did i miss something?

Brik

unread,
Jul 27, 2011, 6:25:51 AM7/27/11
to jmeter-plugins
I love my company. No one knows how to get threads from Tomcat like it
does jConsole... nothing about it in google...
But, just for my own progress - if I make my plugin like a
HitPerSecond plugin, how can i get host and port, for example, from
config element HTTP Authorization Manager?

Andrey Pohilko

unread,
Jul 27, 2011, 9:07:14 AM7/27/11
to jmeter-...@googlegroups.com
I'd use clean Netbeans build environment with separate JAR...

Andrey Pohilko

unread,
Jul 27, 2011, 9:07:39 AM7/27/11
to jmeter-...@googlegroups.com
So how do you monitor Tomcat threads remotely?

Brik

unread,
Jul 27, 2011, 10:37:53 AM7/27/11
to jmeter-plugins


On 27 ŠøŃŽŠ», 19:07, Andrey Pohilko <a...@apc.kg> wrote:
> So how do you monitor Tomcat threads remotely?
Jconsole from JDK binaries. Shows threads, has filter field

Andrey Pohilko

unread,
Jul 27, 2011, 10:46:12 AM7/27/11
to jmeter-...@googlegroups.com
How do you connect to that info? With which classes?

Brik

unread,
Jul 27, 2011, 12:32:14 PM7/27/11
to jmeter-plugins
I input host:port, login + pass if necessary. There are methods of
getting metrics inside the VM, but i still dont know how to get them
remotely, by creating JMXConnector and so on.
My question about jmeter for now is - how to provide plugin with host
and port info or just URL, which is String "host:port". There are some
default config elements in jmeter, e.g. HTTP Authentication, so, how
to tell plugin to grab info from smth like it?

Brik

unread,
Jul 27, 2011, 12:33:58 PM7/27/11
to jmeter-plugins


On 27 ŠøŃŽŠ», 20:46, Andrey Pohilko <a...@apc.kg> wrote:
> How do you connect to that info? With which classes?
ThreadMXBean has method getThreadCount, if u mean that. But
ThreadMXBean and JMXConnector are not compatible...

Andrey Pohilko

unread,
Jul 27, 2011, 12:55:12 PM7/27/11
to jmeter-...@googlegroups.com
Well, to get JMeter plugin to work you need to implement its methods correctly. There is no easy way "just write 2 lines and everything magically works"

Brik

unread,
Jul 27, 2011, 2:00:39 PM7/27/11
to jmeter-plugins
> There is no easy way "just write 2 lines and everything magically works"
You're right. Got to find out which methods i have to implement to
make it work my way =)

Brik

unread,
Jul 28, 2011, 5:29:05 AM7/28/11
to jmeter-plugins
I need your help again :)
I can't get how to make plugin draw the line correctly
I have created method to count threads from my server(still dont know
how to make URL as dynamic parameter, obtained from config element of
jmeter)
private int countThreads() throws IOException
{
int threadCount = 0;

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///
jndi/rmi://192.168.200.46:8086/jmxrmi");

JMXConnector connector = JMXConnectorFactory.connect(url);
MBeanServerConnection mbsc =
connector.getMBeanServerConnection();

ThreadMXBean
threadmxbean=ManagementFactory.newPlatformMXBeanProxy(mbsc,
ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
threadmxbean.setThreadContentionMonitoringEnabled(true);
threadCount = threadmxbean.getThreadCount();
connector.close();

return threadCount;
}
it returns the number, but the amount shown on the graph line
sometimes doubles. I mean, if real amount is 500, it shows
500-500-1000-500-1000-1000-500 and etc.

private void addHit(String threadGroupName, long time, int count)
{
AbstractGraphRow row = model.get(threadGroupName);

if (row == null)
{
row = getNewRow(model, AbstractGraphRow.ROW_SUM_VALUES,
threadGroupName, AbstractGraphRow.MARKER_SIZE_SMALL, false, false,
false, true, true);
}
row.add(time, count);
}

I know it is method, that shows the graph
public void add(SampleResult res)
{

super.add(res);

updateGui(null);
}
if i put addHit(res.getSampleLabel(),
normalizeTime(res.getStartTime()), countThreads()); in it, strange
thing described above happen. Even if i put a number, e.g. 500 it
doesn't matter. I dont understand exact way it should work...I
certanly miss something...
PS add me in ICQ, my UIN is 9-30-31-32, if it is ok for you. It will
be better way to talk, and faster, sure.

Brik

unread,
Jul 28, 2011, 6:09:11 AM7/28/11
to jmeter-plugins
Done the graph painting. It looks like this now
public void add(SampleResult res)
{
try {
threadsNum = countThreads();
} catch (IOException ex) {

Logger.getLogger(SimpleThreads.class.getName()).log(Level.SEVERE,
null, ex);
}
String threadGroupName = res.getSampleLabel();
super.add(res);

AbstractGraphRow row = model.get(threadGroupName);
if (row == null)
{
row = getNewRow(model, AbstractGraphRow.ROW_EXACT_VALUES,
threadGroupName, AbstractGraphRow.MARKER_SIZE_SMALL, false, false,
false, true, true);
}
row.add(normalizeTime(res.getStartTime()), threadsNum);
updateGui(null);
}

The only issue for now is how to provide the plugin with URL or HOST +
PORT info, or HOST+PORT+LOGIN+PASS info to make it more flexible. On
my server login and password requirement is turned off, so i dont need
them.

Brik

unread,
Jul 28, 2011, 7:31:34 AM7/28/11
to jmeter-plugins
I have made my own files with configs and GUI for this
1. public class ThreadsMonTestElement extends AbstractTestElement
implements Serializable, ConfigElement
2. public class TomcatLoginConfig extends ThreadsMonTestElement
implements Serializable
3. public class TomcatLoginConfigGui extends AbstractConfigGui
Copied and extended them from original jmeter files ConfigTestElement,
LoginConfig and LoginConfigGui
So i have now 4 fields.
How to make my plugin listen this new one and obtain info?

Andrey Pohilko

unread,
Jul 28, 2011, 8:52:27 AM7/28/11
to jmeter-...@googlegroups.com
Seems you progressing well and don't need my help now...

Brik

unread,
Jul 28, 2011, 10:27:22 AM7/28/11
to jmeter-plugins
> Seems you progressing well and don't need my help now...
1 question left - how to make my plugin obtain info from config
element and that's it, i will be done.

Andrey Pohilko

unread,
Jul 28, 2011, 11:07:55 AM7/28/11
to jmeter-...@googlegroups.com
Š’ сообщении от 28 ŠøŃŽŠ»Ń 2011 18:27:22 автор Brik написал:

> > Seems you progressing well and don't need my help now...
>
> 1 question left - how to make my plugin obtain info from config
> element and that's it, i will be done.

Sorry, I never used config elements in that way...

Brik

unread,
Jul 28, 2011, 11:46:13 AM7/28/11
to jmeter-plugins
Oh. Then i gotta understand how your perfmon gets parameters from
fields on panel and do similar to it

Andrey Pohilko

unread,
Jul 28, 2011, 12:33:48 PM7/28/11
to jmeter-...@googlegroups.com
It's all managed via getProperty & setProperty methods.

But you still did not get the architecture of JMeter plugins. They all consists of 2 parts: non-gui class which do actual job and GUI class that presents data...Ā 

Brik

unread,
Jul 28, 2011, 2:18:45 PM7/28/11
to jmeter-plugins
If i figure out how to make 2 parts work together it will be great.
But for now i've put everything in 1 and it works...

Brik

unread,
Jul 29, 2011, 2:49:56 AM7/29/11
to jmeter-plugins
Done it, but it's dummy implementation. Could not make my plugin get
values from config element :( but i tried!
My plugin needs URL to connect to server, so it obtains URL from Name
field on panel. Dummy, but ok for several tests.
I think i will go on with Java and maybe have to improve this plugin
or add some others(hope not).
Last stupid question - how to access "Comments" field on panel to add
some default text?

Brik

unread,
Aug 1, 2011, 6:53:54 AM8/1/11
to jmeter-plugins
Src, as I promised

package kg.apc.jmeter.vizualizers;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import kg.apc.jmeter.JMeterPluginsUtils;
import kg.apc.jmeter.charting.AbstractGraphRow;
import org.apache.jmeter.samplers.SampleResult;


public class TomcatHTTPThreads
extends AbstractOverTimeVisualizer
{
private int threadsNum = 0;
private int httpThreadCount;

/**
*
*/
public TomcatHTTPThreads()
{
super();
setGranulation(1000);
graphPanel.getGraphObject().setyAxisLabel("Number of
threads");

}


@Override
public String getLabelResource()
{
return this.getClass().getSimpleName();

}

@Override
public String getStaticLabel()
{

return JMeterPluginsUtils.prefixLabel("Tomcat HTTP Threads");
}

@Override
public void add(SampleResult res)
{
try {
threadsNum = countThreads();
} catch (IOException ex) {

Logger.getLogger(TomcatHTTPThreads.class.getName()).log(Level.SEVERE,
null, ex);
}
String threadGroupName = "Tomcat HTTP Threads";
super.add(res);

AbstractGraphRow row = model.get(threadGroupName);
if (row == null)
{
row = getNewRow(model, AbstractGraphRow.ROW_EXACT_VALUES,
threadGroupName, AbstractGraphRow.MARKER_SIZE_SMALL, false, false,
false, true, true);
}
row.add(normalizeTime(res.getStartTime()), threadsNum);
updateGui(null);
}



private int countThreads() throws IOException
{
int threadCount = 0;
String URL = this.getName();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///
jndi/rmi://"+ URL + "/jmxrmi");

JMXConnector connector = JMXConnectorFactory.connect(url);
MBeanServerConnection mbsc =
connector.getMBeanServerConnection();

ThreadMXBean
threadmxbean=ManagementFactory.newPlatformMXBeanProxy(mbsc,
ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
threadmxbean.setThreadContentionMonitoringEnabled(true);
threadCount = threadmxbean.getThreadCount();
long[] ids = threadmxbean.getAllThreadIds();
ThreadInfo[] list = threadmxbean.getThreadInfo(ids);
httpThreadCount = 0;

String str = Arrays.deepToString(list);


Pattern p = Pattern.compile("http");
Matcher m = p.matcher(str);

while (m.find()){
httpThreadCount +=1;
}
connector.close();


return httpThreadCount;
}
@Override
protected JSettingsPanel createSettingsPanel()
{
return new JSettingsPanel(this,
JSettingsPanel.TIMELINE_OPTION |
JSettingsPanel.GRADIENT_OPTION |
JSettingsPanel.FINAL_ZEROING_OPTION |
JSettingsPanel.LIMIT_POINT_OPTION |
JSettingsPanel.RELATIVE_TIME_OPTION);
}

@Override
public String getWikiPage() {
return "404";
}
}

Deleting strings associated with getting "http" and returning
threadCount instead of httpThreadCount will make this plugin show all
threads on Tomcat :)
the URL should look as "ip:port"

Andrey Pohilko

unread,
Aug 1, 2011, 8:15:21 AM8/1/11
to jmeter-...@googlegroups.com
Seems your listener will ask the Tomcat for threads info on every request made
by JMeter. Sorry but you doomed to have terrible overhead...

Brik

unread,
Aug 1, 2011, 9:20:44 AM8/1/11
to jmeter-plugins
> Seems your listener will ask the Tomcat for threads info on every request made
> by JMeter. Sorry but you doomed to have terrible overhead...
Yes it will. Dont know how to tell it to upgrade, one time in 5
seconds, for example...

Andrey Pohilko

unread,
Aug 1, 2011, 11:30:36 AM8/1/11
to jmeter-...@googlegroups.com

You could remember in field the time of last request and don't make requests
until some time has passed... Ugly and has side effects, but will work.

Better way is to use separate data provider object like PerfMon do...

Brik

unread,
Aug 2, 2011, 7:42:05 AM8/2/11
to jmeter-plugins
Decided to take your advice
Made separate files - MetricsCollector and ThreadsGui
How can i get notification from JMeter to start my collector? For now,
it implements Runnable, void run() { createConnection(); }
(there is try-catch block ofc). It seems to start but doesn't provide
metrics...I'm wondering why
public void createConnection() throws MalformedURLException,
IOException
{
String URL = ThreadsGui.class.getName();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///
jndi/rmi://"+ URL + "/jmxrmi");

connector = JMXConnectorFactory.connect(url);

MBeanServerConnection mbsc =
connector.getMBeanServerConnection();


threadmxbean=ManagementFactory.newPlatformMXBeanProxy(mbsc,
ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
threadmxbean.setThreadContentionMonitoringEnabled(true);

}

public int countThreads() throws IOException
{
httpThreadsCount = 0;
threadsCount = threadmxbean.getThreadCount();
long[] ids = threadmxbean.getAllThreadIds();
ThreadInfo[] list = threadmxbean.getThreadInfo(ids);

String str = Arrays.deepToString(list);

Pattern p = Pattern.compile("http");
Matcher m = p.matcher(str);

while (m.find()){
httpThreadsCount +=1;
}
return httpThreadsCount;
}
And in ThreadsGui i do this
public void add(SampleResult res)
{
MetricsCollector mc = new MetricsCollector();

String threadGroupName = "Tomcat HTTP Threads";
super.add(res);
try {
count = mc.countThreads();
} catch (IOException ex) {

Logger.getLogger(ThreadsGui.class.getName()).log(Level.SEVERE, null,
ex);
}
AbstractGraphRow row = model.get(threadGroupName);
if (row == null)
{
row = getNewRow(model, AbstractGraphRow.ROW_EXACT_VALUES,
threadGroupName, AbstractGraphRow.MARKER_SIZE_SMALL, false, false,
false, true, true);
}
row.add(normalizeTime(res.getStartTime()), count);
updateGui(null);
}
Logic is next - 1st file creates connection and it lives for some
period(need notification to kill it too), the 2nd file uses
countThreads method to get metric and put this number on graph

Andrey Pohilko

unread,
Aug 2, 2011, 8:08:23 AM8/2/11
to jmeter-...@googlegroups.com
Well, there's some pain you must go through: correct interaction between GUI
and Non-gui parts. Otherwise you'll fail again.

Non-gui class should extend ResultCollector, and implement Runnable.
Important thing to know: ResultCollector itself implements SampleListener,
Clearable, Serializable, TestListener, Remoteable, NoThreadClone
This interfaces are important, you'll need to override some of their methods
to make it work as you wish. So look at PerfMonCollector class, it does just
what you need, eg it overrides testStarted() method and starts monitoring with
1sec interval. You may just copy that class and replace contents of
initiateConnectors(), processConnectors() and shutdownConnectors() with your
TomCat-specific calls. But keep the idea of generating SampleResults - it's the
key for easy handling monitoring data in graphs.

Then... Then just try to copy PerfMonGui and replace class inside
createTestElement with your class. For the first try make URL of monitoring
constant, we'll parameterize it later. Try compiling and running your code.
Write the letter on results.

Let's go the right way.

Brik

unread,
Aug 3, 2011, 2:09:30 AM8/3/11
to jmeter-plugins
IT WORKS! FINALLY! HURRAY! Thanks so much for your patience and help
-----------------SOURCE CODE------------------------------
package kg.apc.jmeter.tomcatmon;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
*
* @author MrBrik
* based on code of PerfMonCollector, author APC
*/
public class TomcatMonCollector
extends ResultCollector
implements Runnable {

public int threadsCount = 0;
public int httpThreadsCount = 0;
public String type = "";
ThreadMXBean threadmxbean;
JMXConnector connector;

private static final String PERFMON = "TomcatMon";
private static final Logger log =
LoggingManager.getLoggerForClass();
public static final String DATA_PROPERTY = "metricConnections";
private Thread workerThread;
private HashMap<String, Long> oldValues = new HashMap<String,
Long>();

public void setData(CollectionProperty rows) {
setProperty(rows);
}

public JMeterProperty getData() {
return getProperty(DATA_PROPERTY);
}

@Override
public void sampleOccurred(SampleEvent event) {
// just dropping regular test samples
}

public synchronized void run() {
while (true) {
processConnectors();
try {
this.wait(1000);
}
catch (InterruptedException ex) {
log.debug("Monitoring thread was interrupted", ex);
break;
}
}
}

@Override
public void testStarted(String host) {
try {
initiateConnectors();
} catch (MalformedURLException ex) {

java.util.logging.Logger.getLogger(TomcatMonCollector.class.getName()).log(Level.SEVERE,
null, ex);
}

workerThread = new Thread(this);
workerThread.start();

super.testStarted(host);
}

@Override
public void testEnded(String host) {
workerThread.interrupt();
shutdownConnectors();

super.testEnded(host);
}

private void initiateConnectors() throws MalformedURLException {

oldValues.clear();
JMeterProperty prop = getData();
if (!(prop instanceof CollectionProperty)) {
log.warn("Got unexpected property: " + prop);
return;
}
CollectionProperty rows = (CollectionProperty) prop;
ArrayList<Object> row = (ArrayList<Object>)
rows.get(0).getObjectValue();
String host = ((JMeterProperty)
row.get(0)).getStringValue();
int port = ((JMeterProperty) row.get(1)).getIntValue();
type = ((JMeterProperty) row.get(2)).getStringValue();
try {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///
jndi/rmi://"+host+":" + port + "/jmxrmi");
connector = JMXConnectorFactory.connect(url);
MBeanServerConnection mbsc =
connector.getMBeanServerConnection();
threadmxbean =
ManagementFactory.newPlatformMXBeanProxy(mbsc,
ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
threadmxbean.setThreadContentionMonitoringEnabled(true);
} catch (IOException ex) {

java.util.logging.Logger.getLogger(TomcatMonCollector.class.getName()).log(Level.SEVERE,
null, ex);
}


}

private void shutdownConnectors() {
try {
connector.close();
} catch (IOException ex) {

java.util.logging.Logger.getLogger(TomcatMonCollector.class.getName()).log(Level.SEVERE,
null, ex);
}
}



private void processConnectors() {
httpThreadsCount = 0;
threadsCount = threadmxbean.getThreadCount();
long[] ids = threadmxbean.getAllThreadIds();
ThreadInfo[] list = threadmxbean.getThreadInfo(ids);

if(type.contains("http") || type.contains("HTTP"))
{
String str = Arrays.deepToString(list);

Pattern p = Pattern.compile("http");
Matcher m = p.matcher(str);

while (m.find()){
httpThreadsCount +=1;
}

generateSample(httpThreadsCount, "HTTP Threads");
}
else generateSample(threadsCount, "Live Threads");
}

private void generateSample(long value, String label) {
TomcatMonSampleResult res = new TomcatMonSampleResult();
res.setSampleLabel(label);
res.setValue(value);
SampleEvent e = new SampleEvent(res, PERFMON);
super.sampleOccurred(e);
}

}
----
I added TomcatMonSampleResult to my package just to be sure that i'm
not taking smtn from perfmon package. It's code is just the same as
PerfMonSampleResult.


package kg.apc.jmeter.vizualizers;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import kg.apc.jmeter.JMeterPluginsUtils;
import kg.apc.jmeter.charting.AbstractGraphRow;
import kg.apc.jmeter.gui.ButtonPanelAddCopyRemove;
import kg.apc.jmeter.tomcatmon.TomcatMonCollector;
import org.apache.jmeter.gui.util.PowerTableModel;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.NullProperty;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
*
* @author MrBrik
* based on code of PerfMonGui, author APC
*/
public class TomcatMonGui
extends AbstractOverTimeVisualizer {
private static final Logger log =
LoggingManager.getLoggerForClass();
private PowerTableModel tableModel;
private JTable grid;
private JTextField metricTypesBox;
public static final String[] columnIdentifiers = new String[]{
"Host / IP", "Port", "Metric type(http or all)", ""
};
public static final Class[] columnClasses = new Class[]{
String.class, String.class, String.class, String.class
};
private static String[] defaultValues = new String[]{
"localhost", "4444", "HTTP threads", ""
};

public TomcatMonGui() {
super();
graphPanel.getGraphObject().setyAxisLabel("Number of threads");
graphPanel.getGraphObject().setExpendRows(true);
initGui();
}

@Override
protected JSettingsPanel createSettingsPanel() {
return new JSettingsPanel(this,
JSettingsPanel.GRADIENT_OPTION
| JSettingsPanel.LIMIT_POINT_OPTION
| JSettingsPanel.MAXY_OPTION
| JSettingsPanel.RELATIVE_TIME_OPTION);
}

@Override
public String getWikiPage() {
return "PerfMon";
}

public String getLabelResource() {
return getClass().getSimpleName();
}

@Override
public String getStaticLabel() {
return JMeterPluginsUtils.prefixLabel("Tomcat Threads
Collector");
}

private void initGui() {
add(createConnectionsPanel(), BorderLayout.SOUTH);
}

private Component createConnectionsPanel() {
JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Server
info"));
panel.setPreferredSize(new Dimension(150, 150));

JScrollPane scroll = new JScrollPane(createGrid());
scroll.setPreferredSize(scroll.getMinimumSize());
panel.add(scroll, BorderLayout.CENTER);
panel.add(new ButtonPanelAddCopyRemove(grid, tableModel,
defaultValues), BorderLayout.SOUTH);

metricTypesBox=new JTextField();
grid.getColumnModel().getColumn(2).setCellEditor(new
DefaultCellEditor(metricTypesBox));

return panel;
}

private JTable createGrid() {
grid = new JTable();
createTableModel();
grid.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
grid.setMinimumSize(new Dimension(200, 100));

return grid;
}

private void createTableModel() {
tableModel = new PowerTableModel(columnIdentifiers,
columnClasses);
grid.setModel(tableModel);
}

@Override
public TestElement createTestElement() {
TestElement te = new TomcatMonCollector();
modifyTestElement(te);

te.setComment(JMeterPluginsUtils.getWikiLinkText(getWikiPage()));
return te;
}

@Override
public void modifyTestElement(TestElement te) {
super.modifyTestElement(te);
if (grid.isEditing()) {
grid.getCellEditor().stopCellEditing();
}

if (te instanceof TomcatMonCollector) {
TomcatMonCollector pmte = (TomcatMonCollector) te;
CollectionProperty rows =
JMeterPluginsUtils.tableModelRowsToCollectionProperty(tableModel,
TomcatMonCollector.DATA_PROPERTY);
pmte.setData(rows);
}
super.configureTestElement(te);
}

@Override
public void configure(TestElement te) {
super.configure(te);
TomcatMonCollector pmte = (TomcatMonCollector) te;
JMeterProperty perfmonValues = pmte.getData();
if (!(perfmonValues instanceof NullProperty)) {

JMeterPluginsUtils.collectionPropertyToTableModelRows((CollectionProperty)
perfmonValues, tableModel);
}
else {
log.warn("Received null property instead of collection");
}
}

@Override
public void add(SampleResult res) {
super.add(res);
addThreadGroupRecord(res.getSampleLabel(),
normalizeTime(res.getEndTime()), res.getLatency());
updateGui(null);
}

private void addThreadGroupRecord(String threadGroupName, long
time, long value) {

AbstractGraphRow row = model.get(threadGroupName);
if (row == null) {
row = getNewRow(model, AbstractGraphRow.ROW_AVERAGES,
threadGroupName,
AbstractGraphRow.MARKER_SIZE_NONE, false, false, false,
true, true);
}

row.add(time, value);

}
}

Changed type of metricsTypeBox to JTextField for my needs. My plugin
can show 2 types of metrics - HTTP Threads and just ALL threads,
depending on what is typed in the 3rd column
You can add this to your package, i think it would be great :)

Andrey Pohilko

unread,
Aug 3, 2011, 2:17:24 AM8/3/11
to jmeter-...@googlegroups.com
Congratulations!

Hope ypu enjoyed extending JMeter and will keep inventing fancy things!

Brik

unread,
Aug 3, 2011, 2:39:08 AM8/3/11
to jmeter-plugins
yeah, it was useful experience in Java-programing.
I will, if it would be necessary for job or for someone who ask help :)

Andrey Pohilko

unread,
Aug 3, 2011, 12:58:50 PM8/3/11
to jmeter-...@googlegroups.com
Well, read this mailing list archive: peopleĀ thirst for your help!

techn...@gmail.com

unread,
Aug 1, 2012, 1:43:08 PM8/1/12
to jmeter-...@googlegroups.com
Hi,

I have installed netbeans> Jmeter > and then installed jmeter toolkit from net beans but how do i start my first jmeter load generator script?

Jayanta

On Monday, 25 July 2011 20:08:29 UTC+5:30, Brik wrote:
Hi all
writing a plugin, that will show threads of Tomcat and i have several
questions
The first is, which graph to extend better? My plugin will show only 1
line - actual http threads running on Tomcat server.
Suggestions?
Left src on work computer, so i will write out tomorrow with next
questions and issues if got some.
Sorry about mistakes, if any.
Thanks.
Reply all
Reply to author
Forward
0 new messages