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

anovikov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 51df7cc1e2 IGNITE-17443 Implement OpenTelemetry metric exporter. 
(#4531)
51df7cc1e2 is described below

commit 51df7cc1e276d8f64c5518b3539c748dc9ca4f27
Author: Andrey Novikov <[email protected]>
AuthorDate: Tue Nov 19 18:11:17 2024 +0700

    IGNITE-17443 Implement OpenTelemetry metric exporter. (#4531)
---
 gradle/libs.versions.toml                          |   3 +
 modules/metrics-exporter-otlp/build.gradle         |  51 +++++
 .../configuration/HeadersConfigurationSchema.java} |  21 +-
 .../OtlpExporterConfigurationModule.java           |  50 +++++
 .../OtlpExporterConfigurationSchema.java           |  65 ++++++
 .../otlp/IgniteDistributionMetricData.java         | 150 +++++++++++++
 .../exporters/otlp/IgniteDoubleMetricData.java     |  71 ++++++
 .../metrics/exporters/otlp/IgniteGaugeData.java}   |  29 ++-
 .../exporters/otlp/IgniteIntMetricData.java        |  71 ++++++
 .../exporters/otlp/IgniteLongMetricData.java       |  71 ++++++
 .../metrics/exporters/otlp/IgniteMetricData.java   |  68 ++++++
 .../metrics/exporters/otlp/IgnitePointData.java}   |  29 ++-
 .../metrics/exporters/otlp/MetricReporter.java     | 244 +++++++++++++++++++++
 .../exporters/otlp/OtlpPushMetricExporter.java     | 116 ++++++++++
 .../exporters/validator/EndpointValidator.java}    |  19 +-
 .../exporters/validator/EndpointValidatorImpl.java |  52 +++++
 .../exporters/otlp/OtlpPushMetricExporterTest.java | 159 ++++++++++++++
 .../validator/EndpointValidatorImplTest.java       | 103 +++++++++
 .../metrics/exporters/ItJvmMetricSourceTest.java   |   3 +-
 .../exporters/ItMetricExportersLoadingTest.java    |   3 +-
 .../metrics/exporters/ItOsMetricSourceTest.java    |   3 +-
 .../metrics/exporters/TestDoubleStartExporter.java |   7 +-
 .../metrics/exporters/TestPullMetricExporter.java  |   6 +-
 .../metrics/exporters/TestPushMetricExporter.java  |   7 +-
 .../ignite/internal/metrics/MetricManager.java     |   6 +-
 .../ignite/internal/metrics/MetricManagerImpl.java |  16 +-
 .../metrics/exporters/BasicMetricExporter.java     |  24 +-
 .../internal/metrics/exporters/MetricExporter.java |  14 +-
 .../metrics/exporters/PushMetricExporter.java      |   7 +-
 .../LogPushExporterConfigurationSchema.java        |   3 +-
 .../metrics/exporters/jmx/JmxExporter.java         |   7 +-
 .../metrics/exporters/log/LogPushExporter.java     |   7 +-
 .../internal/metrics/MetricConfigurationTest.java  |   3 +-
 .../internal/metrics/exporters/TestExporter.java   |   6 +-
 .../{ => exporters/jmx}/JmxExporterTest.java       |  28 ++-
 .../ignite/internal/metrics/NoOpMetricManager.java |   4 +-
 modules/runner/build.gradle                        |   1 +
 .../org/apache/ignite/internal/app/IgniteImpl.java |   7 +-
 settings.gradle                                    |   2 +
 39 files changed, 1466 insertions(+), 70 deletions(-)

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 53da19f915..aa70f02dbf 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -83,6 +83,7 @@ tree-sitter = "0.24.3"
 tree-sitter-json = "0.23.0"
 tree-sitter-sql = "gh-pages-a"
 tree-sitter-hocon = "master-a"
+otel = "1.42.1"
 
 #Tools
 pmdTool = "6.55.0"
@@ -267,3 +268,5 @@ tree-sitter = { module = "io.github.bonede:tree-sitter", 
version.ref = "tree-sit
 tree-sitter-json = { module = "io.github.bonede:tree-sitter-json", version.ref 
= "tree-sitter-json" }
 tree-sitter-sql = { module = "io.github.bonede:tree-sitter-sql", version.ref = 
"tree-sitter-sql" }
 tree-sitter-hocon = { module = "io.github.bonede:tree-sitter-hocon", 
version.ref = "tree-sitter-hocon" }
+
+opentelemetry-exporter-otlp = { module = 
"io.opentelemetry:opentelemetry-exporter-otlp", version.ref = "otel" }
diff --git a/modules/metrics-exporter-otlp/build.gradle 
b/modules/metrics-exporter-otlp/build.gradle
new file mode 100644
index 0000000000..29742e21d0
--- /dev/null
+++ b/modules/metrics-exporter-otlp/build.gradle
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+apply from: "$rootDir/buildscripts/java-core.gradle"
+apply from: "$rootDir/buildscripts/publishing.gradle"
+apply from: "$rootDir/buildscripts/java-junit5.gradle"
+
+dependencies {
+    annotationProcessor project(':ignite-configuration-annotation-processor')
+    annotationProcessor libs.auto.service
+
+    implementation project(':ignite-api')
+    implementation project(':ignite-core')
+    implementation project(':ignite-configuration')
+    implementation project(':ignite-configuration-root')
+    implementation project(':ignite-network')
+    implementation project(':ignite-metrics')
+    implementation libs.jetbrains.annotations
+    implementation libs.auto.service.annotations
+    implementation(libs.opentelemetry.exporter.otlp) {
+        // Exclude transitive dependency for exporting logs and traces.
+        exclude group: 'io.opentelemetry', module: 'opentelemetry-sdk-logs'
+        exclude group: 'io.opentelemetry', module: 'opentelemetry-sdk-trace'
+    }
+
+    testAnnotationProcessor 
project(':ignite-configuration-annotation-processor')
+
+    testImplementation project(':ignite-configuration')
+    testImplementation testFixtures(project(':ignite-core'))
+    testImplementation testFixtures(project(':ignite-configuration'))
+    testImplementation libs.hamcrest.core
+    testImplementation libs.mockito.core
+    testImplementation libs.mockito.junit
+    testImplementation libs.awaitility
+}
+
+description = 'ignite-metrics-exporter-otlp'
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/HeadersConfigurationSchema.java
similarity index 68%
copy from 
modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
copy to 
modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/HeadersConfigurationSchema.java
index 6e0b63046a..2d369c5f63 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/HeadersConfigurationSchema.java
@@ -17,15 +17,22 @@
 
 package org.apache.ignite.internal.metrics.exporters.configuration;
 
-import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.InjectedName;
 import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.internal.metrics.exporters.log.LogPushExporter;
+import org.apache.ignite.configuration.validation.NotBlank;
 
 /**
- * Configuration for log push exporter.
+ * Connection headers configuration schema.
  */
-@PolymorphicConfigInstance(LogPushExporter.EXPORTER_NAME)
-public class LogPushExporterConfigurationSchema extends 
ExporterConfigurationSchema {
-    @Value(hasDefault = true)
-    public int period = 30_000;
+@Config
+public class HeadersConfigurationSchema {
+    /** Name of the header. */
+    @InjectedName
+    public String name;
+
+    /** Header value. */
+    @NotBlank
+    @Value
+    public String header;
 }
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/OtlpExporterConfigurationModule.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/OtlpExporterConfigurationModule.java
new file mode 100644
index 0000000000..27eb722084
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/OtlpExporterConfigurationModule.java
@@ -0,0 +1,50 @@
+/*
+ * 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.metrics.exporters.configuration;
+
+import com.google.auto.service.AutoService;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import org.apache.ignite.configuration.ConfigurationModule;
+import org.apache.ignite.configuration.annotation.ConfigurationType;
+import org.apache.ignite.configuration.validation.Validator;
+import 
org.apache.ignite.internal.metrics.exporters.validator.EndpointValidatorImpl;
+
+/**
+ * {@link ConfigurationModule} for cluster-wide configuration provided by 
metrics-exporter-otlp.
+ */
+@AutoService(ConfigurationModule.class)
+public class OtlpExporterConfigurationModule implements ConfigurationModule {
+    @Override
+    public ConfigurationType type() {
+        return ConfigurationType.DISTRIBUTED;
+    }
+
+    @Override
+    public Set<Validator<?, ?>> validators() {
+        return Set.of(EndpointValidatorImpl.INSTANCE);
+    }
+
+    @Override
+    public Collection<Class<?>> polymorphicSchemaExtensions() {
+        return List.of(
+                OtlpExporterConfigurationSchema.class
+        );
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/OtlpExporterConfigurationSchema.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/OtlpExporterConfigurationSchema.java
new file mode 100644
index 0000000000..8b764c7a26
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/OtlpExporterConfigurationSchema.java
@@ -0,0 +1,65 @@
+/*
+ * 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.metrics.exporters.configuration;
+
+import static 
io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_GRPC;
+import static 
io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
+
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.validation.OneOf;
+import 
org.apache.ignite.internal.metrics.exporters.otlp.OtlpPushMetricExporter;
+import 
org.apache.ignite.internal.metrics.exporters.validator.EndpointValidator;
+import org.apache.ignite.internal.network.configuration.SslConfigurationSchema;
+import 
org.apache.ignite.internal.network.configuration.SslConfigurationValidator;
+
+/**
+ * Configuration for OTLP push exporter.
+ */
+@PolymorphicConfigInstance(OtlpPushMetricExporter.EXPORTER_NAME)
+public class OtlpExporterConfigurationSchema extends 
ExporterConfigurationSchema {
+    /** Export period, in milliseconds. */
+    @Value(hasDefault = true)
+    public long period = 30_000;
+
+    /** String in "host:port" format. */
+    @Value
+    @EndpointValidator
+    public String endpoint;
+
+    /** OTLP protocol. */
+    @OneOf({PROTOCOL_GRPC, PROTOCOL_HTTP_PROTOBUF})
+    @Value(hasDefault = true)
+    public String protocol = PROTOCOL_GRPC;
+
+    /** Connection headers configuration schema. */
+    @NamedConfigValue
+    public HeadersConfigurationSchema headers;
+
+    /** SSL configuration schema. */
+    @ConfigValue
+    @SslConfigurationValidator
+    public SslConfigurationSchema ssl;
+
+    /** Method used to compress payloads. */
+    @OneOf({"none", "gzip"})
+    @Value(hasDefault = true)
+    public String compression = "gzip";
+}
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteDistributionMetricData.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteDistributionMetricData.java
new file mode 100644
index 0000000000..e23c230742
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteDistributionMetricData.java
@@ -0,0 +1,150 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import static io.opentelemetry.sdk.metrics.data.MetricDataType.HISTOGRAM;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.internal.PrimitiveLongList;
+import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
+import io.opentelemetry.sdk.metrics.data.Data;
+import io.opentelemetry.sdk.metrics.data.DoubleExemplarData;
+import io.opentelemetry.sdk.metrics.data.HistogramData;
+import io.opentelemetry.sdk.metrics.data.HistogramPointData;
+import io.opentelemetry.sdk.metrics.data.MetricDataType;
+import io.opentelemetry.sdk.resources.Resource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.ignite.internal.metrics.DistributionMetric;
+
+/**
+ * Metric data that holds distribution metric.
+ */
+class IgniteDistributionMetricData extends 
IgniteMetricData<DistributionMetric> {
+    private final HistogramData data;
+
+    IgniteDistributionMetricData(Resource resource, InstrumentationScopeInfo 
scope, DistributionMetric metric) {
+        super(resource, scope, metric);
+
+        data = new IgniteHistogramData(new 
IgniteDistributionPointData(metric));
+    }
+
+    @Override
+    public MetricDataType getType() {
+        return HISTOGRAM;
+    }
+
+    @Override
+    public Data<?> getData() {
+        return data;
+    }
+
+    static class IgniteHistogramData implements HistogramData {
+        private final Collection<HistogramPointData> points;
+
+        IgniteHistogramData(HistogramPointData data) {
+            points = singletonList(data);
+        }
+
+        @Override
+        public AggregationTemporality getAggregationTemporality() {
+            return AggregationTemporality.CUMULATIVE;
+        }
+
+        @Override
+        public Collection<HistogramPointData> getPoints() {
+            return points;
+        }
+    }
+
+    static class IgniteDistributionPointData extends IgnitePointData 
implements HistogramPointData {
+        private final DistributionMetric metric;
+
+        private final List<Double> boundaries;
+
+        IgniteDistributionPointData(DistributionMetric metric) {
+            this.metric = metric;
+
+            boundaries = asDoubleList(metric.bounds());
+        }
+
+        @Override
+        public double getSum() {
+            return Double.NaN;
+        }
+
+        @Override
+        public long getCount() {
+            long totalCount = 0;
+
+            for (long c : metric.value()) {
+                totalCount += c;
+            }
+
+            return totalCount;
+        }
+
+        @Override
+        public boolean hasMin() {
+            return false;
+        }
+
+        @Override
+        public double getMin() {
+            return Double.NaN;
+        }
+
+        @Override
+        public boolean hasMax() {
+            return false;
+        }
+
+        @Override
+        public double getMax() {
+            return Double.NaN;
+        }
+
+        @Override
+        public List<Double> getBoundaries() {
+            return boundaries;
+        }
+
+        @Override
+        public List<Long> getCounts() {
+            return PrimitiveLongList.wrap(metric.value());
+        }
+
+        @Override
+        public List<DoubleExemplarData> getExemplars() {
+            return emptyList();
+        }
+
+        private static List<Double> asDoubleList(long[] array) {
+            ArrayList<Double> result = new ArrayList<>(array.length);
+
+            for (long el : array) {
+                result.add((double) el);
+            }
+
+            return result;
+        }
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteDoubleMetricData.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteDoubleMetricData.java
new file mode 100644
index 0000000000..b318e661d3
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteDoubleMetricData.java
@@ -0,0 +1,71 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_GAUGE;
+import static java.util.Collections.emptyList;
+
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.metrics.data.Data;
+import io.opentelemetry.sdk.metrics.data.DoubleExemplarData;
+import io.opentelemetry.sdk.metrics.data.DoublePointData;
+import io.opentelemetry.sdk.metrics.data.MetricDataType;
+import io.opentelemetry.sdk.resources.Resource;
+import java.util.List;
+import org.apache.ignite.internal.metrics.DoubleMetric;
+
+/**
+ * Metric data that holds double metric.
+ */
+class IgniteDoubleMetricData extends IgniteMetricData<DoubleMetric> {
+    private final Data<IgniteDoublePointData> data;
+
+    IgniteDoubleMetricData(Resource resource, InstrumentationScopeInfo scope, 
DoubleMetric metric) {
+        super(resource, scope, metric);
+
+        data = new IgniteGaugeData<>(new IgniteDoublePointData(metric));
+    }
+
+    @Override
+    public MetricDataType getType() {
+        return DOUBLE_GAUGE;
+    }
+
+    @Override
+    public Data<?> getData() {
+        return data;
+    }
+
+    private static class IgniteDoublePointData extends IgnitePointData 
implements DoublePointData {
+        private final DoubleMetric metric;
+
+        IgniteDoublePointData(DoubleMetric metric) {
+            this.metric = metric;
+        }
+
+        @Override
+        public double getValue() {
+            return metric.value();
+        }
+
+        @Override
+        public List<DoubleExemplarData> getExemplars() {
+            return emptyList();
+        }
+    }
+}
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteGaugeData.java
similarity index 57%
copy from 
modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
copy to 
modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteGaugeData.java
index 6e0b63046a..c6847e15ee 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteGaugeData.java
@@ -15,17 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.metrics.exporters.configuration;
+package org.apache.ignite.internal.metrics.exporters.otlp;
 
-import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
-import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.internal.metrics.exporters.log.LogPushExporter;
+import static java.util.Collections.singletonList;
+
+import io.opentelemetry.sdk.metrics.data.GaugeData;
+import io.opentelemetry.sdk.metrics.data.PointData;
+import java.util.Collection;
 
 /**
- * Configuration for log push exporter.
+ * Wrapper over data point that returns it as a list.
+ *
+ * @param <T> Data point type.
  */
-@PolymorphicConfigInstance(LogPushExporter.EXPORTER_NAME)
-public class LogPushExporterConfigurationSchema extends 
ExporterConfigurationSchema {
-    @Value(hasDefault = true)
-    public int period = 30_000;
+class IgniteGaugeData<T extends PointData> implements GaugeData<T> {
+    private final Collection<T> points;
+
+    IgniteGaugeData(T data) {
+        points = singletonList(data);
+    }
+
+    @Override
+    public Collection<T> getPoints() {
+        return points;
+    }
 }
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteIntMetricData.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteIntMetricData.java
new file mode 100644
index 0000000000..ca0ad1a7a6
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteIntMetricData.java
@@ -0,0 +1,71 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_GAUGE;
+import static java.util.Collections.emptyList;
+
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.metrics.data.Data;
+import io.opentelemetry.sdk.metrics.data.LongExemplarData;
+import io.opentelemetry.sdk.metrics.data.LongPointData;
+import io.opentelemetry.sdk.metrics.data.MetricDataType;
+import io.opentelemetry.sdk.resources.Resource;
+import java.util.List;
+import org.apache.ignite.internal.metrics.IntMetric;
+
+/**
+ * Metric data that holds int metric.
+ */
+class IgniteIntMetricData extends IgniteMetricData<IntMetric> {
+    private final Data<IgniteIntPointData> data;
+
+    IgniteIntMetricData(Resource resource, InstrumentationScopeInfo scope, 
IntMetric metric) {
+        super(resource, scope, metric);
+
+        this.data = new IgniteGaugeData<>(new IgniteIntPointData(metric));
+    }
+
+    @Override
+    public MetricDataType getType() {
+        return LONG_GAUGE;
+    }
+
+    @Override
+    public Data<?> getData() {
+        return data;
+    }
+
+    private static class IgniteIntPointData extends IgnitePointData implements 
LongPointData {
+        private final IntMetric metric;
+
+        IgniteIntPointData(IntMetric metric) {
+            this.metric = metric;
+        }
+
+        @Override
+        public long getValue() {
+            return metric.value();
+        }
+
+        @Override
+        public List<LongExemplarData> getExemplars() {
+            return emptyList();
+        }
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteLongMetricData.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteLongMetricData.java
new file mode 100644
index 0000000000..781d840e53
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteLongMetricData.java
@@ -0,0 +1,71 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_GAUGE;
+import static java.util.Collections.emptyList;
+
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.metrics.data.Data;
+import io.opentelemetry.sdk.metrics.data.LongExemplarData;
+import io.opentelemetry.sdk.metrics.data.LongPointData;
+import io.opentelemetry.sdk.metrics.data.MetricDataType;
+import io.opentelemetry.sdk.resources.Resource;
+import java.util.List;
+import org.apache.ignite.internal.metrics.LongMetric;
+
+/**
+ * Metric data that holds long metric.
+ */
+class IgniteLongMetricData extends IgniteMetricData<LongMetric> {
+    private final Data<IgniteLongPointData> data;
+
+    IgniteLongMetricData(Resource resource, InstrumentationScopeInfo scope, 
LongMetric metric) {
+        super(resource, scope, metric);
+
+        this.data = new IgniteGaugeData<>(new IgniteLongPointData(metric));
+    }
+
+    @Override
+    public MetricDataType getType() {
+        return LONG_GAUGE;
+    }
+
+    @Override
+    public Data<?> getData() {
+        return data;
+    }
+
+    private static class IgniteLongPointData extends IgnitePointData 
implements LongPointData {
+        private final LongMetric metric;
+
+        IgniteLongPointData(LongMetric metric) {
+            this.metric = metric;
+        }
+
+        @Override
+        public long getValue() {
+            return metric.value();
+        }
+
+        @Override
+        public List<LongExemplarData> getExemplars() {
+            return emptyList();
+        }
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteMetricData.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteMetricData.java
new file mode 100644
index 0000000000..ca7e360869
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgniteMetricData.java
@@ -0,0 +1,68 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.metrics.data.MetricData;
+import io.opentelemetry.sdk.resources.Resource;
+import java.util.Objects;
+import org.apache.ignite.internal.metrics.Metric;
+
+/**
+ * Metric data represents the aggregated measurements of an instrument.
+ *
+ * @param <T> A type of the metric.
+ */
+abstract class IgniteMetricData<T extends Metric> implements MetricData {
+    private final Resource resource;
+    private final InstrumentationScopeInfo scope;
+    private final T metric;
+
+    IgniteMetricData(Resource resource, InstrumentationScopeInfo scope, T 
metric) {
+        this.resource = resource;
+        this.scope = scope;
+        this.metric = metric;
+    }
+
+    @Override
+    public Resource getResource() {
+        return resource;
+    }
+
+    @Override
+    public InstrumentationScopeInfo getInstrumentationScopeInfo() {
+        return scope;
+    }
+
+    @Override
+    public String getName() {
+        return metric.name();
+    }
+
+    @Override
+    public String getDescription() {
+        // Can't be null.
+        return Objects.requireNonNull(metric.description(), "");
+    }
+
+    @Override
+    public String getUnit() {
+        // Can't be null.
+        return "";
+    }
+}
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgnitePointData.java
similarity index 57%
copy from 
modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
copy to 
modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgnitePointData.java
index 6e0b63046a..67ef395be8 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/IgnitePointData.java
@@ -15,17 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.metrics.exporters.configuration;
+package org.apache.ignite.internal.metrics.exporters.otlp;
 
-import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
-import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.internal.metrics.exporters.log.LogPushExporter;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.sdk.common.Clock;
+import io.opentelemetry.sdk.metrics.data.PointData;
 
 /**
- * Configuration for log push exporter.
+ * Base class for a point in the metric data model.
  */
-@PolymorphicConfigInstance(LogPushExporter.EXPORTER_NAME)
-public class LogPushExporterConfigurationSchema extends 
ExporterConfigurationSchema {
-    @Value(hasDefault = true)
-    public int period = 30_000;
+abstract class IgnitePointData implements PointData {
+    @Override
+    public long getStartEpochNanos() {
+        return Clock.getDefault().now();
+    }
+
+    @Override
+    public long getEpochNanos() {
+        return Clock.getDefault().now();
+    }
+
+    @Override
+    public Attributes getAttributes() {
+        return Attributes.empty();
+    }
 }
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/MetricReporter.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/MetricReporter.java
new file mode 100644
index 0000000000..e20ac3468e
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/MetricReporter.java
@@ -0,0 +1,244 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import static 
io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_GRPC;
+import static 
io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
+import static io.opentelemetry.sdk.common.export.MemoryMode.REUSABLE_DATA;
+import static org.apache.ignite.internal.util.StringUtils.nullOrBlank;
+
+import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
+import 
io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
+import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
+import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.metrics.data.MetricData;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
+import io.opentelemetry.sdk.resources.Resource;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.NoSuchFileException;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import org.apache.ignite.configuration.NamedListView;
+import org.apache.ignite.internal.logger.IgniteLogger;
+import org.apache.ignite.internal.logger.Loggers;
+import org.apache.ignite.internal.metrics.DistributionMetric;
+import org.apache.ignite.internal.metrics.DoubleMetric;
+import org.apache.ignite.internal.metrics.IntMetric;
+import org.apache.ignite.internal.metrics.LongMetric;
+import org.apache.ignite.internal.metrics.Metric;
+import org.apache.ignite.internal.metrics.MetricSet;
+import org.apache.ignite.internal.metrics.exporters.configuration.HeadersView;
+import 
org.apache.ignite.internal.metrics.exporters.configuration.OtlpExporterView;
+import org.apache.ignite.internal.network.configuration.SslView;
+import org.apache.ignite.internal.network.ssl.KeystoreLoader;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+
+/**
+ * A reporter which outputs measurements to a {@link MetricExporter}.
+ */
+class MetricReporter implements AutoCloseable {
+    private static final IgniteLogger LOG = 
Loggers.forClass(MetricReporter.class);
+
+    private final Collection<MetricData> metrics = new 
CopyOnWriteArrayList<>();
+    private final Resource resource;
+
+    private MetricExporter exporter;
+
+    MetricReporter(OtlpExporterView view, String clusterId, String nodeName) {
+        this.exporter = createExporter(view);
+
+        this.resource = Resource.builder()
+                .put("service.name", clusterId)
+                .put("service.instance.id", nodeName)
+                .build();
+    }
+
+    void addMetricSet(MetricSet metricSet) {
+        Collection<MetricData> metrics0 = new ArrayList<>();
+
+        InstrumentationScopeInfo scope = 
InstrumentationScopeInfo.builder(metricSet.name())
+                .build();
+
+        for (Metric metric : metricSet) {
+            MetricData metricData = toMetricData(resource, scope, metric);
+
+            if (metricData != null) {
+                metrics0.add(metricData);
+            }
+        }
+
+        metrics.addAll(metrics0);
+    }
+
+    void removeMetricSet(String metricSetName) {
+        metrics.removeIf(metricData -> 
metricSetName.equals(metricData.getName()));
+    }
+
+    void report() {
+        exporter.export(metrics);
+    }
+
+    @Override
+    public void close() throws Exception {
+        exporter.close();
+    }
+
+    @TestOnly
+    void exporter(MetricExporter exporter) {
+        this.exporter = exporter;
+    }
+
+
+    private static Supplier<Map<String, String>> headers(NamedListView<? 
extends HeadersView> headers) {
+        return () -> 
headers.stream().collect(Collectors.toUnmodifiableMap(HeadersView::name, 
HeadersView::header));
+    }
+
+    /** Create client SSL context. */
+    private static TrustManagerFactory createTrustManagerFactory(SslView ssl) {
+        try {
+            TrustManagerFactory trustManagerFactory = 
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            trustManagerFactory.init(KeystoreLoader.load(ssl.trustStore()));
+
+            return trustManagerFactory;
+        } catch (IOException | GeneralSecurityException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, e);
+        }
+    }
+
+    /** Create client SSL context. */
+    private static SSLContext createClientSslContext(SslView ssl, 
TrustManagerFactory trustManagerFactory) {
+        try {
+            KeyManagerFactory keyManagerFactory = 
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+            keyManagerFactory.init(KeystoreLoader.load(ssl.keyStore()), 
ssl.keyStore().password().toCharArray());
+
+            SSLContext sslContext = SSLContext.getInstance("TLS");
+            sslContext.init(keyManagerFactory.getKeyManagers(), 
trustManagerFactory.getTrustManagers(), new SecureRandom());
+
+            return sslContext;
+        } catch (NoSuchFileException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, 
String.format("File %s not found", e.getMessage()), e);
+        } catch (IOException | GeneralSecurityException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, e);
+        }
+    }
+
+    private static String createEndpoint(OtlpExporterView view) {
+        URI uri = URI.create(view.endpoint());
+        StringBuilder sb = new StringBuilder();
+
+        if (view.protocol().equals(PROTOCOL_HTTP_PROTOBUF)) {
+            String basePath = uri.getPath();
+
+            if (!nullOrBlank(basePath)) {
+                sb.append(basePath);
+            }
+
+            if (!basePath.endsWith("v1/metrics")) {
+                if (!basePath.endsWith("/")) {
+                    sb.append('/');
+                }
+
+                sb.append("v1/metrics");
+            }
+        } else {
+            sb.append('/');
+        }
+
+        try {
+            return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), 
uri.getPort(), sb.toString(), null, null).toString();
+        } catch (URISyntaxException e) {
+            throw new RuntimeException("Unexpected exception creating URL.", 
e);
+        }
+    }
+
+    private static MetricExporter createExporter(OtlpExporterView view) {
+        if (view.protocol().equals(PROTOCOL_GRPC)) {
+            OtlpGrpcMetricExporterBuilder builder = 
OtlpGrpcMetricExporter.builder()
+                    .setEndpoint(createEndpoint(view))
+                    .setHeaders(headers(view.headers()))
+                    .setCompression(view.compression())
+                    .setMemoryMode(REUSABLE_DATA);
+
+            SslView sslView = view.ssl();
+
+            if (sslView.enabled()) {
+                TrustManagerFactory trustManagerFactory = 
createTrustManagerFactory(sslView);
+                X509TrustManager trustManager = (X509TrustManager) 
trustManagerFactory.getTrustManagers()[0];
+
+                builder.setSslContext(createClientSslContext(sslView, 
trustManagerFactory), trustManager);
+            }
+
+            return builder.build();
+        }
+
+        OtlpHttpMetricExporterBuilder builder = 
OtlpHttpMetricExporter.builder()
+                .setEndpoint(createEndpoint(view))
+                .setHeaders(headers(view.headers()))
+                .setCompression(view.compression())
+                .setMemoryMode(REUSABLE_DATA);
+
+        SslView sslView = view.ssl();
+
+        if (sslView.enabled()) {
+            TrustManagerFactory trustManagerFactory = 
createTrustManagerFactory(sslView);
+            X509TrustManager trustManager = (X509TrustManager) 
trustManagerFactory.getTrustManagers()[0];
+
+            builder.setSslContext(createClientSslContext(sslView, 
trustManagerFactory), trustManager);
+        }
+
+        return builder.build();
+    }
+
+    private static @Nullable MetricData toMetricData(Resource resource, 
InstrumentationScopeInfo scope, Metric metric) {
+        if (metric instanceof IntMetric) {
+            return new IgniteIntMetricData(resource, scope, (IntMetric) 
metric);
+        }
+
+        if (metric instanceof LongMetric) {
+            return new IgniteLongMetricData(resource, scope, (LongMetric) 
metric);
+        }
+
+        if (metric instanceof DoubleMetric) {
+            return new IgniteDoubleMetricData(resource, scope, (DoubleMetric) 
metric);
+        }
+
+        if (metric instanceof DistributionMetric) {
+            return new IgniteDistributionMetricData(resource, scope, 
(DistributionMetric) metric);
+        }
+
+        LOG.debug("Unknown metric class for export " + metric.getClass());
+
+        return null;
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/OtlpPushMetricExporter.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/OtlpPushMetricExporter.java
new file mode 100644
index 0000000000..16927cc600
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/otlp/OtlpPushMetricExporter.java
@@ -0,0 +1,116 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import com.google.auto.service.AutoService;
+import java.util.UUID;
+import java.util.function.Supplier;
+import org.apache.ignite.internal.metrics.MetricProvider;
+import org.apache.ignite.internal.metrics.MetricSet;
+import org.apache.ignite.internal.metrics.exporters.MetricExporter;
+import org.apache.ignite.internal.metrics.exporters.PushMetricExporter;
+import 
org.apache.ignite.internal.metrics.exporters.configuration.OtlpExporterView;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+
+/**
+ * Otlp(OpenTelemetry) metrics exporter.
+ */
+@AutoService(MetricExporter.class)
+public class OtlpPushMetricExporter extends 
PushMetricExporter<OtlpExporterView> {
+    public static final String EXPORTER_NAME = "otlp";
+
+    private volatile @Nullable MetricReporter reporter;
+
+    @Override
+    public synchronized void start(MetricProvider metricsProvider, 
OtlpExporterView view, Supplier<UUID> clusterIdSupplier,
+            String nodeName) {
+        MetricReporter reporter0 = new MetricReporter(view, 
clusterIdSupplier.get().toString(), nodeName);
+
+        for (MetricSet metricSet : 
metricsProvider.metrics().getKey().values()) {
+            reporter0.addMetricSet(metricSet);
+        }
+
+        reporter = reporter0;
+
+        super.start(metricsProvider, view, clusterIdSupplier, nodeName);
+    }
+
+    @Override
+    public synchronized void stop() {
+        super.stop();
+
+        try {
+            IgniteUtils.closeAll(reporter);
+        } catch (Exception e) {
+            log.error("Failed to stop metric exporter: " + name(), e);
+        }
+
+        reporter = null;
+    }
+
+    @Override
+    public synchronized void reconfigure(OtlpExporterView newVal) {
+        super.reconfigure(newVal);
+
+        reporter = new MetricReporter(newVal, clusterId().toString(), 
nodeName());
+    }
+
+    @Override
+    public void addMetricSet(MetricSet metricSet) {
+        MetricReporter reporter0 = reporter;
+
+        assert reporter0 != null;
+
+        reporter0.addMetricSet(metricSet);
+    }
+
+    @Override
+    public void removeMetricSet(String metricSetName) {
+        MetricReporter reporter0 = reporter;
+
+        assert reporter0 != null;
+
+        reporter0.removeMetricSet(metricSetName);
+    }
+
+    @Override
+    protected long period() {
+        return configuration().period();
+    }
+
+    @Override
+    public void report() {
+        MetricReporter reporter0 = reporter;
+
+        assert reporter0 != null;
+
+        reporter0.report();
+    }
+
+    @Override
+    public String name() {
+        return EXPORTER_NAME;
+    }
+
+    @TestOnly
+    @Nullable MetricReporter reporter() {
+        return reporter;
+    }
+}
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidator.java
similarity index 60%
copy from 
modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
copy to 
modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidator.java
index 6e0b63046a..eab1aa7c1b 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidator.java
@@ -15,17 +15,18 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.metrics.exporters.configuration;
+package org.apache.ignite.internal.metrics.exporters.validator;
 
-import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
-import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.internal.metrics.exporters.log.LogPushExporter;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
 
 /**
- * Configuration for log push exporter.
+ * Annotation to validate endpoint.
  */
-@PolymorphicConfigInstance(LogPushExporter.EXPORTER_NAME)
-public class LogPushExporterConfigurationSchema extends 
ExporterConfigurationSchema {
-    @Value(hasDefault = true)
-    public int period = 30_000;
+@Target(FIELD)
+@Retention(RUNTIME)
+public @interface EndpointValidator {
 }
diff --git 
a/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidatorImpl.java
 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidatorImpl.java
new file mode 100644
index 0000000000..dc2b1f567a
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/main/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidatorImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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.metrics.exporters.validator;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.apache.ignite.configuration.validation.ValidationContext;
+import org.apache.ignite.configuration.validation.ValidationIssue;
+import org.apache.ignite.configuration.validation.Validator;
+
+/** Implementation of the {@link EndpointValidator}. */
+public class EndpointValidatorImpl implements Validator<EndpointValidator, 
String> {
+    public static final EndpointValidatorImpl INSTANCE = new 
EndpointValidatorImpl();
+
+    @Override
+    public void validate(EndpointValidator annotation, 
ValidationContext<String> ctx) {
+        String endpoint = ctx.getNewValue();
+
+        try {
+            URL endpointUrl = new URL(endpoint);
+
+            if (!"http".equalsIgnoreCase(endpointUrl.getProtocol()) && 
!"https".equalsIgnoreCase(endpointUrl.getProtocol())) {
+                ctx.addIssue(new ValidationIssue(ctx.currentKey(), "Endpoint 
scheme must be http or https: " + endpointUrl.getProtocol()));
+            }
+
+            if (endpointUrl.getQuery() != null) {
+                ctx.addIssue(new ValidationIssue(ctx.currentKey(), "Endpoint 
must not have a query string: " + endpointUrl.getQuery()));
+            }
+
+            if (endpointUrl.getRef() != null) {
+                ctx.addIssue(new ValidationIssue(ctx.currentKey(), "Endpoint 
must not have a fragment: " + endpointUrl.getRef()));
+            }
+        } catch (MalformedURLException e) {
+            ctx.addIssue(new ValidationIssue(ctx.currentKey(), "Endpoint must 
be a valid URL: " + endpoint));
+        }
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/test/java/org/apache/ignite/internal/metrics/exporters/otlp/OtlpPushMetricExporterTest.java
 
b/modules/metrics-exporter-otlp/src/test/java/org/apache/ignite/internal/metrics/exporters/otlp/OtlpPushMetricExporterTest.java
new file mode 100644
index 0000000000..3d6db8672d
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/test/java/org/apache/ignite/internal/metrics/exporters/otlp/OtlpPushMetricExporterTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.metrics.exporters.otlp;
+
+import static io.opentelemetry.api.common.AttributeType.STRING;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.opentelemetry.api.internal.InternalAttributeKeyImpl;
+import io.opentelemetry.sdk.common.CompletableResultCode;
+import io.opentelemetry.sdk.metrics.data.HistogramPointData;
+import io.opentelemetry.sdk.metrics.data.MetricData;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
+import io.opentelemetry.sdk.resources.Resource;
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
+import org.apache.ignite.internal.lang.IgniteBiTuple;
+import org.apache.ignite.internal.metrics.AtomicDoubleMetric;
+import org.apache.ignite.internal.metrics.AtomicIntMetric;
+import org.apache.ignite.internal.metrics.AtomicLongMetric;
+import org.apache.ignite.internal.metrics.DistributionMetric;
+import org.apache.ignite.internal.metrics.DoubleAdderMetric;
+import org.apache.ignite.internal.metrics.DoubleGauge;
+import org.apache.ignite.internal.metrics.DoubleMetric;
+import org.apache.ignite.internal.metrics.HitRateMetric;
+import org.apache.ignite.internal.metrics.IntGauge;
+import org.apache.ignite.internal.metrics.IntMetric;
+import org.apache.ignite.internal.metrics.LongAdderMetric;
+import org.apache.ignite.internal.metrics.LongGauge;
+import org.apache.ignite.internal.metrics.LongMetric;
+import org.apache.ignite.internal.metrics.Metric;
+import org.apache.ignite.internal.metrics.MetricProvider;
+import org.apache.ignite.internal.metrics.MetricSet;
+import org.apache.ignite.internal.metrics.configuration.MetricConfiguration;
+import 
org.apache.ignite.internal.metrics.exporters.configuration.OtlpExporterView;
+import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
+import org.apache.ignite.internal.util.CollectionUtils;
+import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(ConfigurationExtension.class)
+@ExtendWith(MockitoExtension.class)
+class OtlpPushMetricExporterTest extends BaseIgniteAbstractTest {
+    @InjectConfiguration("mock.exporters = {otlp = {exporterName = otlp, 
period = 10000000, endpoint = \"http://localhost:4317\"}}";)
+    private MetricConfiguration metricConfiguration;
+
+    private static final UUID CLUSTER_ID = UUID.randomUUID();
+
+    private static final String SRC_NAME = "testSource";
+
+    /** Metric set with all available metric types. */
+    private static final MetricSet metricSet =
+            new MetricSet(
+                    SRC_NAME,
+                    Map.of(
+                            "intGauge", new IntGauge("intGauge", "", () -> 1),
+                            "longGauge", new LongGauge("longGauge", "", () -> 
1L),
+                            "doubleGauge", new DoubleGauge("doubleGauge", "", 
() -> 1d),
+                            "atomicInt", new AtomicIntMetric("atomicInt", ""),
+                            "atomicLong", new AtomicLongMetric("atomicLong", 
""),
+                            "atomicDouble", new 
AtomicDoubleMetric("atomicDouble", ""),
+                            "longAdder", new LongAdderMetric("longAdder", ""),
+                            "doubleAdder", new 
DoubleAdderMetric("doubleAdder", ""),
+                            "distributionMetric", new 
DistributionMetric("distributionMetric", "", new long[] {0, 1}),
+                            "hitRate", new HitRateMetric("hitRate", "", 
Long.MAX_VALUE)
+                    )
+            );
+
+    private MetricProvider metricsProvider;
+
+    private MetricExporter metricsExporter;
+
+    private OtlpPushMetricExporter exporter;
+
+    @Captor
+    private ArgumentCaptor<Collection<MetricData>> metricsCaptor;
+
+    @BeforeEach
+    void setUp() {
+        OtlpExporterView exporterConf = (OtlpExporterView) 
metricConfiguration.exporters().get("otlp").value();
+        metricsProvider = mock(MetricProvider.class);
+        Map<String, MetricSet> metrics = Map.of(metricSet.name(), metricSet);
+        when(metricsProvider.metrics()).thenReturn(new 
IgniteBiTuple<>(metrics, 1L));
+
+        exporter = new OtlpPushMetricExporter();
+        exporter.start(metricsProvider, exporterConf, () -> CLUSTER_ID, 
"nodeName");
+
+        metricsExporter = mock(MetricExporter.class);
+        exporter.reporter().exporter(metricsExporter);
+    }
+
+    @Test
+    public void testExport() {
+        
when(metricsExporter.export(metricsCaptor.capture())).thenReturn(CompletableResultCode.ofSuccess());
+        exporter.report();
+
+        
assertThatExportedMetricsAndMetricValuesAreTheSame(metricsCaptor.getValue());
+    }
+
+    /**
+     * Check, that all exported has the same values as original metric values.
+     */
+    private static void 
assertThatExportedMetricsAndMetricValuesAreTheSame(Collection<MetricData> 
metrics) {
+        for (Metric metric : metricSet) {
+            MetricData otlpMetric = metrics.stream().filter(m -> 
m.getName().equals(metric.name())).findFirst()
+                    .orElseThrow(() -> new IllegalArgumentException("Failed to 
find metric with name " + metric.name()));
+
+            Resource res = otlpMetric.getResource();
+
+            assertEquals(CLUSTER_ID.toString(), 
res.getAttribute(InternalAttributeKeyImpl.create("service.name", STRING)));
+            assertEquals("nodeName", 
res.getAttribute(InternalAttributeKeyImpl.create("service.instance.id", 
STRING)));
+
+            if (metric instanceof IntMetric) {
+                assertEquals(((IntMetric) metric).value(), 
CollectionUtils.first(otlpMetric.getLongGaugeData().getPoints()).getValue());
+            } else if (metric instanceof LongMetric) {
+                assertEquals(((LongMetric) metric).value(), 
CollectionUtils.first(otlpMetric.getLongGaugeData().getPoints()).getValue());
+            } else if (metric instanceof DoubleMetric) {
+                assertEquals(((DoubleMetric) metric).value(),
+                        
CollectionUtils.first(otlpMetric.getDoubleGaugeData().getPoints()).getValue());
+            } else if (metric instanceof DistributionMetric) {
+                @Nullable HistogramPointData point = 
CollectionUtils.first(otlpMetric.getHistogramData().getPoints());
+
+                assertArrayEquals(
+                        ((DistributionMetric) metric).bounds(),
+                        
point.getBoundaries().stream().mapToLong(Double::longValue).toArray()
+                );
+                assertArrayEquals(
+                        ((DistributionMetric) metric).value(),
+                        
point.getCounts().stream().mapToLong(Long::longValue).toArray()
+                );
+            }
+        }
+    }
+}
diff --git 
a/modules/metrics-exporter-otlp/src/test/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidatorImplTest.java
 
b/modules/metrics-exporter-otlp/src/test/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidatorImplTest.java
new file mode 100644
index 0000000000..b949f8ef3a
--- /dev/null
+++ 
b/modules/metrics-exporter-otlp/src/test/java/org/apache/ignite/internal/metrics/exporters/validator/EndpointValidatorImplTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.metrics.exporters.validator;
+
+import static 
org.apache.ignite.internal.configuration.validation.TestValidationUtil.mockValidationContext;
+import static org.mockito.Mockito.mock;
+
+import org.apache.ignite.configuration.validation.ValidationContext;
+import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import org.apache.ignite.internal.configuration.validation.TestValidationUtil;
+import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/** Tests for {@link  EndpointValidatorImpl}. */
+@ExtendWith(ConfigurationExtension.class)
+class EndpointValidatorImplTest extends BaseIgniteAbstractTest {
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "http://127.0.0.1:8080";,
+            "http://127.0.0.1";,
+            "http://host";,
+            "http://host:8080";,
+            "http://www.host.com";,
+            "http://www.host.com:8080";
+    })
+    void validEndpointSuccess(String endpoint) {
+        validate(endpoint);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "127.0.0.1:8080",
+            "127.0.0.1",
+            "host/v1/metrics",
+            "www.host.com",
+    })
+    void invalidEndpointFails(String endpoint) {
+        validate(endpoint, "Endpoint must be a valid URL");
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "ftp://127.0.0.1:8080";,
+            "file://www.host.com"
+    })
+    void endpointWithUnexpectedSchemaFails(String endpoint) {
+        validate(endpoint, "Endpoint scheme must be http or https");
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "http://www.host.com/?s=1";,
+            "https://www.host.com/?s=1";
+    })
+    void endpointWithQueryStringFails(String endpoint) {
+        validate(endpoint, "Endpoint must not have a query string");
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "http://www.host.com/v1/metrics#print";,
+            "https://127.0.0.1:8080/#test";
+    })
+    void endpointWithFragmentFails(String endpoint) {
+        validate(endpoint, "Endpoint must not have a fragment");
+    }
+
+    private static void validate(String newValue) {
+        validate(newValue, (String[]) null);
+    }
+
+    private static void validate(String newValue, String @Nullable ... 
errorMessagePrefixes) {
+        ValidationContext<String> ctx = mockValidationContext(
+                null,
+                newValue
+        );
+
+        TestValidationUtil.validate(
+                EndpointValidatorImpl.INSTANCE,
+                mock(EndpointValidator.class),
+                ctx,
+                errorMessagePrefixes
+        );
+    }
+}
diff --git 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItJvmMetricSourceTest.java
 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItJvmMetricSourceTest.java
index 30f2d3ae50..9e55bde12d 100644
--- 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItJvmMetricSourceTest.java
+++ 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItJvmMetricSourceTest.java
@@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.UUID;
 import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
 import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.manager.ComponentContext;
@@ -54,7 +55,7 @@ public class ItJvmMetricSourceTest extends 
BaseIgniteAbstractTest {
     public void testMemoryUsageMetric() {
         MetricManager metricManager = new MetricManagerImpl();
 
-        metricManager.configure(simpleConfiguration);
+        metricManager.configure(simpleConfiguration, UUID::randomUUID, 
"test-node");
 
         Map<String, MetricExporter> exporters = new HashMap<>();
 
diff --git 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItMetricExportersLoadingTest.java
 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItMetricExportersLoadingTest.java
index c6986efcca..c3578a072d 100644
--- 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItMetricExportersLoadingTest.java
+++ 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItMetricExportersLoadingTest.java
@@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
+import java.util.UUID;
 import java.util.concurrent.locks.LockSupport;
 import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
 import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
@@ -56,7 +57,7 @@ public class ItMetricExportersLoadingTest extends 
BaseIgniteAbstractTest {
     public void test() throws Exception {
         MetricManager metricManager = new MetricManagerImpl();
 
-        metricManager.configure(metricConfiguration);
+        metricManager.configure(metricConfiguration, UUID::randomUUID, 
"test-node");
 
         TestMetricsSource src = new TestMetricsSource("TestMetricsSource");
 
diff --git 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItOsMetricSourceTest.java
 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItOsMetricSourceTest.java
index 3543a4697f..f2b6918e47 100644
--- 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItOsMetricSourceTest.java
+++ 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/ItOsMetricSourceTest.java
@@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.greaterThan;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.UUID;
 import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
 import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.manager.ComponentContext;
@@ -49,7 +50,7 @@ class ItOsMetricSourceTest extends BaseIgniteAbstractTest {
     @Test
     void testOsMetrics() {
         MetricManager metricManager = new MetricManagerImpl();
-        metricManager.configure(simpleConfiguration);
+        metricManager.configure(simpleConfiguration, UUID::randomUUID, 
"test-node");
 
         Map<String, MetricExporter> exporters = new HashMap<>();
         TestSimpleExporter simpleExporter = new TestSimpleExporter();
diff --git 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestDoubleStartExporter.java
 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestDoubleStartExporter.java
index a1c327c4d4..79edc4f4c6 100644
--- 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestDoubleStartExporter.java
+++ 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestDoubleStartExporter.java
@@ -21,7 +21,9 @@ import static java.util.Collections.emptyMap;
 
 import com.google.auto.service.AutoService;
 import java.util.Map;
+import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.metrics.MetricProvider;
 import org.apache.ignite.internal.metrics.MetricSet;
 
@@ -47,8 +49,9 @@ public class TestDoubleStartExporter extends 
BasicMetricExporter<TestDoubleStart
     }
 
     @Override
-    public void start(MetricProvider metricsProvider, 
TestDoubleStartExporterView configuration) {
-        super.start(metricsProvider, configuration);
+    public void start(MetricProvider metricsProvider, 
TestDoubleStartExporterView configuration, Supplier<UUID> clusterIdSupplier,
+            String nodeName) {
+        super.start(metricsProvider, configuration, clusterIdSupplier, 
nodeName);
 
         START_COUNTER.incrementAndGet();
     }
diff --git 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java
 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java
index 316cf1008f..7fde93997d 100644
--- 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java
+++ 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java
@@ -21,8 +21,10 @@ import com.google.auto.service.AutoService;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.UUID;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.metrics.Metric;
 import org.apache.ignite.internal.metrics.MetricProvider;
 import org.apache.ignite.internal.metrics.MetricSet;
@@ -55,8 +57,8 @@ public class TestPullMetricExporter extends 
BasicMetricExporter<TestPullMetricsE
     }
 
     @Override
-    public void start(MetricProvider metricProvider, 
TestPullMetricsExporterView conf) {
-        super.start(metricProvider, conf);
+    public void start(MetricProvider metricProvider, 
TestPullMetricsExporterView conf, Supplier<UUID> clusterIdSupplier, String 
nodeName) {
+        super.start(metricProvider, conf, clusterIdSupplier, nodeName);
 
         executorService.execute(() -> {
             while (true) {
diff --git 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.java
 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.java
index 9309544d75..dd81a4ced7 100644
--- 
a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.java
+++ 
b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.java
@@ -21,6 +21,8 @@ import com.google.auto.service.AutoService;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.metrics.Metric;
 import org.apache.ignite.internal.metrics.MetricProvider;
 import org.apache.ignite.internal.metrics.MetricSet;
@@ -37,10 +39,11 @@ public class TestPushMetricExporter extends 
PushMetricExporter<TestPushMetricsEx
     private long period;
 
     @Override
-    public void start(MetricProvider metricsProvider, 
TestPushMetricsExporterView configuration) {
+    public void start(MetricProvider metricsProvider, 
TestPushMetricsExporterView configuration, Supplier<UUID> clusterIdSupplier,
+            String nodeName) {
         period = configuration.period();
 
-        super.start(metricsProvider, configuration);
+        super.start(metricsProvider, configuration, clusterIdSupplier, 
nodeName);
     }
 
     public static void setOutputStream(OutputStream outputStream) {
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
index 07baf98ed7..337114a1ac 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
@@ -19,6 +19,8 @@ package org.apache.ignite.internal.metrics;
 
 import java.util.Collection;
 import java.util.Map;
+import java.util.UUID;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.lang.IgniteBiTuple;
 import org.apache.ignite.internal.manager.IgniteComponent;
 import org.apache.ignite.internal.metrics.configuration.MetricConfiguration;
@@ -33,10 +35,12 @@ public interface MetricManager extends IgniteComponent {
      * Method to configure {@link MetricManager} with distributed 
configuration.
      *
      * @param metricConfiguration Distributed metric configuration.
+     * @param clusterIdSupplier Cluster ID supplier.
+     * @param nodeName Node name.
      */
     // TODO: IGNITE-17718 when we design the system to configure metrics itself
     // TODO: this method should be revisited, but now it is supposed to use 
only to set distributed configuration for exporters.
-    void configure(MetricConfiguration metricConfiguration);
+    void configure(MetricConfiguration metricConfiguration, Supplier<UUID> 
clusterIdSupplier, String nodeName);
 
     /**
      * Start component.
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManagerImpl.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManagerImpl.java
index 9609010663..282462ec0c 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManagerImpl.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManagerImpl.java
@@ -24,9 +24,11 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.ServiceLoader.Provider;
+import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import 
org.apache.ignite.configuration.notifications.ConfigurationNamedListListener;
 import 
org.apache.ignite.configuration.notifications.ConfigurationNotificationEvent;
@@ -60,6 +62,10 @@ public class MetricManagerImpl implements MetricManager {
 
     private MetricConfiguration metricConfiguration;
 
+    private Supplier<UUID> clusterIdSupplier;
+
+    private String nodeName;
+
     /**
      * Constructor.
      */
@@ -79,10 +85,14 @@ public class MetricManagerImpl implements MetricManager {
     }
 
     @Override
-    public void configure(MetricConfiguration metricConfiguration) {
+    public void configure(MetricConfiguration metricConfiguration, 
Supplier<UUID> clusterIdSupplier, String nodeName) {
         assert this.metricConfiguration == null : "Metric manager must be 
configured only once, on the start of the node";
+        assert this.clusterIdSupplier == null : "Metric manager must be 
configured only once, on the start of the node";
+        assert this.nodeName == null : "Metric manager must be configured only 
once, on the start of the node";
 
         this.metricConfiguration = metricConfiguration;
+        this.clusterIdSupplier = clusterIdSupplier;
+        this.nodeName = nodeName;
     }
 
     @Override
@@ -111,7 +121,7 @@ public class MetricManagerImpl implements MetricManager {
         this.availableExporters = new HashMap<>();
 
         for (MetricExporter<?> exporter : exporters) {
-            exporter.start(metricsProvider, null);
+            exporter.start(metricsProvider, null, clusterIdSupplier, nodeName);
 
             availableExporters.put(exporter.name(), exporter);
             enabledMetricExporters.put(exporter.name(), exporter);
@@ -197,7 +207,7 @@ public class MetricManagerImpl implements MetricManager {
         if (exporter != null) {
             enabledMetricExporters.computeIfAbsent(exporter.name(), name -> {
                 try {
-                    exporter.start(metricsProvider, exporterConfiguration);
+                    exporter.start(metricsProvider, exporterConfiguration, 
clusterIdSupplier, nodeName);
 
                     return exporter;
                 } catch (Exception e) {
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java
index 0464484f15..a5cdb40fd8 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.internal.metrics.exporters;
 
 import java.util.Map;
+import java.util.UUID;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.lang.IgniteBiTuple;
 import org.apache.ignite.internal.metrics.MetricProvider;
 import org.apache.ignite.internal.metrics.MetricSet;
@@ -31,14 +33,20 @@ public abstract class BasicMetricExporter<CfgT extends 
ExporterView> implements
     /** Metrics provider. */
     private MetricProvider metricsProvider;
 
+    private Supplier<UUID> clusterIdSupplier;
+
+    private String nodeName;
+
     /** Exporter's configuration view. */
     private CfgT configuration;
 
     /** {@inheritDoc} */
     @Override
-    public void start(MetricProvider metricsProvider, CfgT configuration) {
+    public void start(MetricProvider metricsProvider, CfgT configuration, 
Supplier<UUID> clusterIdSupplier, String nodeName) {
         this.metricsProvider = metricsProvider;
         this.configuration = configuration;
+        this.clusterIdSupplier = clusterIdSupplier;
+        this.nodeName = nodeName;
     }
 
     /** {@inheritDoc} */
@@ -64,4 +72,18 @@ public abstract class BasicMetricExporter<CfgT extends 
ExporterView> implements
     protected final IgniteBiTuple<Map<String, MetricSet>, Long> metrics() {
         return metricsProvider.metrics();
     }
+
+    /**
+     * Returns current cluster ID.
+     */
+    protected final UUID clusterId() {
+        return clusterIdSupplier.get();
+    }
+
+    /**
+     * Returns the network alias of the node.
+     */
+    protected final String nodeName() {
+        return nodeName;
+    }
 }
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java
index d93db1fd85..76c73a547d 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.metrics.exporters;
 
+import java.util.UUID;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.metrics.MetricManagerImpl;
 import org.apache.ignite.internal.metrics.MetricProvider;
 import org.apache.ignite.internal.metrics.MetricSet;
@@ -39,8 +41,10 @@ public interface MetricExporter<CfgT extends ExporterView> {
      *
      * @param metricProvider Provider of metric sources.
      * @param configuration Exporter configuration view.
+     * @param clusterIdSupplier Cluster ID supplier.
+     * @param nodeName Node name.
      */
-    void start(MetricProvider metricProvider, CfgT configuration);
+    void start(MetricProvider metricProvider, CfgT configuration, 
Supplier<UUID> clusterIdSupplier, String nodeName);
 
     /**
      * Stop and cleanup work for current exporter must be implemented here.
@@ -70,7 +74,9 @@ public interface MetricExporter<CfgT extends ExporterView> {
      *
      * @param metricSet Named metric set.
      */
-    void addMetricSet(MetricSet metricSet);
+    default void addMetricSet(MetricSet metricSet) {
+        // No-op.
+    }
 
     /**
      * {@link MetricManagerImpl} invokes this method,
@@ -78,5 +84,7 @@ public interface MetricExporter<CfgT extends ExporterView> {
      *
      * @param metricSetName Name of metric set to remove.
      */
-    void removeMetricSet(String metricSetName);
+    default void removeMetricSet(String metricSetName) {
+        // No-op.
+    }
 }
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java
index 71704e05be..6948f4b049 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java
@@ -17,10 +17,12 @@
 
 package org.apache.ignite.internal.metrics.exporters;
 
+import java.util.UUID;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.metrics.MetricProvider;
@@ -45,8 +47,8 @@ public abstract class PushMetricExporter<CfgT extends 
ExporterView> extends Basi
 
     /** {@inheritDoc} */
     @Override
-    public synchronized void start(MetricProvider metricProvider, CfgT conf) {
-        super.start(metricProvider, conf);
+    public synchronized void start(MetricProvider metricProvider, CfgT conf, 
Supplier<UUID> clusterIdSupplier, String nodeName) {
+        super.start(metricProvider, conf, clusterIdSupplier, nodeName);
 
         scheduler =
                 Executors.newSingleThreadScheduledExecutor(new 
NamedThreadFactory("metrics-exporter-" + name(), log));
@@ -61,7 +63,6 @@ public abstract class PushMetricExporter<CfgT extends 
ExporterView> extends Basi
                 throw th;
             }
         }, period(), period(), TimeUnit.MILLISECONDS);
-
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
index 6e0b63046a..0a19701e97 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/configuration/LogPushExporterConfigurationSchema.java
@@ -26,6 +26,7 @@ import 
org.apache.ignite.internal.metrics.exporters.log.LogPushExporter;
  */
 @PolymorphicConfigInstance(LogPushExporter.EXPORTER_NAME)
 public class LogPushExporterConfigurationSchema extends 
ExporterConfigurationSchema {
+    /** Export period, in milliseconds. */
     @Value(hasDefault = true)
-    public int period = 30_000;
+    public long period = 30_000;
 }
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporter.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporter.java
index 526afde60a..646bc32b7d 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporter.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporter.java
@@ -23,6 +23,8 @@ import com.google.auto.service.AutoService;
 import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
+import java.util.function.Supplier;
 import javax.management.JMException;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
@@ -71,8 +73,9 @@ public class JmxExporter extends 
BasicMetricExporter<JmxExporterView> {
      * {@inheritDoc}
      */
     @Override
-    public synchronized void start(MetricProvider metricsProvider, 
JmxExporterView configuration) {
-        super.start(metricsProvider, configuration);
+    public synchronized void start(MetricProvider metricsProvider, 
JmxExporterView configuration, Supplier<UUID> clusterIdSupplier,
+            String nodeName) {
+        super.start(metricsProvider, configuration, clusterIdSupplier, 
nodeName);
 
         for (MetricSet metricSet : metricsProvider.metrics().get1().values()) {
             register(metricSet);
diff --git 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/log/LogPushExporter.java
 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/log/LogPushExporter.java
index cd00a45d7f..13749deeed 100644
--- 
a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/log/LogPushExporter.java
+++ 
b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/log/LogPushExporter.java
@@ -19,6 +19,8 @@ package org.apache.ignite.internal.metrics.exporters.log;
 
 import com.google.auto.service.AutoService;
 import java.util.Comparator;
+import java.util.UUID;
+import java.util.function.Supplier;
 import java.util.stream.StreamSupport;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
@@ -42,11 +44,12 @@ public class LogPushExporter extends 
PushMetricExporter<LogPushExporterView> {
     private long period;
 
     @Override
-    public void start(MetricProvider metricsProvider, LogPushExporterView 
configuration) {
+    public synchronized void start(MetricProvider metricsProvider, 
LogPushExporterView configuration, Supplier<UUID> clusterIdSupplier,
+            String nodeName) {
         period = configuration.period();
         log = Loggers.forClass(LogPushExporter.class);
 
-        super.start(metricsProvider, configuration);
+        super.start(metricsProvider, configuration, clusterIdSupplier, 
nodeName);
     }
 
     @Override
diff --git 
a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/MetricConfigurationTest.java
 
b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/MetricConfigurationTest.java
index f14034627b..d71aab526c 100644
--- 
a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/MetricConfigurationTest.java
+++ 
b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/MetricConfigurationTest.java
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.UUID;
 import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
 import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.metrics.configuration.MetricConfiguration;
@@ -61,7 +62,7 @@ public class MetricConfigurationTest extends 
BaseIgniteAbstractTest {
 
         availableExporters.put("test", exporter);
 
-        metricManager.configure(metricConfiguration);
+        metricManager.configure(metricConfiguration, UUID::randomUUID, 
"test-node");
 
         metricManager.start(availableExporters);
     }
diff --git 
a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/TestExporter.java
 
b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/TestExporter.java
index b95795cf22..43c246a4a1 100644
--- 
a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/TestExporter.java
+++ 
b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/TestExporter.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.metrics.exporters;
 
+import java.util.UUID;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.metrics.MetricProvider;
 import org.apache.ignite.internal.metrics.MetricSet;
 import org.jetbrains.annotations.Nullable;
@@ -31,8 +33,8 @@ public class TestExporter extends 
BasicMetricExporter<TestExporterView> {
     private volatile int port;
 
     @Override
-    public void start(MetricProvider metricsProvider, TestExporterView 
configuration) {
-        super.start(metricsProvider, configuration);
+    public void start(MetricProvider metricsProvider, TestExporterView 
configuration, Supplier<UUID> clusterIdSupplier, String nodeName) {
+        super.start(metricsProvider, configuration, clusterIdSupplier, 
nodeName);
 
         port = configuration.port();
 
diff --git 
a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/JmxExporterTest.java
 
b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporterTest.java
similarity index 86%
rename from 
modules/metrics/src/test/java/org/apache/ignite/internal/metrics/JmxExporterTest.java
rename to 
modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporterTest.java
index 913f279102..59066a7ff4 100644
--- 
a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/JmxExporterTest.java
+++ 
b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/exporters/jmx/JmxExporterTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.metrics;
+package org.apache.ignite.internal.metrics.exporters.jmx;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -27,6 +27,7 @@ import java.lang.management.ManagementFactory;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.UUID;
 import javax.management.AttributeNotFoundException;
 import javax.management.DynamicMBean;
 import javax.management.InstanceNotFoundException;
@@ -43,9 +44,24 @@ import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExten
 import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.lang.IgniteBiTuple;
 import org.apache.ignite.internal.logger.Loggers;
+import org.apache.ignite.internal.metrics.AtomicDoubleMetric;
+import org.apache.ignite.internal.metrics.AtomicIntMetric;
+import org.apache.ignite.internal.metrics.AtomicLongMetric;
+import org.apache.ignite.internal.metrics.DistributionMetric;
+import org.apache.ignite.internal.metrics.DoubleAdderMetric;
+import org.apache.ignite.internal.metrics.DoubleGauge;
+import org.apache.ignite.internal.metrics.DoubleMetric;
+import org.apache.ignite.internal.metrics.HitRateMetric;
+import org.apache.ignite.internal.metrics.IntGauge;
+import org.apache.ignite.internal.metrics.IntMetric;
+import org.apache.ignite.internal.metrics.LongAdderMetric;
+import org.apache.ignite.internal.metrics.LongGauge;
+import org.apache.ignite.internal.metrics.LongMetric;
+import org.apache.ignite.internal.metrics.Metric;
+import org.apache.ignite.internal.metrics.MetricProvider;
+import org.apache.ignite.internal.metrics.MetricSet;
 import org.apache.ignite.internal.metrics.configuration.MetricConfiguration;
 import 
org.apache.ignite.internal.metrics.exporters.configuration.JmxExporterView;
-import org.apache.ignite.internal.metrics.exporters.jmx.JmxExporter;
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.junit.jupiter.api.AfterEach;
@@ -122,7 +138,7 @@ public class JmxExporterTest extends BaseIgniteAbstractTest 
{
 
         when(metricsProvider.metrics()).thenReturn(new 
IgniteBiTuple<>(metrics, 1L));
 
-        jmxExporter.start(metricsProvider, jmxExporterConf);
+        jmxExporter.start(metricsProvider, jmxExporterConf, UUID::randomUUID, 
"nodeName");
 
         assertThatMbeanAttributeAndMetricValuesAreTheSame();
     }
@@ -132,7 +148,7 @@ public class JmxExporterTest extends BaseIgniteAbstractTest 
{
             throws ReflectionException, AttributeNotFoundException, 
MBeanException {
         when(metricsProvider.metrics()).thenReturn(new IgniteBiTuple<>(new 
HashMap<>(), 1L));
 
-        jmxExporter.start(metricsProvider, jmxExporterConf);
+        jmxExporter.start(metricsProvider, jmxExporterConf, UUID::randomUUID, 
"nodeName");
 
         assertThrows(
                 InstanceNotFoundException.class,
@@ -151,7 +167,7 @@ public class JmxExporterTest extends BaseIgniteAbstractTest 
{
 
         when(metricsProvider.metrics()).thenReturn(new 
IgniteBiTuple<>(metrics, 1L));
 
-        jmxExporter.start(metricsProvider, jmxExporterConf);
+        jmxExporter.start(metricsProvider, jmxExporterConf, UUID::randomUUID, 
"nodeName");
 
         assertThatMbeanAttributeAndMetricValuesAreTheSame();
 
@@ -169,7 +185,7 @@ public class JmxExporterTest extends BaseIgniteAbstractTest 
{
 
         when(metricsProvider.metrics()).thenReturn(new 
IgniteBiTuple<>(Map.of(metricSet.name(), metricSet), 1L));
 
-        jmxExporter.start(metricsProvider, jmxExporterConf);
+        jmxExporter.start(metricsProvider, jmxExporterConf, UUID::randomUUID, 
"nodeName");
 
         assertEquals(0, mbean().getAttribute(MTRC_NAME));
 
diff --git 
a/modules/metrics/src/testFixtures/java/org/apache/ignite/internal/metrics/NoOpMetricManager.java
 
b/modules/metrics/src/testFixtures/java/org/apache/ignite/internal/metrics/NoOpMetricManager.java
index c19905ef0c..5164c15b96 100644
--- 
a/modules/metrics/src/testFixtures/java/org/apache/ignite/internal/metrics/NoOpMetricManager.java
+++ 
b/modules/metrics/src/testFixtures/java/org/apache/ignite/internal/metrics/NoOpMetricManager.java
@@ -22,7 +22,9 @@ import static 
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFu
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
+import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.lang.IgniteBiTuple;
 import org.apache.ignite.internal.manager.ComponentContext;
 import org.apache.ignite.internal.metrics.configuration.MetricConfiguration;
@@ -34,7 +36,7 @@ import 
org.apache.ignite.internal.metrics.exporters.MetricExporter;
  */
 public class NoOpMetricManager implements MetricManager {
     @Override
-    public void configure(MetricConfiguration metricConfiguration) {
+    public void configure(MetricConfiguration metricConfiguration, 
Supplier<UUID> clusterIdSupplier, String nodeName) {
     }
 
     @Override
diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle
index 570e1fa60d..42c06099a1 100644
--- a/modules/runner/build.gradle
+++ b/modules/runner/build.gradle
@@ -75,6 +75,7 @@ dependencies {
     implementation project(':ignite-cluster-management')
     implementation project(':ignite-metrics')
     implementation project(':ignite-cluster-metrics')
+    implementation project(':ignite-metrics-exporter-otlp')
     implementation project(':ignite-replicator')
     implementation project(':ignite-distribution-zones')
     implementation project(':ignite-placement-driver')
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index 9b2d97770b..0a5b14c206 100644
--- 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -262,6 +262,7 @@ import 
org.apache.ignite.internal.tx.impl.TransactionIdGenerator;
 import org.apache.ignite.internal.tx.impl.TransactionInflights;
 import org.apache.ignite.internal.tx.impl.TxManagerImpl;
 import org.apache.ignite.internal.tx.message.TxMessageGroup;
+import org.apache.ignite.internal.util.CollectionUtils;
 import org.apache.ignite.internal.vault.VaultManager;
 import org.apache.ignite.internal.vault.persistence.PersistentVaultService;
 import org.apache.ignite.internal.worker.CriticalWorkerWatchdog;
@@ -819,7 +820,11 @@ public class IgniteImpl implements Ignite {
                 threadPoolsManager.tableIoExecutor()
         );
 
-        
metricManager.configure(clusterConfigRegistry.getConfiguration(MetricExtensionConfiguration.KEY).metrics());
+        metricManager.configure(
+                
clusterConfigRegistry.getConfiguration(MetricExtensionConfiguration.KEY).metrics(),
+                () -> 
CollectionUtils.last(clusterInfo(clusterStateStorageMgr).idHistory()),
+                name
+        );
 
         DataStorageModules dataStorageModules = new DataStorageModules(
                 ServiceLoader.load(DataStorageModule.class, 
serviceProviderClassLoader)
diff --git a/settings.gradle b/settings.gradle
index 7b4271fa3e..8df3ddf551 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -61,6 +61,7 @@ include(':ignite-configuration-annotation-processor')
 include(':ignite-compute')
 include(':ignite-metrics')
 include(':ignite-cluster-metrics')
+include(':ignite-metrics-exporter-otlp')
 include(':ignite-binary-tuple')
 include(':platforms')
 include(':packaging-cli')
@@ -139,6 +140,7 @@ 
project(":ignite-configuration-annotation-processor").projectDir = file('modules
 project(":ignite-compute").projectDir = file('modules/compute')
 project(":ignite-metrics").projectDir = file('modules/metrics')
 project(":ignite-cluster-metrics").projectDir = file('modules/cluster-metrics')
+project(":ignite-metrics-exporter-otlp").projectDir = 
file('modules/metrics-exporter-otlp')
 project(":ignite-binary-tuple").projectDir = file('modules/binary-tuple')
 project(":platforms").projectDir = file('modules/platforms')
 project(":ignite-replicator").projectDir = file('modules/replicator')

Reply via email to