Skip to content

Commit 49b232e

Browse files
committed
Enhancement Request 37293266 - [35017063->24.09.1] ENH: Improve resetStatistics capability for all or for selection of services in the cluster (merge ce/main -> 24.09.1 @ 112448)
[git-p4: depot-paths = "//dev/coherence-ce/release/coherence-ce-v24.09/": change = 112452]
1 parent babb1dc commit 49b232e

File tree

5 files changed

+149
-4
lines changed

5 files changed

+149
-4
lines changed

prj/coherence-core-components/src/main/java/com/tangosol/coherence/component/manageable/modelAdapter/ManagementMBean.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
/*
3-
* Copyright (c) 2000, 2023, Oracle and/or its affiliates.
3+
* Copyright (c) 2000, 2024, Oracle and/or its affiliates.
44
*
55
* Licensed under the Universal Permissive License v 1.0 as shown at
66
* https://oss.oracle.com/licenses/upl.
@@ -260,6 +260,19 @@ protected java.util.Map get_MethodInfo()
260260
});
261261
}
262262

263+
// behavior resetStatistics()
264+
{
265+
mapInfo.put("resetStatistics(Ljava.lang.String;)", new Object[]
266+
{
267+
"Call resetStatistics on each mbeans returned by the query.",
268+
"resetStatistics",
269+
"[Ljava.lang.String;",
270+
new String[] {"sName", },
271+
new String[] {"Ljava.lang.String;", },
272+
null,
273+
});
274+
}
275+
263276
return mapInfo;
264277
}
265278

prj/coherence-core-components/src/main/java/com/tangosol/coherence/component/net/management/model/localModel/ManagementModel.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
/*
3-
* Copyright (c) 2000, 2023, Oracle and/or its affiliates.
3+
* Copyright (c) 2000, 2024, Oracle and/or its affiliates.
44
*
55
* Licensed under the Universal Permissive License v 1.0 as shown at
66
* https://oss.oracle.com/licenses/upl.
@@ -12,6 +12,20 @@
1212

1313
import com.tangosol.coherence.component.net.management.Connector;
1414

15+
import com.tangosol.net.management.MBeanHelper;
16+
17+
import com.oracle.coherence.common.base.Logger;
18+
19+
import javax.management.InstanceNotFoundException;
20+
import javax.management.MBeanException;
21+
import javax.management.MBeanServer;
22+
import javax.management.ObjectInstance;
23+
import javax.management.ObjectName;
24+
import javax.management.ReflectionException;
25+
26+
import java.util.ArrayList;
27+
import java.util.Set;
28+
1529
/**
1630
* Model components implement the JMX-managed functionality of the
1731
* corresponding MBeans without being dependent on any JMX classes and could be
@@ -261,6 +275,43 @@ public void resetStatistics()
261275
{
262276
get_Connector().resetStatistics();
263277
}
278+
279+
public String[] resetStatistics(String sName)
280+
{
281+
ArrayList<String> result = new ArrayList<>();
282+
try
283+
{
284+
MBeanServer server = MBeanHelper.findMBeanServer();
285+
ObjectName objectName = new ObjectName(sName);
286+
Set<ObjectInstance> instances = server.queryMBeans(objectName, null);
287+
for (ObjectInstance instance : instances)
288+
{
289+
try
290+
{
291+
server.invoke(instance.getObjectName(), "resetStatistics", new Object[0], new String[0]);
292+
result.add(instance.getObjectName() + " OK");
293+
}
294+
catch (InstanceNotFoundException | MBeanException | ReflectionException e)
295+
{
296+
Throwable t = rootCause(e);
297+
result.add(instance.getObjectName() + " ERROR: " + t.getMessage());
298+
}
299+
catch (Throwable e)
300+
{
301+
Throwable t = rootCause(e);
302+
result.add(instance.getObjectName() + " ERROR: " + t.getMessage());
303+
}
304+
}
305+
}
306+
catch (Throwable e)
307+
{
308+
Throwable t = rootCause(e);
309+
Logger.warn("Failed to execute query \"" + sName + "\"; " + t);
310+
result.add("Error: " + t.getMessage());
311+
}
312+
313+
return result.toArray(new String[0]);
314+
}
264315

265316
// Accessor for the property "_Connector"
266317
/**
@@ -312,4 +363,16 @@ public void writeExternal(java.io.DataOutput out)
312363
{
313364
throw new IllegalStateException("ManagementModel is not global");
314365
}
366+
367+
private static Throwable rootCause(Throwable t)
368+
{
369+
Throwable rootCause = t;
370+
Throwable cause = t.getCause();
371+
while (cause != null)
372+
{
373+
rootCause = cause;
374+
cause = cause.getCause();
375+
}
376+
return rootCause;
377+
}
315378
}

prj/coherence-core/src/main/java/com/tangosol/internal/management/resources/ClusterResource.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,20 @@ public Response executeOperation(HttpRequest request)
279279
if ("shutdown".equals(sOperationName) || "resetStatistics".equals(sOperationName)
280280
|| "logNodeState".equals(sOperationName))
281281
{
282+
if ("resetStatistics".equals(sOperationName))
283+
{
284+
Map<String, Object> mapQuery = getJsonBody(request);
285+
String query = (String) mapQuery.get("query");
286+
if (query != null && !query.isBlank())
287+
{
288+
return response(getResponseFromMBeanOperation(request,
289+
getManagementQuery(request),
290+
"result",
291+
sOperationName,
292+
new Object[] {query},
293+
new String[] {String.class.getName()}));
294+
}
295+
}
282296
return executeMBeanOperation(request, getMembersQuery(request), sOperationName,
283297
null, null);
284298
}

prj/coherence-core/src/main/resources/management-swagger.json

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,14 +388,41 @@
388388
"Cluster"
389389
],
390390
"summary": "Reset Member Statistics for all the members",
391-
"description": "Use this endpoint to clear the current statistics for all the members.",
391+
"description": "Use this endpoint to clear the current statistics for all the members.\nThis end point also takes an ObjectName pattern (query) to allow you to control\n the MBeans to reset. For example, if you want to reset all the MBeans in\n the cluster, use pattern \"Coherence:type=*\" (for MBeans that don't support\n statistics reset an error will be returned). If you want to reset all the\n cache MBeans, pattern \"Coherence:type=Cache,*\". Pattern should be passed as\n a json object in the request body\n Example: {\"query\": \"Coherence:type=Service,name=DistributedCachePersistence,nodeId=1\"} - reset statistics on a specific service and member\n\n",
392392
"operationId": "/management/coherence/cluster/resetStatistics POST",
393+
"consumes": [
394+
"application/json"
395+
],
396+
"parameters": [{
397+
"in": "body",
398+
"name": "query",
399+
"description": "ObjectName pattern to search for.",
400+
"schema": {
401+
"type": "object",
402+
"properties": {
403+
"query": {
404+
"type": "string"
405+
}
406+
}
407+
}
408+
}],
393409
"produces": [
394410
"application/json"
395411
],
396412
"responses": {
397413
"200": {
398-
"description": "Command invocation is successful"
414+
"description": "It returns a collection of the status for all the MBeans that were reset.",
415+
"schema": {
416+
"type": "object",
417+
"properties": {
418+
"result": {
419+
"type": "array",
420+
"items": {
421+
"type": "string"
422+
}
423+
}
424+
}
425+
}
399426
}
400427
}
401428
}

prj/test/functional/management/src/main/java/management/BaseManagementInfoResourceTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,34 @@ public void testMemberResetStats()
941941
assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
942942
}
943943

944+
@Test
945+
public void testResetStatsQuery()
946+
{
947+
WebTarget target = getBaseTarget();
948+
Response response = target.request().get();
949+
950+
assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
951+
assertThat(response.getHeaderString("X-Content-Type-Options"), is("nosniff"));
952+
Map mapResponse = readEntity(target, response);
953+
954+
List<Number> listMemberIds = (List<Number>) mapResponse.get("memberIds");
955+
956+
assertThat(listMemberIds, notNullValue());
957+
assertThat(listMemberIds.size(), greaterThan(0));
958+
959+
Map<String, String> entity = new LinkedHashMap<>();
960+
entity.put("query", "Coherence:type=Cache,*");
961+
response = getBaseTarget()
962+
.path("resetStatistics").request(MediaType.APPLICATION_JSON_TYPE)
963+
.post(Entity.entity(entity, MediaType.APPLICATION_JSON_TYPE));
964+
965+
assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
966+
Map r = readEntity(target, response);
967+
List<String> result = (List) r.get("result");
968+
assertThat(result.size(), greaterThan(0));
969+
assertTrue(result.stream().anyMatch(s -> s.contains("Coherence:type=Cache") && s.endsWith("OK")));
970+
}
971+
944972
@Test
945973
public void testProxyConnectionManagerResetStats()
946974
{

0 commit comments

Comments
 (0)