This page describes how to instrument AWT and Swing applications with AppMon. The goal is to start PurePaths on every user interaction such as mouse clicks or keyboard events.
The standard Java library contains out of the box the following packages:
- AWT (Abstract Widget Toolkit, the first approach from Sun Microsystems to standardize user interface components)
- Swing (Based on AWT, contains many improved classes and extended functionalities)
It is very important to understand that Swing is built on top of AWT, since you do not want AppMon instrumentation based entirely on the Swing level. You must hook into selected basic AWT classes to fully instrument both AWT and Swing. More information about Swing is available here: https://docs.oracle.com/javase/tutorial/uiswing/
AWT / swing demo application
The AWT/Swing sample application used in this walkthrough ships with the Java Development Kit (JDK). The sample application provides a good overview over most out of the box Swing user interface controls, but it lacks any business logic behind them. It's still a good example for configuring AppMon to start PurePaths on user interface actions.
The sample application is located in your local %JDK_HOME%/demo/jfc/SwingSet2 folder. For example:
To run the demo application, start a command prompt and enter the following:
java -jar SwingSet2.jar
After a quick startup displaying a splash screen, the application should look similar to the following.
With the demo AWT/Swing sample application running, inject the AppMon agent. See Application Environment Configuration for more about instrumenting Java or .NET applications.
Instead of creating a new System Profile from scratch, you can download the System Profile from the table in the Download section on this page. The prepared System Profile contains the Agent Mapping as well as all measures and Business Transactions needed for this walkthrough.
Perform the following to inject the agent.
Create a System Profile for the Swing Demo application, as shown in the following.
Create an agent group/mapping that connects an agent with name AwtSwingDemoApp.
Enter the following to inject the AppMon Agent into the Swing Demo application.
java -agentpath:"C:\Program Files (x86)\dynaTrace\dynaTrace 7.0\agent\lib64\dtagent.dll"=name="AWTSwingDemoApp",server=localhost:9998 -jar SwingSet2.jar.
lib directory must match your platform and JVM architecture (x86 / x64).
Default AWT sensor pack
A default AppMon AWT Sensor Pack is already activated for the new System Profile. This AWT Sensor Pack is activated by default for all System Profiles using JAVA technology, as shown in the following graphic.
The default AWT Sensor Pack attends to Action events and ItemSelection events. The action event can be considered a universal event, which may be attached to multiple user interface elements such as buttons, menu items, combo boxes, or other controls. The event does specify an action for the Action event, but it is typically used for mouse clicks or other user interface actions. The ItemSelection event is mostly used for combo boxes, lists, and other controls.
The problem with the default AWT Sensor Pack starts when taking a closer look on how most developers typically work with AWT and Swing. There are many more event types than just the ActionListener and ItemListener. For example, a developer may use an ActionListener to get a simple notification when a button is clicked. Alternatively the MouseListener (which is not part of the AppMon default AWT Sensor Pack) can be notified about a button click. The MouseListener is much more specific than the ActionListener. It provides additional data such as X / Y coordinates, single / double / right button click, and more.
How the application is programmed determines the listeners to track with AppMon. The ActionListener and the ItemListener may not be sufficient for some real world applications, so you may want to create your own AWT Sensor Pack to cover more user interface event types than what the default AWT Sensor Pack provides.
Creating your own AWT sensor pack
You can create your own AWT Sensor Pack to define a wider range of AWT user interface entry points. The following table lists available AWT events. Use this to determine which events you need for instrumenting real user interactions.
A Listener class provides the hooking machanism to fetch the Event itself. Listener classes (like MouseListener) are usually interfaces and may contain one or more hook methods such as
mouseReleased(EventObject). An Event object class such as MouseEvent is a simple object containing event attributes such as X/Y coordinates. This Event object procides event details when passed to the hook method.
There are also some abstract Adapter classes such as MouseAdapter), but they are usually only empty implementations of the corresponding Listener class. This was mainly done to help developers avoid implementing the whole interface, and just inherit from the Adapter class and override the required methods.
From the previous list of event types, the following listeners are typically used most often:
|ActionListener||public void actionPerformed(ActionEvent e)|
|ItemListener||void itemStateChanged(ItemEvent e)|
|MouseListener||public void mouseClicked(MouseEvent e) public void mouseClicked(MouseEvent e) public void mousePressed(MouseEvent e) public void mouseReleased(MouseEvent e)|
|KeyListener||public void keyTyped(KeyEvent e) public void keyTyped(KeyEvent e) public void keyPressed(KeyEvent e) public void keyReleased(KeyEvent e)|
After creating a custom Sensor Group within the System Profile, it should look like this:
You have now created basic AWT sensors. It is important to turn on argument capturing for the listeners arguments such as
ActionEvent e, and
ItemEvent e. Doing this lets you extract helpful additional information, like the name of the pressed UI button, or the pressed key on the keyboard. Use this extra information to set up some business transactions. These business transactions help transform the technical events (PurePaths) into something human readable and understandable.
Enable argument capturing for every method sensor rule defined in the new Sensor Group. The following graphic shows an example
Increase the size of the captured strings from 256 to 1024 characters since the toString() method of the events may deliver fairly long strings.
Deactivate the default AWT Sensor Pack from the System Profile and activate the new Sensor Group.
Next, check the PurePaths being captured. Restart the swing demo application and click some buttons, then open the PurePaths dashboard for the System Profile. It should look similar to the following.
You may see many PurePaths with size
1. This means the listener triggered, but there is no business logic behind that listener. Unfortunately, the Swing Demo Application does not have much code behind the user interface controls. So at this point, it's good to have many PurePaths, and to see seeing the event object as string in the argument column as previously shown.
At this point in the walkthrough, many user interface events are captured. For a better overview, you can define some business transactions for the different event types. The following sections describe how to set up these business transaction and how they work.
User interface action events
As previously stated, the ActionEvent is a common universal event you can attach to many user interface controls. What defines an action and when it is triggered is handled by the component providing support for Action event Listeners. This means an action definition may vary from component to component. For buttons, it's a simple button click.
Event are primitive but flexible. It can't provide additional meta information about the triggered action such as mouse coordinates. Because of this, your use of ActionEvents may vary from application to application, or from business case to business case, depending on whether you desire simple listeners or more specific listeners.
The following is an example how an ActionEvent may look when captured.
The example's argument looks like this:
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=**PaintBorder** ,when=**1310471676432** ,modifiers=Button1] on**javax.swing.JToggleButton** $ToggleButtonModel@309fe84e
The most important part of an action event is the action command
PaintBorder parameter. This usually describes the command. It is not mandatory to implement, so its value may be null for some applications. Another interesting parameter is the timestamp, which is when the action event was triggered (for example
1310471676432). The timestamp provides a chronological view of all actions. This may lead to an unintended number of measures. Another interesting parameter is the UI control (javax.swing.JToggleButton in the previous screenshot) which triggered the action event.
Define a Business Transaction
Measures are required to define a business transaction. In this case, Measures are split, which filters only these PurePaths which contain the previously described ActionEvent. The result is then further split to list of all PurePaths containing only the ActionEvent by the individual values previously described. That result defines this business transaction.
Learn more about business transactions.
Splitting Measure for the Action Event Command Name:
Splitting Measure for the Action Event Component:
Splitting Measure for the Action Event Timestamp:
This is the definition of the Action Event business transaction, which uses all splitting measures for grouping:
After the business transaction is defined, the result should look like the screenshot below when clicking around in the Swing Demo Application. The List Example was used for clicking, as this provides at least some command names. The Swing Demo Application is only a showcase for user interface controls, so developers did not spend time on setting proper command action names.
This looks like the following in AppMon:
The first value in the Group column is the timestamp (in numeric format) from our Action Event Timestamp measure. Sorting this column gives you a chronological list of what the user has clicked. It's sometimes very helpful seeing what the user has clicked in the correct order/timeline.
The second value in the Group column shows the component type which the user has clicked (JCheckBox in this example). This value comes from our Action Event Command Name measure.
The Group column value in the previous example shows the action command name and the name of the clicked check box. This value comes from the Action Event Command Name measure defined for the business transaction.
User interface keyboard events
Unfortunately, the Swing demo app does not use key listeners. Most functionality is covered with action listeners. After a quick source code modification and attaching a KeyListener to the first TextField (named Frame Title), you can see the following PurePaths:
The following screenshot shows a PurePath for the keyReleased Event. The business transaction uses keyTyped() as this is probably the most common event. In this example, A-B-C-D was typed in the Frame Title input field, then ESC and RETURN were hit:
The argument of this example appears in the node details.
The most important part of the keyboard event is the pressed keyboard character (
keyChar= parameter). In the previous example, the
D key was pressed on the keyboard. The second interesting parameter is the component, which received the keyboard input (on javax.swing.JTextField). If the component has a proper name, it displays here instead of the internal toString() representation.
Splitting Measure for the pressed keyboard character:
Splitting Measure for the keyboard input component:
This is the definition of the Keyboard Input business transaction, which uses all splitting measures for grouping:
After doing some other keyboard action in the Frame Title text box, the defined business transaction result appears. In addition to regular keystrokes such as
D, other ley presses such as ESC, RETURN, and BACKSPACE key presses appear.
The keyboard events do not deliver a timestamp, so it is not possible to view them chronologically in the business transaction dashlet. However, there is still enough information to pinpoint slow keyboard input processing in the monitored application.
User interface mouse events
The swing demo application also registers some mouse events. Unfortunately there is not much business logic behind the clicks, so there is not much application code running behind these clicks. As already mentioned, the swing demo application mostly uses the action event for triggering functional code. While this is true to the swing demo application, it may be different on other applications. In the real world, it is mainly the developer who decides to either use action, mouse, keyboard or other types of events.
Here's how a PurePath with a mouse event might look:
The argument looks like this:
java.awt.event.MouseEvent[MOUSE_CLICKED,(58,20),absolute(1078,436 ),button=1,modifiers=Button1,clickCount=1] on Fish Button
Three arguments could be valuable. First, the event type (MOUSE_CLICKED), which identifies the mouse event type (such as clicked or released). Second the clicked X/Y coordinates (1078, 436) and third the name of the clicked component (FishButton).
Splitting Measure for the Mouse Event Type:
Splitting Measure for the absolute Mouse Event Coordinates:
Splitting Measure for the Mouse Event Component:
This is the definition of the Mouse Event business transaction, which uses all previously shown Splitting Measures:
Clicking the One, Two, and Three buttons in the Swing demo application
This looks like the following in AppMon:
In this example, the Swing Demo Application's source code is modified to give the buttons some names (for example, by using setName("One")) for the buttons.
User interface item changed events
The swing demo application also registers some item state events. There is not much business logic behind these events, so there is not much application code running behind these clicks. The event is mostly used for lists and combo boxes to get notified about selection changes.
The following screenshot show an example PurePath for an Item Changed event. In this case, the Mouse event has triggered the Item event. Constellations like this are quite normal for AWT/Swing:
The argument appears in the node details.
Four arguments could be valuable. First, the item event type (ITEM_STATE_CHANGED), which identifies event itself. Second the new state(SELECTED) of the item (selected/deselected). Third, the selected/deselected combo box or list item (Larry) and fourth, the name of component which raised the event (javax.swing.JComboBox). Please note that if the component has a name (by using setName("MyButton") for example), the name is shown here instead of the default toString() representation.
Splitting Measure for the item event Type:
Splitting Measure for the changed State:
Splitting Measure for changed Component:
Splitting Measure for the changed Item:
This is the definition of the item Changed Item business transaction, which uses all previously shown splitting Measures:
Changing a combo box selection within the Swing demo application looks like this:
This looks like the following in AppMon:
After defining business transactions, you can build a dashboard for easy AWT/Swing analysis. The following dashboard gives an example. The shown dashboard can be downloaded from here
Wrong listener type
Instrumenting AppMon Client applications more challenging than instrumenting regular request or response based applications. Because of this, you may miss the listener causing a performance problem. In the case where you may have designed your own listeners, you can find and instrument the corresponding listener. One approach could be to instrument the AWT Event Dispatcher. However, this can lead to a very high quantity of PurePaths and probably should only be used to find out which listener should finally be instrumented.
Too many PurePaths
The defaults used in this walkthrough can lead to quite a lot of PurePaths. Adjust the custom created AWT Sensor Group and remove listeners from which you know that they do not trigger any business logic to reduce the amount of captured PurePaths. You can also define an API based filter for the entire dashboard. This filters out everything that does not call certain business logic code, so the PurePath dashlet only shows relevant transactions.
Modal dialog box problematic
This is challenging to resolve with AppMon. The problem is as follows:
In AWT and Swing you can display modal dialog boxes. Modal means, that a new child window is opened on top of the parent window and the parent window is inactive until the child window is closed. For AWT and Swing this means that the calling method, which opens the modal dialog box, does not finish until the modal dialog box is closed by the user. This might sound like a bad design in AWT / Swing. Some companies even developed their own modal dialog box handling because of this. Unfortunately, AppMon has no chance to overcome this design weakness. AppMon also does not allow to define custom transaction exit points, which could be used to overcome the issue, so the transaction (PurePath) keeps going until the modal dialog box closes. Everything that happened in the modal child window is then in context of one single PurePath. This currently is a known problem.
- Look at the PurePath entry method call which starts the long modal window transaction. Try to skip it by defining a method exclusion sensor rule. Speaking technically, this means if you have a PurePath which contains the setVisible(true) method of a modal window, the PurePath is affected by this problem.
- Look at the CPU time of the modal dialog box PurePath instead of the PP Duration. Duration tells you only how long the modal dialog box was open. CPU Duration gives you at least some hints about the processing hotspots while the modal dialog box was open.