This is an automated email from the ASF dual-hosted git repository.
namelchev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 9003d09e29e IGNITE-14913 Added cache metrics command for Control
Script (#9694)
9003d09e29e is described below
commit 9003d09e29e2465e0766be73f0837bc56ae64a24
Author: Ilya Shishkov <[email protected]>
AuthorDate: Wed Jun 1 15:59:34 2022 +0300
IGNITE-14913 Added cache metrics command for Control Script (#9694)
---
docs/_docs/tools/control-script.adoc | 29 +++
.../commandline/cache/CacheCommandList.java | 7 +-
.../internal/commandline/cache/CacheMetrics.java | 133 ++++++++++
.../commandline/cache/CacheSubcommands.java | 7 +-
.../testsuites/IgniteControlUtilityTestSuite.java | 2 +
.../ignite/util/CacheMetricsCommandTest.java | 278 +++++++++++++++++++++
.../visor/cache/metrics/CacheMetricsOperation.java | 53 ++++
.../visor/cache/metrics/VisorCacheMetricsTask.java | 114 +++++++++
.../cache/metrics/VisorCacheMetricsTaskArg.java | 84 +++++++
.../cache/metrics/VisorCacheMetricsTaskResult.java | 83 ++++++
.../main/resources/META-INF/classnames.properties | 5 +
...mandHandlerClusterByClassTest_cache_help.output | 7 +
...dlerClusterByClassWithSSLTest_cache_help.output | 7 +
13 files changed, 807 insertions(+), 2 deletions(-)
diff --git a/docs/_docs/tools/control-script.adoc
b/docs/_docs/tools/control-script.adoc
index 599bf841de1..d1fe4732356 100644
--- a/docs/_docs/tools/control-script.adoc
+++ b/docs/_docs/tools/control-script.adoc
@@ -1081,3 +1081,32 @@ tab:Window[]
control.bat --enable-experimental --consistency status
----
--
+
+== Manage cache metrics collection
+
+The command provides an ability to enable, disable or show status of cache
metrics collection.
+
+[source, shell]
+----
+control.sh|bat --cache metrics enable|disable|status --caches
cache1[,...,cacheN]|--all-caches
+----
+
+Parameters:
+
+[cols="1,3",opts="header"]
+|===
+| Parameter | Description
+| `--caches cache1[,...,cacheN]`| Specifies a comma-separated list of cache
names to which operation should be applied.
+| `--all-caches` | Applies operation to all user caches.
+|===
+
+Examples:
+[source, shell]
+----
+# Show metrics statuses for all caches:
+control.sh|bat --cache metrics status --all-caches
+
+# Enable metrics collection for cache-1 and cache-2:
+control.sh|bat --cache metrics enable --caches cache-2,cache-1
+----
+
diff --git
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommandList.java
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommandList.java
index d11ddcbfbf6..5eed85e63c8 100644
---
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommandList.java
+++
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommandList.java
@@ -87,7 +87,12 @@ public enum CacheCommandList {
/**
* Index force rebuild.
*/
- INDEX_FORCE_REBUILD("indexes_force_rebuild", new
CacheIndexesForceRebuild());
+ INDEX_FORCE_REBUILD("indexes_force_rebuild", new
CacheIndexesForceRebuild()),
+
+ /**
+ * Enable, disable or show status for cache metrics.
+ */
+ METRICS("metrics", new CacheMetrics());
/** Enumerated values. */
private static final CacheCommandList[] VALS = values();
diff --git
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheMetrics.java
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheMetrics.java
new file mode 100644
index 00000000000..602ac23eedd
--- /dev/null
+++
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheMetrics.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ignite.internal.commandline.cache;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.AbstractCommand;
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.TaskExecutor;
+import org.apache.ignite.internal.commandline.systemview.SystemViewCommand;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation;
+import org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTask;
+import org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTaskArg;
+import
org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTaskResult;
+
+import static java.util.Arrays.asList;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.CommandLogger.or;
+import static
org.apache.ignite.internal.commandline.cache.CacheSubcommands.METRICS;
+import static
org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation.DISABLE;
+import static
org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation.ENABLE;
+import static
org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation.STATUS;
+import static
org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleType.STRING;
+
+/**
+ * Cache sub-command for a cache metrics collection management. It provides an
ability to enable, disable or show status.
+ */
+public class CacheMetrics extends AbstractCommand<VisorCacheMetricsTaskArg> {
+ /** Argument for applying metrics command operation to explicitly
specified caches. */
+ public static final String CACHES_ARGUMENT = "--caches";
+
+ /** Argument for applying metrics command operation to all user caches. */
+ public static final String ALL_CACHES_ARGUMENT = "--all-caches";
+
+ /** Incorrect metrics operation message. */
+ public static final String INCORRECT_METRICS_OPERATION_MESSAGE = "Expected
correct metrics command operation.";
+
+ /** Incorrect cache argument message. */
+ public static final String INCORRECT_CACHE_ARGUMENT_MESSAGE =
+ String.format("Expected one of these arguments: '%s' or '%s'. Multiple
arguments are not allowed.",
+ CACHES_ARGUMENT, ALL_CACHES_ARGUMENT);
+
+ /** Expected caches list message. */
+ public static final String EXPECTED_CACHES_LIST_MESSAGE = "comma-separated
list of cache names.";
+
+ /** Task argument. */
+ private VisorCacheMetricsTaskArg arg;
+
+ /** {@inheritDoc} */
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger
log) throws Exception {
+ try (GridClient client = Command.startClient(clientCfg)) {
+ VisorCacheMetricsTaskResult res =
TaskExecutor.executeTaskByNameOnNode(client,
+ VisorCacheMetricsTask.class.getName(), arg, null, clientCfg);
+
+ List<List<?>> values = new ArrayList<>();
+
+ for (Map.Entry<String, Boolean> e : res.result().entrySet())
+ values.add(asList(e.getKey(), e.getValue() ? "enabled" :
"disabled"));
+
+ SystemViewCommand.printTable(asList("Cache Name", "Metrics
Status"), asList(STRING, STRING), values, log);
+
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printUsage(Logger log) {
+ String desc = "Manages user cache metrics collection: enables,
disables it or shows status.";
+
+ String cachesArgDesc = CACHES_ARGUMENT + " cache1" +
optional(",...,cacheN");
+
+ Map<String, String> paramsDesc = F.asMap(
+ cachesArgDesc, "specifies a comma-separated list of cache names to
which operation should be applied.",
+ ALL_CACHES_ARGUMENT, "applies operation to all user caches.");
+
+ usageCache(log, METRICS, desc, paramsDesc, or(ENABLE, DISABLE,
STATUS), or(cachesArgDesc, ALL_CACHES_ARGUMENT));
+ }
+
+ /** {@inheritDoc} */
+ @Override public VisorCacheMetricsTaskArg arg() {
+ return arg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void parseArguments(CommandArgIterator argIter) {
+ CacheMetricsOperation op =
CacheMetricsOperation.of(argIter.nextArg(INCORRECT_METRICS_OPERATION_MESSAGE));
+
+ if (op == null)
+ throw new
IllegalArgumentException(INCORRECT_METRICS_OPERATION_MESSAGE);
+
+ Set<String> cacheNames;
+
+ String arg = argIter.nextArg(INCORRECT_CACHE_ARGUMENT_MESSAGE);
+
+ if (CACHES_ARGUMENT.equals(arg))
+ cacheNames = new
TreeSet<>(argIter.nextStringSet(EXPECTED_CACHES_LIST_MESSAGE));
+ else if (ALL_CACHES_ARGUMENT.equals(arg))
+ cacheNames = Collections.emptySet();
+ else
+ throw new
IllegalArgumentException(INCORRECT_CACHE_ARGUMENT_MESSAGE);
+
+ this.arg = new VisorCacheMetricsTaskArg(op, cacheNames);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return METRICS.text().toUpperCase();
+ }
+}
diff --git
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheSubcommands.java
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheSubcommands.java
index 770e8ead20f..1565dafc95e 100644
---
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheSubcommands.java
+++
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/cache/CacheSubcommands.java
@@ -96,7 +96,12 @@ public enum CacheSubcommands {
/**
* Destroy caches.
*/
- DESTROY("destroy", null, new CacheDestroy());
+ DESTROY("destroy", null, new CacheDestroy()),
+
+ /**
+ * Enable / disable cache metrics collection or show metrics collection
status.
+ */
+ METRICS("metrics", null, new CacheMetrics());
/** Enumerated values. */
private static final CacheSubcommands[] VALS = values();
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java
b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java
index f020609d046..02206c76b8b 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java
@@ -22,6 +22,7 @@ import org.apache.ignite.events.BaselineEventsRemoteTest;
import org.apache.ignite.internal.commandline.CommandHandlerParsingTest;
import
org.apache.ignite.internal.commandline.indexreader.IgniteIndexReaderTest;
import
org.apache.ignite.internal.processors.security.GridCommandHandlerSslWithSecurityTest;
+import org.apache.ignite.util.CacheMetricsCommandTest;
import org.apache.ignite.util.GridCommandHandlerBrokenIndexTest;
import org.apache.ignite.util.GridCommandHandlerCheckIndexesInlineSizeTest;
import org.apache.ignite.util.GridCommandHandlerClusterByClassTest;
@@ -103,6 +104,7 @@ import org.junit.runners.Suite;
SystemViewCommandTest.class,
MetricCommandTest.class,
PerformanceStatisticsCommandTest.class,
+ CacheMetricsCommandTest.class,
IgniteIndexReaderTest.class
})
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/util/CacheMetricsCommandTest.java
b/modules/control-utility/src/test/java/org/apache/ignite/util/CacheMetricsCommandTest.java
new file mode 100644
index 00000000000..ad7d99ebe30
--- /dev/null
+++
b/modules/control-utility/src/test/java/org/apache/ignite/util/CacheMetricsCommandTest.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ignite.util;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.commandline.cache.CacheMetrics;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.junit.Test;
+
+import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_INVALID_ARGUMENTS;
+import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
+import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR;
+import static org.apache.ignite.internal.commandline.CommandList.CACHE;
+import static
org.apache.ignite.internal.commandline.cache.CacheMetrics.ALL_CACHES_ARGUMENT;
+import static
org.apache.ignite.internal.commandline.cache.CacheMetrics.CACHES_ARGUMENT;
+import static
org.apache.ignite.internal.commandline.cache.CacheMetrics.EXPECTED_CACHES_LIST_MESSAGE;
+import static
org.apache.ignite.internal.commandline.cache.CacheMetrics.INCORRECT_CACHE_ARGUMENT_MESSAGE;
+import static
org.apache.ignite.internal.commandline.cache.CacheMetrics.INCORRECT_METRICS_OPERATION_MESSAGE;
+import static
org.apache.ignite.internal.commandline.cache.CacheSubcommands.METRICS;
+import static org.apache.ignite.internal.util.lang.GridFunc.asMap;
+
+/**
+ * Test for {@link CacheMetrics} command.
+ */
+public class CacheMetricsCommandTest extends GridCommandHandlerAbstractTest {
+ /** Enable operation. */
+ private static final String ENABLE =
CacheMetricsOperation.ENABLE.toString();
+
+ /** Disable operation. */
+ private static final String DISABLE =
CacheMetricsOperation.DISABLE.toString();
+
+ /** Status operation. */
+ private static final String STATUS =
CacheMetricsOperation.STATUS.toString();
+
+ /** Cache one. */
+ private static final String CACHE_ONE = "cache-1";
+
+ /** Cache two. */
+ private static final String CACHE_TWO = "cache-2";
+
+ /** {@inheritDoc} */
+ @Override public void beforeTest() throws Exception {
+ super.beforeTest();
+
+ injectTestSystemOut();
+ persistenceEnable(false);
+ autoConfirmation = false;
+
+ startGrids(2);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ stopAllGrids();
+ }
+
+ /**
+ * Tests metrics enable / disable operations.
+ */
+ @Test
+ public void testEnableDisable() {
+ // Test empty cluster
+ checkExecutionSuccess(Collections.emptyMap(), ENABLE,
ALL_CACHES_ARGUMENT);
+
+ createCachesWithMetrics(asMap(CACHE_ONE, false, CACHE_TWO, true));
+
+ checkExecutionSuccess(asMap(CACHE_ONE, true), ENABLE, CACHES_ARGUMENT,
CACHE_ONE);
+ checkExecutionSuccess(asMap(CACHE_TWO, false), DISABLE,
CACHES_ARGUMENT, CACHE_TWO);
+
+ // Cache list with duplicates
+ String cacheNames = String.join(",", CACHE_TWO, CACHE_ONE, CACHE_ONE,
CACHE_TWO);
+
+ checkExecutionSuccess(asMap(CACHE_ONE, false, CACHE_TWO, false),
DISABLE, CACHES_ARGUMENT, cacheNames);
+
+ checkExecutionSuccess(asMap(CACHE_ONE, true, CACHE_TWO, true), ENABLE,
ALL_CACHES_ARGUMENT);
+ }
+
+ /**
+ * Tests metrics status operation.
+ */
+ @Test
+ public void testStatus() {
+ // Test empty cluster
+ checkExecutionSuccess(Collections.emptyMap(), STATUS,
ALL_CACHES_ARGUMENT);
+
+ createCachesWithMetrics(asMap(CACHE_ONE, false, CACHE_TWO, true));
+
+ checkExecutionSuccess(asMap(CACHE_ONE, false), STATUS,
CACHES_ARGUMENT, CACHE_ONE);
+ checkExecutionSuccess(asMap(CACHE_TWO, true), STATUS, CACHES_ARGUMENT,
CACHE_TWO);
+
+ // Cache list with duplicates
+ String cacheNames = String.join(",", CACHE_TWO, CACHE_ONE, CACHE_ONE,
CACHE_TWO);
+
+ checkExecutionSuccess(asMap(CACHE_ONE, false, CACHE_TWO, true),
STATUS, CACHES_ARGUMENT, cacheNames);
+
+ checkExecutionSuccess(asMap(CACHE_ONE, false, CACHE_TWO, true),
STATUS, ALL_CACHES_ARGUMENT);
+ }
+
+ /**
+ * Tests metrics operations for a non-existing cache.
+ */
+ @Test
+ public void testNotFoundCache() {
+ createCachesWithMetrics(asMap(CACHE_ONE, false));
+
+ String descriptorsNotFoundMsg = "One or more cache descriptors not
found [caches=[" + CACHE_ONE + ", " +
+ CACHE_TWO + ']';
+
+ checkExecutionError(descriptorsNotFoundMsg, ENABLE, CACHES_ARGUMENT,
CACHE_ONE + ',' + CACHE_TWO);
+
+ // Check that metrics statuses was not changed
+ checkClusterMetrics(asMap(CACHE_ONE, false));
+
+ checkExecutionError("Cache does not exist: " + CACHE_TWO, STATUS,
CACHES_ARGUMENT, CACHE_ONE + ',' + CACHE_TWO);
+ }
+
+ /** */
+ @Test
+ public void testInvalidArguments() {
+ String checkArgs = "Check arguments. ";
+
+ // Check when no operation passed
+ checkInvalidArguments(checkArgs + INCORRECT_METRICS_OPERATION_MESSAGE);
+
+ // Check when unknown operation passed
+ checkInvalidArguments(checkArgs + INCORRECT_METRICS_OPERATION_MESSAGE,
"bad-command");
+
+ // Check when no --caches/--all-caches arguments passed
+ checkInvalidArguments(checkArgs + INCORRECT_CACHE_ARGUMENT_MESSAGE,
ENABLE);
+ checkInvalidArguments(checkArgs + INCORRECT_CACHE_ARGUMENT_MESSAGE,
STATUS);
+
+ String invalidCacheListFullMsg = "Check arguments. Expected " +
EXPECTED_CACHES_LIST_MESSAGE;
+
+ // Check when --caches argument passed without list of caches
+ checkInvalidArguments(invalidCacheListFullMsg, ENABLE,
CACHES_ARGUMENT);
+ checkInvalidArguments(invalidCacheListFullMsg, STATUS,
CACHES_ARGUMENT);
+
+ String incorrectCacheArgFullMsg = checkArgs +
INCORRECT_CACHE_ARGUMENT_MESSAGE;
+
+ // Check when unknown argument is passed after metric operation
+ checkInvalidArguments(incorrectCacheArgFullMsg, ENABLE, "--arg");
+ checkInvalidArguments(incorrectCacheArgFullMsg, STATUS, "--arg");
+
+ String unexpectedCacheArgMsg = "Unexpected argument of --cache
subcommand: ";
+
+ // Check when extra argument passed after correct command
+ checkInvalidArguments(unexpectedCacheArgMsg + ALL_CACHES_ARGUMENT,
ENABLE, CACHES_ARGUMENT, CACHE_ONE,
+ ALL_CACHES_ARGUMENT);
+ checkInvalidArguments(unexpectedCacheArgMsg + CACHES_ARGUMENT, STATUS,
ALL_CACHES_ARGUMENT, CACHES_ARGUMENT,
+ CACHE_ONE);
+
+ // Check when after --caches argument extra argument is passed instead
of list of caches
+ checkInvalidArguments(unexpectedCacheArgMsg + ALL_CACHES_ARGUMENT,
ENABLE, CACHES_ARGUMENT, ALL_CACHES_ARGUMENT);
+ }
+
+ /**
+ * Check execution of metric operation and parse resulting table.
+ *
+ * @param expStatuses Expected table entries in command output.
+ * @param args Command arguments.
+ */
+ private void checkExecutionSuccess(Map<String, Boolean> expStatuses,
String... args) {
+ exec(EXIT_CODE_OK, args);
+
+ checkOutput(expStatuses, testOut.toString());
+
+ checkClusterMetrics(expStatuses);
+ }
+
+ /**
+ * @param expExitCode Expected exit code.
+ * @param args Command arguments.
+ */
+ private void exec(int expExitCode, String... args) {
+ String[] fullArgs = F.concat(new String[] {CACHE.text(),
METRICS.text()}, args);
+
+ int exitCode = execute(fullArgs);
+ assertEquals("Unexpected exit code", expExitCode, exitCode);
+ }
+
+ /** */
+ private void checkInvalidArguments(String expOut, String... args) {
+ checkExecutionAndOutput(EXIT_CODE_INVALID_ARGUMENTS, expOut, args);
+ }
+
+ /** */
+ private void checkExecutionError(String expOut, String... args) {
+ checkExecutionAndOutput(EXIT_CODE_UNEXPECTED_ERROR, expOut, args);
+ }
+
+ /**
+ * Check command execution and results.
+ *
+ * @param expExitCode Expected exit code.
+ * @param expOut Expected command output.
+ * @param args Command arguments.
+ */
+ private void checkExecutionAndOutput(int expExitCode, String expOut,
String... args) {
+ exec(expExitCode, args);
+
+ GridTestUtils.assertContains(log, testOut.toString(), expOut);
+ }
+
+ /**
+ * @param expStatuses Expected metrics statuses.
+ * @param testOutStr Test output.
+ */
+ private void checkOutput(Map<String, Boolean> expStatuses, String
testOutStr) {
+ for (Map.Entry<String, Boolean> entry : expStatuses.entrySet()) {
+ String cacheName = entry.getKey();
+ String metricsStatus = entry.getValue() ? "enabled" : "disabled";
+
+ Matcher cacheStatusMatcher = Pattern.compile(cacheName + "\\s+" +
metricsStatus).matcher(testOutStr);
+
+ String msg = String.format("Unexpected count of table entries for
metrics: [cacheName=%s, metricsStatus=%s]",
+ cacheName, metricsStatus);
+
+ int cnt = 0;
+
+ while (cacheStatusMatcher.find())
+ cnt++;
+
+ assertEquals(msg, 1, cnt);
+ }
+ }
+
+ /**
+ * @param metricsStatuses Metrics statuses.
+ */
+ private void createCachesWithMetrics(Map<String, Boolean> metricsStatuses)
{
+ for (Map.Entry<String, Boolean> nameAndState :
metricsStatuses.entrySet()) {
+ grid(0).getOrCreateCache(new CacheConfiguration<>()
+ .setName(nameAndState.getKey())
+ .setStatisticsEnabled(nameAndState.getValue()));
+ }
+
+ checkClusterMetrics(metricsStatuses);
+ }
+
+ /**
+ * @param expStatuses Expected cache metrics statuses.
+ */
+ private void checkClusterMetrics(Map<String, Boolean> expStatuses) {
+ for (Ignite ignite : G.allGrids()) {
+ for (String cacheName : expStatuses.keySet()) {
+ Boolean cacheMetricsEnabled =
ignite.cache(cacheName).metrics().isStatisticsEnabled();
+
+ assertEquals("Unexpected metrics mode for cache: " +
cacheName, expStatuses.get(cacheName),
+ cacheMetricsEnabled);
+ }
+ }
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/CacheMetricsOperation.java
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/CacheMetricsOperation.java
new file mode 100644
index 00000000000..133e454fca8
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/CacheMetricsOperation.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ignite.internal.visor.cache.metrics;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Enum for cache metrics command operations.
+ */
+public enum CacheMetricsOperation {
+ /** Enable operation. */
+ ENABLE,
+
+ /** Disable operation. */
+ DISABLE,
+
+ /** Status operation. */
+ STATUS;
+
+ /**
+ * @param strRep String representation of operation.
+ *
+ * @return Operation corresponding to the specified string representation.
+ */
+ public static @Nullable CacheMetricsOperation of(String strRep) {
+ for (CacheMetricsOperation op : values()) {
+ if (op.name().equalsIgnoreCase(strRep))
+ return op;
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return super.toString().toLowerCase();
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTask.java
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTask.java
new file mode 100644
index 00000000000..5071ded10e6
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTask.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ignite.internal.visor.cache.metrics;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.processors.task.GridVisorManagementTask;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.VisorJob;
+import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.jetbrains.annotations.Nullable;
+
+import static
org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation.ENABLE;
+
+/**
+ * Task for a cache metrics command.
+ */
+@GridInternal
+@GridVisorManagementTask
+public class VisorCacheMetricsTask extends
VisorOneNodeTask<VisorCacheMetricsTaskArg, VisorCacheMetricsTaskResult> {
+ /** Serial version uid. */
+ private static final long serialVersionUID = 0L;
+
+ /** {@inheritDoc} */
+ @Override protected VisorCacheMetricsJob job(VisorCacheMetricsTaskArg arg)
{
+ return new VisorCacheMetricsJob(arg, false);
+ }
+
+ /**
+ * Job returns {@link Map} with names of processed caches paired with
corresponding metrics collection statuses or
+ * exception, caught during execution of job.
+ * Results are passed into instance of wrapper class {@link
VisorCacheMetricsTaskResult}.
+ */
+ private static class VisorCacheMetricsJob extends
VisorJob<VisorCacheMetricsTaskArg, VisorCacheMetricsTaskResult> {
+ /** Serial version uid. */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Create job with specified argument.
+ *
+ * @param arg Job argument.
+ * @param debug Flag indicating whether debug information should be
printed into node log.
+ */
+ protected VisorCacheMetricsJob(@Nullable VisorCacheMetricsTaskArg arg,
boolean debug) {
+ super(arg, debug);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected VisorCacheMetricsTaskResult run(@Nullable
VisorCacheMetricsTaskArg arg)
+ throws IgniteException {
+ if (arg != null) {
+ Collection<String> cacheNames = F.isEmpty(arg.cacheNames()) ?
ignite.cacheNames() : arg.cacheNames();
+
+ try {
+ switch (arg.operation()) {
+ case ENABLE:
+ case DISABLE:
+ ignite.cluster().enableStatistics(cacheNames,
ENABLE == arg.operation());
+
+ return new
VisorCacheMetricsTaskResult(cacheMetricsStatus(cacheNames));
+
+ case STATUS:
+ return new
VisorCacheMetricsTaskResult(cacheMetricsStatus(cacheNames));
+
+ default:
+ throw new IllegalStateException("Unexpected value:
" + arg.operation());
+ }
+ }
+ catch (Exception e) {
+ return new VisorCacheMetricsTaskResult(e);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param cacheNames Cache names.
+ */
+ private Map<String, Boolean> cacheMetricsStatus(Collection<String>
cacheNames) {
+ Map<String, Boolean> cacheMetricsStatus = new TreeMap<>();
+
+ for (String cacheName : cacheNames) {
+ IgniteInternalCache<?, ?> cachex = ignite.cachex(cacheName);
+
+ if (cachex != null)
+ cacheMetricsStatus.put(cacheName,
cachex.clusterMetrics().isStatisticsEnabled());
+ else
+ throw new IgniteException("Cache does not exist: " +
cacheName);
+ }
+
+ return cacheMetricsStatus;
+ }
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTaskArg.java
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTaskArg.java
new file mode 100644
index 00000000000..c6574e40532
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTaskArg.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ignite.internal.visor.cache.metrics;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Collections;
+import java.util.Set;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Task argument for {@link VisorCacheMetricsTask}.
+ */
+public class VisorCacheMetricsTaskArg extends IgniteDataTransferObject {
+ /** Serial version uid. */
+ private static final long serialVersionUID = 0L;
+
+ /** Metrics command operation. */
+ private CacheMetricsOperation op;
+
+ /** Caches which will be processed. If not set, operation will affect all
caches. */
+ private Set<String> cacheNames;
+
+ /**
+ * Default constructor.
+ */
+ public VisorCacheMetricsTaskArg() {
+ // No-op.
+ }
+
+ /**
+ * @param op Metrics command operation.
+ * @param cacheNames Names of the caches, which should be processed.
+ */
+ public VisorCacheMetricsTaskArg(CacheMetricsOperation op, Set<String>
cacheNames) {
+ this.op = op;
+ this.cacheNames = cacheNames == null ? null :
Collections.unmodifiableSet(cacheNames);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws
IOException {
+ U.writeEnum(out, op);
+ U.writeCollection(out, cacheNames);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in)
throws IOException,
+ ClassNotFoundException {
+ op = U.readEnum(in, CacheMetricsOperation.class);
+ cacheNames = U.readSet(in);
+ }
+
+ /**
+ * @return Metrics command operation.
+ */
+ public CacheMetricsOperation operation() {
+ return op;
+ }
+
+ /**
+ * @return Caches which will be processed. If not set, operation will
affect all caches.
+ */
+ public Set<String> cacheNames() {
+ return Collections.unmodifiableSet(cacheNames);
+ }
+}
+
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTaskResult.java
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTaskResult.java
new file mode 100644
index 00000000000..e232f7048f2
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/metrics/VisorCacheMetricsTaskResult.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ignite.internal.visor.cache.metrics;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Result wrapper for {@link VisorCacheMetricsTask}.
+ */
+public class VisorCacheMetricsTaskResult extends IgniteDataTransferObject {
+ /** Serial version uid. */
+ private static final long serialVersionUID = 0L;
+
+ /** Task result. */
+ private Map<String, Boolean> result;
+
+ /** Task execution error. */
+ private Exception error;
+
+ /**
+ * Default constructor.
+ */
+ public VisorCacheMetricsTaskResult() {
+ // No-op.
+ }
+
+ /**
+ * @param result Task execution result.
+ */
+ public VisorCacheMetricsTaskResult(Map<String, Boolean> result) {
+ this.result = Collections.unmodifiableMap(result);
+ }
+
+ /**
+ * @param error Task execution error.
+ */
+ public VisorCacheMetricsTaskResult(Exception error) {
+ this.error = error;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws
IOException {
+ U.writeMap(out, result);
+ out.writeObject(error);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in)
throws IOException, ClassNotFoundException {
+ result = U.readMap(in);
+ error = (Exception)in.readObject();
+ }
+
+ /**
+ * Get task result or task execution error.
+ */
+ public Map<String, Boolean> result() throws Exception {
+ if (error != null)
+ throw error;
+
+ return Collections.unmodifiableMap(result);
+ }
+}
diff --git a/modules/core/src/main/resources/META-INF/classnames.properties
b/modules/core/src/main/resources/META-INF/classnames.properties
index 266910ea138..5aeb89669a7 100644
--- a/modules/core/src/main/resources/META-INF/classnames.properties
+++ b/modules/core/src/main/resources/META-INF/classnames.properties
@@ -2051,6 +2051,11 @@ org.apache.ignite.internal.visor.cache.VisorCacheMetrics
org.apache.ignite.internal.visor.cache.VisorCacheMetricsCollectorTask
org.apache.ignite.internal.visor.cache.VisorCacheMetricsCollectorTask$VisorCacheMetricsCollectorJob
org.apache.ignite.internal.visor.cache.VisorCacheMetricsCollectorTaskArg
+org.apache.ignite.internal.visor.cache.metrics.CacheMetricsOperation
+org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTask
+org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTask$VisorCacheMetricsJob
+org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTaskArg
+org.apache.ignite.internal.visor.cache.metrics.VisorCacheMetricsTaskResult
org.apache.ignite.internal.visor.cache.VisorCacheModifyTask
org.apache.ignite.internal.visor.cache.VisorCacheModifyTask$VisorCacheModifyJob
org.apache.ignite.internal.visor.cache.VisorCacheModifyTaskArg
diff --git
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
index d175fcce598..585370b4963 100644
---
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
+++
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
@@ -83,6 +83,13 @@ Arguments: --cache help --yes
--cache-names - Comma-separated list of cache names for which indexes
should be rebuilt.
--group-names - Comma-separated list of cache group names for which
indexes should be rebuilt.
+ --cache metrics enable|disable|status --caches
cache1[,...,cacheN]|--all-caches
+ Manages user cache metrics collection: enables, disables it or shows
status.
+
+ Parameters:
+ --caches cache1[,...,cacheN] - specifies a comma-separated list of
cache names to which operation should be applied.
+ --all-caches - applies operation to all user caches.
+
Command [CACHE] finished with code: 0
Control utility has completed execution at: <!any!>
Execution time: <!any!>
diff --git
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
index d175fcce598..585370b4963 100644
---
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
+++
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
@@ -83,6 +83,13 @@ Arguments: --cache help --yes
--cache-names - Comma-separated list of cache names for which indexes
should be rebuilt.
--group-names - Comma-separated list of cache group names for which
indexes should be rebuilt.
+ --cache metrics enable|disable|status --caches
cache1[,...,cacheN]|--all-caches
+ Manages user cache metrics collection: enables, disables it or shows
status.
+
+ Parameters:
+ --caches cache1[,...,cacheN] - specifies a comma-separated list of
cache names to which operation should be applied.
+ --all-caches - applies operation to all user caches.
+
Command [CACHE] finished with code: 0
Control utility has completed execution at: <!any!>
Execution time: <!any!>