Skip to content

Commit

Permalink
Add ability to analyze log files created with Partition Events Logging (
Browse files Browse the repository at this point in the history
#8)

* Add ability to analyze log files created with Partition Events Logging enabled
* Minor formatting
* Add workaround for REST bug
  • Loading branch information
tmiddlet2666 committed Jul 13, 2021
1 parent 1fbc1ce commit 0ba51a4
Show file tree
Hide file tree
Showing 15 changed files with 2,823 additions and 43 deletions.
3 changes: 2 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ image::assets/coherence-visualvm.png[Coherence VisualVM Plugin,800,479]

The Plugin will connect to and display data for the following Coherence versions:

**Community Editions**: 14.1.1.0.x, 20.06.x and 20.12.x
**Community Editions**: 14.1.1.0.x, 20.06.x, 20.12.x and 21.06

**Commercial Editions**: 12.2.1.5.x, 12.2.1.4.x, 12.1.3.x, 12.1.2.x and 3.7.1.x

Expand Down Expand Up @@ -185,6 +185,7 @@ There are tool tips for each of the preferences, but a summary is shown below.
| Enable Zoom on Graphs | false | Enables additional zoom function for all graphs.
| Enable Cluster Snapshot tab | false | Enables experimental Cluster Snapshot tab. This tab is useful for seeing all the relevant cluster information on one pae in a text format.
| Enable Cluster Heap Dump | false | Enables the cluster heap dump button on the Cluster Overview tab.
| Analyze Unavailable Time in LogFile| | Provides the ability to analyze log files where Partition Events Logging has been enabled for logs generated from Coherence versions 21.06 and above. See https://coherence.community/21.06/docs/#/docs/core/07_partition_events_logging[here] for more details. Note: You select a Coherence log file to analyze and don't need to be connected to a running cluster.
!===

[#capabilities]
Expand Down
Binary file modified assets/coherence-visualvm-preferences.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions coherence-visualvm-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -804,9 +804,10 @@ public JsonNode getDataForStorageManagerMembers(String sServiceName, String sDom
{
URLBuilder urlBuilder = getBasePath().addPathSegment("services")
.addPathSegment(encodeServiceName(sServiceName)).addPathSegment("caches").addPathSegment(sCacheName)
.addPathSegment("members").addQueryParameter("fields", "nodeId," +
"locksGranted,locksPending,listenerRegistrations,maxQueryDurationMillis,maxQueryDescription," +
"nonOptimizedQueryAverageMillis,optimizedQueryAverageMillis,indexTotalUnits");
.addPathSegment("members").addQueryParameter("fields",
"nodeId,locksGranted,locksPending,listenerRegistrations,maxQueryDurationMillis,maxQueryDescription," +
"nonOptimizedQueryAverageMillis,optimizedQueryAverageMillis,indexTotalUnits,indexingTotalMillis")
.addQueryParameter("links", "");

if (sDomainPartition != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.Dimension;
Expand Down Expand Up @@ -93,7 +94,7 @@ public AbstractMenuOption(VisualVMModel model, RequestSender requestSender, Expo
* @param sMessage the message to display
* @param nDialogType the type of dialog, e.g. JOptionPane.INFORMATION_MESSAGE
*/
protected void showMessageDialog(String sTitle, String sMessage, int nDialogType)
protected static void showMessageDialog(String sTitle, String sMessage, int nDialogType)
{
showMessageDialog(sTitle, sMessage, nDialogType, 500, 400);
}
Expand All @@ -108,7 +109,7 @@ protected void showMessageDialog(String sTitle, String sMessage, int nDialogType
* @param nWidth the width of the dialog window
* @param fCopySave true if copy and save buttons should be displayed
*/
protected void showMessageDialog(String sTitle, String sMessage, int nDialogType, int nLength, int nWidth, boolean fCopySave)
public static void showMessageDialog(String sTitle, String sMessage, int nDialogType, int nLength, int nWidth, boolean fCopySave)
{
JTextArea txtArea = new JTextArea(sMessage);
final JPanel panel = new JPanel();
Expand All @@ -118,6 +119,7 @@ protected void showMessageDialog(String sTitle, String sMessage, int nDialogType
txtArea.setEditable(false);
txtArea.setLineWrap(false);
txtArea.setWrapStyleWord(true);
txtArea.setFont(new Font("monospaced", Font.PLAIN, 12));
pneMessage.setPreferredSize(new Dimension(nLength, nWidth));

setResizable(pneMessage);
Expand Down Expand Up @@ -174,7 +176,7 @@ protected void showMessageDialog(String sTitle, String sMessage, int nDialogType
*
* @return a filler {@link JLabel}
*/
private JLabel getFiller()
private static JLabel getFiller()
{
JLabel label = new JLabel();
label.setText(" ");
Expand All @@ -188,7 +190,7 @@ private JLabel getFiller()
*
* @return true if the file was saved
*/
private boolean saveContentsToFile(File file, String sContents)
private static boolean saveContentsToFile(File file, String sContents)
{
PrintStream fileWriter = null;

Expand Down Expand Up @@ -223,7 +225,7 @@ private boolean saveContentsToFile(File file, String sContents)
* @param nLength the length of the dialog window
* @param nWidth the width of the dialog window
*/
protected void showMessageDialog(String sTitle, String sMessage, int nDialogType, int nLength, int nWidth)
protected static void showMessageDialog(String sTitle, String sMessage, int nDialogType, int nLength, int nWidth)
{
showMessageDialog(sTitle, sMessage, nDialogType, nLength, nWidth,false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,7 @@ private boolean validateFileSelection(File file)
{
if (file.exists())
{
String sQuestion = Localization.getLocalText("LBL_file_already_exists",
new String[] {file.getAbsolutePath()});
String sQuestion = Localization.getLocalText("LBL_file_already_exists", file.getAbsolutePath());

if (JOptionPane.showConfirmDialog(null, sQuestion, Localization.getLocalText("LBL_confirm"),
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,17 @@ public List<Map.Entry<Object, Data>> getJMXData(RequestSender requestSender, Vis
new String[]{ ATTR_LOCKS_GRANTED, ATTR_LOCKS_PENDING, ATTR_LISTENER_REG });

String sLocksGranted = getAttributeValueAsString(listAttr, ATTR_LOCKS_GRANTED);
String sLocksPending = getAttributeValueAsString(listAttr, ATTR_LOCKS_PENDING);
String sListenerReg = getAttributeValueAsString(listAttr, ATTR_LOCKS_PENDING);

data.setColumn(CacheStorageManagerData.NODE_ID, Integer.valueOf(sNodeId));
data.setColumn(CacheStorageManagerData.LOCKS_GRANTED,
Integer.parseInt(getAttributeValueAsString(listAttr, ATTR_LOCKS_GRANTED)));
Integer.parseInt(sLocksGranted == null ? "0" : sLocksGranted));
// locks pending may be returns as null over REST
data.setColumn(CacheStorageManagerData.LOCKS_PENDING,
Integer.parseInt(sLocksGranted == null ? "0" : sLocksGranted));
Integer.parseInt(sLocksPending == null ? "0" : sLocksPending));
data.setColumn(CacheStorageManagerData.LISTENER_REGISTRATIONS,
Long.parseLong(getAttributeValueAsString(listAttr, ATTR_LISTENER_REG)));
Long.parseLong(sListenerReg == null ? "0" : sListenerReg));
try {
data.setColumn(CacheStorageManagerData.MAX_QUERY_DURATION,
Long.parseLong(requestSender.getAttribute(objName, "MaxQueryDurationMillis")));
Expand Down Expand Up @@ -258,14 +261,26 @@ public SortedMap<Object, Data> getAggregatedDataFromHttpQuerying(VisualVMModel
for (int i = 0; i < nodeCacheItems.size(); i++)
{
JsonNode nodeCacheStorage = nodeCacheItems.get(i);
Data data = new CacheStorageManagerData();
// Workaround Bug 33107052
if (nodeCacheStorage.size() < 2)
{
continue;
}
Data data = new CacheStorageManagerData();

JsonNode locksGranted = nodeCacheStorage.get("locksGranted");
JsonNode locksGranted = nodeCacheStorage.get("locksGranted");
if (locksGranted == null)
{
// Connecting to version without Bug 32134281 fix so force less efficient way
List<Map.Entry<Object, Data>> jmxData = getJMXData(requestSender, model);
jmxData.forEach(e -> mapData.put(e.getKey(), e.getValue()));
if (jmxData == null || jmxData.size() == 0)
{
return null;
}
else
{
jmxData.forEach(e -> mapData.put(e.getKey(), e.getValue()));
}
return mapData;
}

Expand All @@ -281,7 +296,7 @@ public SortedMap<Object, Data> getAggregatedDataFromHttpQuerying(VisualVMModel
try
{
data.setColumn(CacheStorageManagerData.INDEX_TOTAL_UNITS,nodeCacheStorage.get("indexTotalUnits").asLong());
data.setColumn(CacheStorageManagerData.INDEXING_TOTAL_MILLIS,nodeCacheStorage.get("IndexingTotalMillis").asLong());
data.setColumn(CacheStorageManagerData.INDEXING_TOTAL_MILLIS,nodeCacheStorage.get("indexingTotalMillis").asLong());
}
catch (Exception ignore)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,13 @@ LBL_rest_request_timeout=REST Request Timeout\:
LBL_millis=millis.
LBL_enable_rest_debug=Enable REST debug\:
LBL_other=Other / Experimental
LBL_enable_heatmap=Enable Heat Map* \:
LBL_analyze_log_file=Analyze Unavailable Time in Logfile
LBL_enable_zoom=Enable Zoom on Graphs* \:
LBL_enable_cluster_snapshot=Enable Cluster Snapshot Tab* \:
LBL_enable_admin_functions=Enable Cluster Heap Dump* \:
LBL_enable_persistence_list=Enable Persistence List* \:
LBL_reconnect=Items marked with (*) take effect when you reconnect to a Coherence cluster.
LBL_verbose=Do you want to include verbose partition level output?
TTIP_refresh_time=Time (in seconds) between refreshing data from the cluster. Do not set too low as this could adversely affect performance in large clusters.
TTIP_log_query_times=Enables logging of query times to the VisualVM logfile when retrieving data.
TTIP_disable_mbean_check=Disables the MBean check when connecting to WebLogic Server. This allows the plugin to startup without checking for Cluster MBean.
Expand All @@ -551,4 +552,5 @@ TTIP_rest_debug=Enables HTTP request debugging when using REST to connect to a c
TTIP_persistence_list=Enables dropdown list of snapshots rather than having to enter the snapshot when performing snapshot operations.
TTIP_zoom_enabled=Enables additional zoom function for all graphs.
TTIP_enable_cluster_snapshot=Enables experimental cluster snapshot tab.
TTIP_enable_cluster_head_dump=Enables the cluster heap dump button on the Cluster Overview tab.
TTIP_enable_cluster_head_dump=Enables the cluster heap dump button on the Cluster Overview tab.
TTIP_LBL_analyze_log_file=Analyzes a Coherence log file that has Partition Events Logging enabled.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package com.oracle.coherence.plugin.visualvm;

import org.junit.Test;

import java.io.File;
import java.net.URL;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
* Tests for the UnavailabilityTimeAnalyzer.
*
* @author Tim Middleton 2021.07.06
*/
public class UnavailabilityTimeAnalyzerTest
{
@Test
public void testAnalyzeLogFile()
{
File fileLogFile = getTestResource("/test-logfile-1.log");

assertNotNull(fileLogFile);
CoherenceOptionsPanel.UnavailabilityTimeAnalyzer analyzer =
new CoherenceOptionsPanel.UnavailabilityTimeAnalyzer(fileLogFile);

String sResults = analyzer.analyze(true);
assertNotNull(sResults);
}

@Test
public void testInvalidFile()
{
File fileLogFile = getTestResource("/test-logfile-2.log");

assertNotNull(fileLogFile);
CoherenceOptionsPanel.UnavailabilityTimeAnalyzer analyzer =
new CoherenceOptionsPanel.UnavailabilityTimeAnalyzer(fileLogFile);

String sResults = analyzer.analyze(true);
assertTrue(sResults.contains("No services found. This may not be a Coherence log file."));
}

// ----- helpers --------------------------------------------------------

private File getTestResource(String sResource)
{
URL resource = this.getClass().getResource(sResource);
assertNotNull(resource);
return new File(resource.getFile());
}

// ----- data members ---------------------------------------------------

private File testLogfile;
}
Loading

0 comments on commit 0ba51a4

Please sign in to comment.