You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ni...@apache.org on 2023/01/25 09:09:54 UTC

[ignite] branch master updated: IGNITE-18616 control.sh metric configuration added (#10494)

This is an automated email from the ASF dual-hosted git repository.

nizhikov 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 8e1ba2628a9 IGNITE-18616 control.sh metric configuration added (#10494)
8e1ba2628a9 is described below

commit 8e1ba2628a9e225525f6e9094271985bad36f746
Author: Nikolay <ni...@apache.org>
AuthorDate: Wed Jan 25 12:09:47 2023 +0300

    IGNITE-18616 control.sh metric configuration added (#10494)
---
 docs/_docs/monitoring-metrics/new-metrics.adoc     |   2 +-
 docs/_docs/monitoring-metrics/system-views.adoc    |  11 +++
 docs/_docs/tools/control-script.adoc               |  20 ++++
 .../internal/commandline/metric/MetricCommand.java |  57 ++++++++++-
 .../commandline/metric/MetricCommandArg.java       |   8 +-
 .../org/apache/ignite/util/MetricCommandTest.java  | 104 +++++++++++++++++++++
 .../cache/persistence/DataRegionMetricsImpl.java   |   2 +-
 .../persistence/DistributedMetaStorageImpl.java    |   4 +-
 .../internal/processors/pool/PoolProcessor.java    |   2 +-
 .../internal/visor/metric/VisorMetricTask.java     |  17 ++++
 .../internal/visor/metric/VisorMetricTaskArg.java  |  32 ++++++-
 .../ignite/internal/metric/SystemViewSelfTest.java |  22 +++--
 ...ridCommandHandlerClusterByClassTest_help.output |   8 ++
 ...andHandlerClusterByClassWithSSLTest_help.output |   8 ++
 14 files changed, 280 insertions(+), 17 deletions(-)

diff --git a/docs/_docs/monitoring-metrics/new-metrics.adoc b/docs/_docs/monitoring-metrics/new-metrics.adoc
index 2442bbe7a53..927e834789e 100644
--- a/docs/_docs/monitoring-metrics/new-metrics.adoc
+++ b/docs/_docs/monitoring-metrics/new-metrics.adoc
@@ -364,7 +364,7 @@ Register name: `io.dataregion.{data_region_name}`
 [cols="2,1,3",opts="header"]
 |===
 |Name |    Type |    Description
-|AllocationRate | long|    Allocation rate (pages per second) averaged across rateTimeInternal.
+|AllocationRate | long|    Allocation rate (pages per second) averaged across rateTimeInterval.
 |CheckpointBufferSize |    long |    Checkpoint buffer size in bytes.
 |DirtyPages |  long|    Number of pages in memory not yet synchronized with persistent storage.
 |EmptyDataPages|  long|    Calculates empty data pages count for region. It counts only totally free pages that can be reused (e. g. pages that are contained in reuse bucket of free list).
diff --git a/docs/_docs/monitoring-metrics/system-views.adoc b/docs/_docs/monitoring-metrics/system-views.adoc
index cd9a667c73b..d4bd9658c38 100644
--- a/docs/_docs/monitoring-metrics/system-views.adoc
+++ b/docs/_docs/monitoring-metrics/system-views.adoc
@@ -737,6 +737,17 @@ This view exposes the contents of the metastorage cache.
 |VALUE | string | String or raw binary (if data could not be deserialized for some reason) representation of an element
 |===
 
+== DISTRIBUTED_METASTORAGE
+
+This view exposes the contents of the distributed metastorage cache.
+
+[{table_opts}]
+|===
+|Column | Data type |  Description
+|NAME | string | Name
+|VALUE | string | String or raw binary (if data could not be deserialized for some reason) representation of an element
+|===
+
 == DS_QUEUES
 
 This view exposes the list of `IgniteQueue`.
diff --git a/docs/_docs/tools/control-script.adoc b/docs/_docs/tools/control-script.adoc
index 9f8c754dcfe..01f1da1c201 100644
--- a/docs/_docs/tools/control-script.adoc
+++ b/docs/_docs/tools/control-script.adoc
@@ -898,6 +898,26 @@ io.dataregion.default.PagesReplaceAge             0
 io.dataregion.default.PhysicalMemoryPages         0
 Command [METRIC] finished with code: 0
 
+== Metric configure command
+
+The metrics command configure bounds of histogram metrics or rate time interval of hitrate metric.
+
+[tabs]
+--
+tab:Unix[]
+[source,shell,subs="verbatim,quotes"]
+----
+control.sh --metric --configure-histogram histogram-metric-name 1,2,3
+control.sh --metric --configure-hitrate hitrate-metric-name 1000
+----
+tab:Windows[]
+[source,shell,subs="verbatim,quotes"]
+----
+control.bat --metric --configure-histogram histogram-metric-name 1,2,3
+control.bat --metric --configure-hitrate hitrate-metric-name 1000
+----
+--
+
 == Indexes Management
 
 The commands below allow to get a specific information on indexes and to trigger the indexes rebuild process.
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommand.java
index 350487811f8..3e8d22bf2ed 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommand.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommand.java
@@ -18,9 +18,9 @@
 package org.apache.ignite.internal.commandline.metric;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 import java.util.UUID;
 import java.util.stream.Collectors;
 import org.apache.ignite.IgniteLogger;
@@ -31,13 +31,18 @@ import org.apache.ignite.internal.commandline.Command;
 import org.apache.ignite.internal.commandline.CommandArgIterator;
 import org.apache.ignite.internal.commandline.CommandLogger;
 import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.visor.metric.VisorMetricTask;
 import org.apache.ignite.internal.visor.metric.VisorMetricTaskArg;
 
 import static java.util.Arrays.asList;
 import static org.apache.ignite.internal.commandline.CommandList.METRIC;
+import static org.apache.ignite.internal.commandline.CommandLogger.grouped;
 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.TaskExecutor.executeTaskByNameOnNode;
+import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.CONFIGURE_HISTOGRAM;
+import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.CONFIGURE_HITRATE;
 import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.NODE_ID;
 import static org.apache.ignite.internal.commandline.systemview.SystemViewCommand.printTable;
 import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleType.STRING;
@@ -75,7 +80,7 @@ public class MetricCommand extends AbstractCommand<VisorMetricTaskArg> {
 
                 printTable(asList("metric", "value"), asList(STRING, STRING), data, log);
             }
-            else
+            else if (arg().bounds() == null && arg().rateTimeInterval() < 0)
                 log.info("No metric with specified name was found [name=" + taskArg.name() + "]");
 
             return res;
@@ -93,6 +98,8 @@ public class MetricCommand extends AbstractCommand<VisorMetricTaskArg> {
         nodeId = null;
 
         String metricName = null;
+        Object val = null;
+        boolean configureHistogram = false;
 
         while (argIter.hasNextSubArg()) {
             String arg = argIter.nextArg("Failed to read command argument.");
@@ -112,6 +119,31 @@ public class MetricCommand extends AbstractCommand<VisorMetricTaskArg> {
                         " 123e4567-e89b-42d3-a456-556642440000", e);
                 }
             }
+            else if (cmdArg == CONFIGURE_HISTOGRAM || cmdArg == CONFIGURE_HITRATE) {
+                if (metricName != null) {
+                    throw new IllegalArgumentException(
+                        "One of " + CONFIGURE_HISTOGRAM + ", " + CONFIGURE_HITRATE + " must be specified"
+                    );
+                }
+
+                configureHistogram = cmdArg == CONFIGURE_HISTOGRAM;
+                metricName = argIter.nextArg("Name of metric to configure expected");
+
+                if (configureHistogram) {
+                    val = Arrays.stream(argIter.nextArg("Comma-separated histogram bounds expected").split(","))
+                        .mapToLong(Long::parseLong)
+                        .toArray();
+
+                    if (!F.isSorted((long[])val))
+                        throw new IllegalArgumentException("Bounds must be sorted");
+                }
+                else {
+                    val = argIter.nextNonNegativeLongArg("Hitrate time interval");
+
+                    if ((long)val == 0)
+                        throw new IllegalArgumentException("Positive value expected");
+                }
+            }
             else {
                 if (metricName != null)
                     throw new IllegalArgumentException("Multiple metric(metric registry) names are not supported.");
@@ -123,7 +155,11 @@ public class MetricCommand extends AbstractCommand<VisorMetricTaskArg> {
         if (metricName == null)
             throw new IllegalArgumentException("The name of a metric(metric registry) is expected.");
 
-        taskArg = new VisorMetricTaskArg(metricName);
+        taskArg = new VisorMetricTaskArg(
+            metricName,
+            val != null && configureHistogram ? (long[])val : null,
+            val != null && !configureHistogram ? (Long)val : -1
+        );
     }
 
     /** {@inheritDoc} */
@@ -133,7 +169,7 @@ public class MetricCommand extends AbstractCommand<VisorMetricTaskArg> {
 
     /** {@inheritDoc} */
     @Override public void printUsage(IgniteLogger log) {
-        Map<String, String> params = new HashMap<>();
+        Map<String, String> params = new TreeMap<>();
 
         params.put("node_id", "ID of the node to get the metric values from. If not set, random node will be chosen.");
         params.put("name", "Name of the metric which value should be printed." +
@@ -141,6 +177,19 @@ public class MetricCommand extends AbstractCommand<VisorMetricTaskArg> {
 
         usage(log, "Print metric value:", METRIC, params, optional(NODE_ID, "node_id"),
             "name");
+
+        params.remove("node_id");
+        params.put("name", "Name of the metric which value should be configured.");
+        params.put("newBounds", "Comma-separated list of longs to configure histogram.");
+        params.put("newRateTimeInterval", "Rate time interval of hitrate.");
+
+        usage(
+            log,
+            "Configure metric:", METRIC,
+            params,
+            or(grouped(CONFIGURE_HISTOGRAM, "name", "newBounds"),
+                grouped(CONFIGURE_HITRATE, "name", "newRateTimeInterval"))
+        );
     }
 
     /** {@inheritDoc} */
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommandArg.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommandArg.java
index b73ba2f65c3..2aeaf480512 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommandArg.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/metric/MetricCommandArg.java
@@ -22,7 +22,13 @@ import org.apache.ignite.internal.commandline.argument.CommandArg;
 /** Represents all possible arguments for {@link MetricCommand}. */
 public enum MetricCommandArg implements CommandArg {
     /** Id of the node to get metric values from. */
-    NODE_ID("--node-id");
+    NODE_ID("--node-id"),
+
+    /** Configure histograme. */
+    CONFIGURE_HISTOGRAM("--configure-histogram"),
+
+    /** Configure histograme. */
+    CONFIGURE_HITRATE("--configure-hitrate");
 
     /** Name of the argument. */
     private final String name;
diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
index beffa3e00ea..b173fad8ddb 100644
--- a/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
+++ b/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
@@ -27,6 +27,7 @@ import org.apache.ignite.internal.commandline.CommandList;
 import org.apache.ignite.internal.commandline.metric.MetricCommandArg;
 import org.apache.ignite.internal.processors.metric.MetricRegistry;
 import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
+import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.junit.Test;
 
@@ -34,6 +35,8 @@ import static java.util.regex.Pattern.quote;
 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.CommandList.METRIC;
+import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.CONFIGURE_HISTOGRAM;
+import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.CONFIGURE_HITRATE;
 import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.NODE_ID;
 import static org.apache.ignite.internal.commandline.systemview.SystemViewCommand.COLUMN_SEPARATOR;
 import static org.apache.ignite.internal.processors.metric.GridMetricManager.IGNITE_METRICS;
@@ -114,6 +117,107 @@ public class MetricCommandTest extends GridCommandHandlerClusterByClassAbstractT
             "No metric with specified name was found [name=nonexistent.metric]");
     }
 
+    /** Tests command error output in case of invalid arguments for configure command. */
+    @Test
+    public void testInvalidConfigureMetricParameter() {
+        assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HISTOGRAM.argName()),
+            "Name of metric to configure expected");
+
+        assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HITRATE.argName()),
+            "Name of metric to configure expected");
+
+        assertContains(log,
+            executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HISTOGRAM.argName(), "some.metric"),
+            "Comma-separated histogram bounds expected"
+        );
+
+        assertContains(
+            log,
+            executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HITRATE.argName(), "some.metric"),
+            "Hitrate time interval"
+        );
+
+        assertContains(
+            log,
+            executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HISTOGRAM.argName(), "some.metric", "not_a_number"),
+            "Check arguments. For input string: \"not_a_number\""
+        );
+
+        assertContains(
+            log,
+            executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HITRATE.argName(), "some.metric", "not_a_number"),
+            "Check arguments. Invalid value for Hitrate time interval: not_a_number"
+        );
+
+        assertContains(
+            log,
+            executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HISTOGRAM.argName(), "some.metric", "1,not_a_number"),
+            "Check arguments. For input string: \"not_a_number\""
+        );
+
+        assertContains(
+            log,
+            executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, CONFIGURE_HISTOGRAM.argName(), "some.metric", "3,2,1"),
+            "Bounds must be sorted"
+        );
+
+        assertContains(
+            log,
+            executeCommand(
+                EXIT_CODE_INVALID_ARGUMENTS,
+                CMD_METRIC,
+                CONFIGURE_HISTOGRAM.argName(),
+                "some.metric",
+                "1,2,3",
+                CONFIGURE_HITRATE.argName()
+            ),
+            "One of " + CONFIGURE_HISTOGRAM.argName() + ", " + CONFIGURE_HITRATE.argName() + " must be specified"
+        );
+    }
+
+    /** Tests configuration of histgoram metric. */
+    @Test
+    public void testConfigureHistogram() {
+        String mregName = "configure-registry";
+
+        MetricRegistry mreg = ignite0.context().metric().registry(mregName);
+
+        long[] bounds = new long[] {50, 500};
+
+        HistogramMetricImpl histogram = mreg.histogram("histogram", bounds, null);
+
+        bounds = histogram.bounds();
+
+        assertEquals(2, bounds.length);
+        assertEquals(50, bounds[0]);
+        assertEquals(500, bounds[1]);
+
+        executeCommand(EXIT_CODE_OK, CMD_METRIC, CONFIGURE_HISTOGRAM.argName(), histogram.name(), "1,2,3");
+
+        bounds = histogram.bounds();
+
+        assertEquals(3, bounds.length);
+        assertEquals(1, bounds[0]);
+        assertEquals(2, bounds[1]);
+        assertEquals(3, bounds[2]);
+    }
+
+    /** Tests configuration of hitrate metric. */
+    @Test
+    public void testConfigureHitrate() {
+        String mregName = "configure-registry";
+
+        MetricRegistry mreg = ignite0.context().metric().registry(mregName);
+
+        HitRateMetric hitrate = mreg.hitRateMetric("hitrate", null, 500, 5);
+
+        assertEquals(500, hitrate.rateTimeInterval());
+
+        executeCommand(EXIT_CODE_OK, CMD_METRIC, CONFIGURE_HITRATE.argName(), hitrate.name(), "100");
+
+        assertEquals(100, hitrate.rateTimeInterval());
+    }
+
     /** */
     @Test
     public void testHistogramMetrics() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
index 17f1efe921f..7d7750c34a4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
@@ -213,7 +213,7 @@ public class DataRegionMetricsImpl implements DataRegionMetrics {
         MetricRegistry mreg = metricRegistry();
 
         allocRate = mreg.hitRateMetric("AllocationRate",
-            "Allocation rate (pages per second) averaged across rateTimeInternal.",
+            "Allocation rate (pages per second) averaged across rateTimeInterval.",
             60_000,
             5);
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java
index e20cd55de72..7cf1b8d5d62 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java
@@ -334,7 +334,9 @@ public class DistributedMetaStorageImpl extends GridProcessorAdapter
                 try {
                     List<MetastorageView> data = new ArrayList<>();
 
-                    iterate("", (key, val) -> data.add(new MetastorageView(key, IgniteUtils.toStringSafe(val))));
+                    iterate("", (key, val) -> data.add(new MetastorageView(key, val == null || !val.getClass().isArray()
+                        ? IgniteUtils.toStringSafe(val)
+                        : S.arrayToString(val))));
 
                     return data;
                 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/pool/PoolProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/pool/PoolProcessor.java
index 67ce29dcd65..c7985236c1a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/pool/PoolProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/pool/PoolProcessor.java
@@ -137,7 +137,7 @@ public class PoolProcessor extends GridProcessorAdapter {
     public static final String THREAD_POOLS = "threadPools";
 
     /** Histogram buckets for the task execution time metric (in milliseconds). */
-    public static final long[] TASK_EXEC_TIME_HISTOGRAM_BUCKETS = new long[] {100, 1000, 10000, 30000, 60000};
+    public static final long[] TASK_EXEC_TIME_HISTOGRAM_BUCKETS = new long[] {10, 50, 100, 500, 1000};
 
     /** Executor service. */
     @GridToStringExclude
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTask.java
index 63f4359f7a9..f633225ddc2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTask.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.visor.metric;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.processors.metric.GridMetricManager;
 import org.apache.ignite.internal.processors.task.GridInternal;
@@ -71,6 +72,22 @@ public class VisorMetricTask extends VisorOneNodeTask<VisorMetricTaskArg, Map<St
 
             GridMetricManager mmgr = ignite.context().metric();
 
+            try {
+                if (arg.bounds() != null) {
+                    mmgr.configureHistogram(arg.name(), arg.bounds());
+
+                    return null;
+                }
+                else if (arg.rateTimeInterval() > 0) {
+                    mmgr.configureHitRate(arg.name(), arg.rateTimeInterval());
+
+                    return null;
+                }
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+
             for (ReadOnlyMetricRegistry mreg : mmgr) {
                 String mregName = mreg.name();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTaskArg.java
index afc81811fc1..75edccc2e75 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTaskArg.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/metric/VisorMetricTaskArg.java
@@ -32,14 +32,30 @@ public class VisorMetricTaskArg extends IgniteDataTransferObject {
     /** Name of a particular metric or metric registry. */
     private String name;
 
+    /**
+     * New bounds of histogram metric.
+     * @see org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl#bounds(long[])
+     * @see org.apache.ignite.mxbean.MetricsMxBean#configureHistogramMetric(String, long[])
+     */
+    private long[] bounds;
+
+    /**
+     * New rate time internal of hirtate metric.
+     * @see org.apache.ignite.internal.processors.metric.impl.HitRateMetric#reset(long)
+     * @see org.apache.ignite.mxbean.MetricsMxBean#configureHitRateMetric(String, long)
+     */
+    private long rateTimeInterval;
+
     /** Default constructor. */
     public VisorMetricTaskArg() {
         // No-op.
     }
 
     /** @param name Name of a particular metric or metric registry. */
-    public VisorMetricTaskArg(String name) {
+    public VisorMetricTaskArg(String name, long[] bounds, long rateTimeInterval) {
         this.name = name;
+        this.bounds = bounds;
+        this.rateTimeInterval = rateTimeInterval;
     }
 
     /** @return Name of a particular metric or metric registry. */
@@ -47,14 +63,28 @@ public class VisorMetricTaskArg extends IgniteDataTransferObject {
         return name;
     }
 
+    /** @return New bounds of histgoram metric. */
+    public long[] bounds() {
+        return bounds;
+    }
+
+    /** @return New rate time internal. */
+    public long rateTimeInterval() {
+        return rateTimeInterval;
+    }
+
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
         U.writeString(out, name);
+        U.writeLongArray(out, bounds);
+        out.writeLong(rateTimeInterval);
     }
 
     /** {@inheritDoc} */
     @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
         name = U.readString(in);
+        bounds = U.readLongArray(in);
+        rateTimeInterval = in.readLong();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
index b68fa39369c..8ba9ea29283 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
@@ -1978,21 +1978,29 @@ public class SystemViewSelfTest extends GridCommonAbstractTest {
             )))) {
             ignite.cluster().state(ClusterState.ACTIVE);
 
-            DistributedMetaStorage dms = ignite.context().distributedMetastorage();
+            String histogramName = "my-histogram";
 
-            SystemView<MetastorageView> metaStoreView = ignite.context().systemView().view(DISTRIBUTED_METASTORE_VIEW);
+            ignite.context().metric().configureHistogram(histogramName, new long[] { 1, 2, 3});
 
-            assertNotNull(metaStoreView);
+            DistributedMetaStorage dms = ignite.context().distributedMetastorage();
 
             String name = "test-distributed-key";
             String val = "test-distributed-value";
 
             dms.write(name, val);
 
-            MetastorageView testKey = F.find(metaStoreView, null,
-                (IgnitePredicate<? super MetastorageView>)view -> name.equals(view.name()) && val.equals(view.value()));
-
-            assertNotNull(testKey);
+            assertNotNull(F.find(
+                ignite.context().systemView().view(DISTRIBUTED_METASTORE_VIEW),
+                null,
+                (IgnitePredicate<? super MetastorageView>)view -> name.equals(view.name()) && val.equals(view.value()))
+            );
+
+            assertNotNull(F.find(
+                ignite.context().systemView().view(DISTRIBUTED_METASTORE_VIEW),
+                null,
+                (IgnitePredicate<? super MetastorageView>)
+                    view -> view.name().endsWith(histogramName) && "[1, 2, 3]".equals(view.value()))
+            );
         }
     }
 
diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
index 52882c92e8f..08f1081d34c 100644
--- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
+++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
@@ -274,6 +274,14 @@ If the file name isn't specified the output file name is: '<typeId>.bin'
       name     - Name of the metric which value should be printed. If name of the metric registry is specified, value of all its metrics will be printed.
       node_id  - ID of the node to get the metric values from. If not set, random node will be chosen.
 
+  Configure metric:
+    control.(sh|bat) --metric (--configure-histogram name newBounds)|(--configure-hitrate name newRateTimeInterval)
+
+    Parameters:
+      name                 - Name of the metric which value should be configured.
+      newBounds            - Comma-separated list of longs to configure histogram.
+      newRateTimeInterval  - Rate time interval of hitrate.
+
   Print information about potentially corrupted caches on local node:
     control.(sh|bat) --persistence
 
diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
index 52882c92e8f..08f1081d34c 100644
--- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
+++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
@@ -274,6 +274,14 @@ If the file name isn't specified the output file name is: '<typeId>.bin'
       name     - Name of the metric which value should be printed. If name of the metric registry is specified, value of all its metrics will be printed.
       node_id  - ID of the node to get the metric values from. If not set, random node will be chosen.
 
+  Configure metric:
+    control.(sh|bat) --metric (--configure-histogram name newBounds)|(--configure-hitrate name newRateTimeInterval)
+
+    Parameters:
+      name                 - Name of the metric which value should be configured.
+      newBounds            - Comma-separated list of longs to configure histogram.
+      newRateTimeInterval  - Rate time interval of hitrate.
+
   Print information about potentially corrupted caches on local node:
     control.(sh|bat) --persistence