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

zrlw pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new 82e77e4603 Fix issue 12517, implemented new module for otlp config 
along with test checking jvm metric export using mock server (#16023)
82e77e4603 is described below

commit 82e77e4603e12ef686129555870fa4eea04add30
Author: Manas Agarwal <[email protected]>
AuthorDate: Wed Jan 28 10:45:33 2026 +0530

    Fix issue 12517, implemented new module for otlp config along with test 
checking jvm metric export using mock server (#16023)
---
 .artifacts                                         |   1 +
 .../dubbo/common/constants/MetricsConstants.java   |   2 +
 .../org/apache/dubbo/config/MetricsConfig.java     |  15 +++
 .../dubbo/config/nested/OtlpMetricConfig.java      |  90 +++++++++++++
 dubbo-distribution/dubbo-all-shaded/pom.xml        |  10 +-
 dubbo-distribution/dubbo-all/pom.xml               |   9 +-
 dubbo-distribution/dubbo-bom/pom.xml               |   6 +-
 dubbo-metrics/dubbo-metrics-otlp/pom.xml           |  74 +++++++++++
 .../dubbo/metrics/otlp/OtlpMetricsReporter.java    | 143 ++++++++++++++++++++
 .../metrics/otlp/OtlpMetricsReporterFactory.java   |  34 +++++
 ...che.dubbo.metrics.report.MetricsReporterFactory |   1 +
 .../otlp/OtlpMetricsReporterFactoryTest.java       | 146 +++++++++++++++++++++
 dubbo-metrics/pom.xml                              |   1 +
 dubbo-test/dubbo-dependencies-all/pom.xml          |   6 +-
 14 files changed, 534 insertions(+), 4 deletions(-)

diff --git a/.artifacts b/.artifacts
index 09d2d03525..28b0249adb 100644
--- a/.artifacts
+++ b/.artifacts
@@ -53,6 +53,7 @@ dubbo-metrics-api
 dubbo-metrics-default
 dubbo-metrics-metadata
 dubbo-metrics-prometheus
+dubbo-metrics-otlp
 dubbo-metrics-registry
 dubbo-metrics-config-center
 dubbo-metrics-netty
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
index b9b503d0e9..2fa7e2d5b5 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
@@ -98,4 +98,6 @@ public interface MetricsConstants {
     String METRIC_FILTER_START_TIME = "metric_filter_start_time";
 
     String TAG_THREAD_NAME = "thread.pool.name";
+
+    String PROTOCOL_OTLP = "otlp";
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
index 5a56ed40ea..7c948b4b02 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.UrlUtils;
 import org.apache.dubbo.config.nested.AggregationConfig;
 import org.apache.dubbo.config.nested.HistogramConfig;
+import org.apache.dubbo.config.nested.OtlpMetricConfig;
 import org.apache.dubbo.config.nested.PrometheusConfig;
 import org.apache.dubbo.config.support.Nested;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -127,6 +128,12 @@ public class MetricsConfig extends AbstractConfig {
      */
     private String rpcLevel;
 
+    /**
+     * Configuration for the metrics exporter.
+     */
+    @Nested
+    private OtlpMetricConfig otlp;
+
     public MetricsConfig() {}
 
     public MetricsConfig(ApplicationModel applicationModel) {
@@ -287,4 +294,12 @@ public class MetricsConfig extends AbstractConfig {
     public void setEnableNetty(Boolean enableNetty) {
         this.enableNetty = enableNetty;
     }
+
+    public OtlpMetricConfig getOtlp() {
+        return otlp;
+    }
+
+    public void setOtlp(OtlpMetricConfig otlp) {
+        this.otlp = otlp;
+    }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OtlpMetricConfig.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OtlpMetricConfig.java
new file mode 100644
index 0000000000..97ddc40c86
--- /dev/null
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OtlpMetricConfig.java
@@ -0,0 +1,90 @@
+/*
+ * 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.dubbo.config.nested;
+
+import java.io.Serializable;
+import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class OtlpMetricConfig implements Serializable {
+
+    /**
+     * URI of the OLTP server.
+     */
+    private String endpoint;
+
+    /**
+     * Monitored resource's attributes.
+     */
+    private Map<String, String> resourceAttributes;
+
+    /**
+     * Headers for the exported metrics.
+     */
+    private Map<String, String> headers;
+
+    /**
+     * Time unit for exported metrics.
+     */
+    private TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS;
+
+    /**
+     * Intervals for pushing metrics
+     */
+    private Duration step;
+
+    public String getEndpoint() {
+        return this.endpoint;
+    }
+
+    public void setUrl(String endpoint) {
+        this.endpoint = endpoint;
+    }
+
+    public Map<String, String> getResourceAttributes() {
+        return this.resourceAttributes;
+    }
+
+    public void setResourceAttributes(Map<String, String> resourceAttributes) {
+        this.resourceAttributes = resourceAttributes;
+    }
+
+    public Map<String, String> getHeaders() {
+        return this.headers;
+    }
+
+    public void setHeaders(Map<String, String> headers) {
+        this.headers = headers;
+    }
+
+    public TimeUnit getBaseTimeUnit() {
+        return this.baseTimeUnit;
+    }
+
+    public void setBaseTimeUnit(TimeUnit baseTimeUnit) {
+        this.baseTimeUnit = baseTimeUnit;
+    }
+
+    public Duration getStep() {
+        return this.step;
+    }
+
+    public void setStep(Duration step) {
+        this.step = step;
+    }
+}
diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml 
b/dubbo-distribution/dubbo-all-shaded/pom.xml
index b5c1d40dd8..84884121d5 100644
--- a/dubbo-distribution/dubbo-all-shaded/pom.xml
+++ b/dubbo-distribution/dubbo-all-shaded/pom.xml
@@ -207,7 +207,13 @@
       <scope>compile</scope>
       <optional>true</optional>
     </dependency>
-
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-metrics-otlp</artifactId>
+      <version>${project.version}</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
     <!-- tracing -->
     <dependency>
       <groupId>org.apache.dubbo</groupId>
@@ -508,6 +514,7 @@
                   
<include>org.apache.dubbo:dubbo-metrics-config-center</include>
                   <include>org.apache.dubbo:dubbo-metrics-netty</include>
                   <include>org.apache.dubbo:dubbo-metrics-prometheus</include>
+                  <include>org.apache.dubbo:dubbo-metrics-otlp</include>
                   <include>org.apache.dubbo:dubbo-tracing</include>
                   <include>org.apache.dubbo:dubbo-qos</include>
                   <include>org.apache.dubbo:dubbo-qos-api</include>
@@ -541,6 +548,7 @@
                   
<include>org.apache.dubbo:dubbo-serialization-hessian2</include>
                   
<include>org.apache.dubbo:dubbo-serialization-fastjson2</include>
                   <include>org.apache.dubbo:dubbo-plugin-loom</include>
+
                   <include>io.netty:*</include>
                 </includes>
               </artifactSet>
diff --git a/dubbo-distribution/dubbo-all/pom.xml 
b/dubbo-distribution/dubbo-all/pom.xml
index a766ee0558..3ac1a3939f 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -207,7 +207,13 @@
       <scope>compile</scope>
       <optional>true</optional>
     </dependency>
-
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-metrics-otlp</artifactId>
+      <version>${project.version}</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
     <!-- tracing -->
     <dependency>
       <groupId>org.apache.dubbo</groupId>
@@ -507,6 +513,7 @@
                   
<include>org.apache.dubbo:dubbo-metrics-config-center</include>
                   <include>org.apache.dubbo:dubbo-metrics-netty</include>
                   <include>org.apache.dubbo:dubbo-metrics-prometheus</include>
+                  <include>org.apache.dubbo:dubbo-metrics-otlp</include>
                   <include>org.apache.dubbo:dubbo-tracing</include>
                   <include>org.apache.dubbo:dubbo-qos</include>
                   <include>org.apache.dubbo:dubbo-qos-api</include>
diff --git a/dubbo-distribution/dubbo-bom/pom.xml 
b/dubbo-distribution/dubbo-bom/pom.xml
index 558f95a7c6..d699478357 100644
--- a/dubbo-distribution/dubbo-bom/pom.xml
+++ b/dubbo-distribution/dubbo-bom/pom.xml
@@ -237,7 +237,11 @@
         <artifactId>dubbo-metrics-netty</artifactId>
         <version>${project.version}</version>
       </dependency>
-
+      <dependency>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-metrics-otlp</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <!-- tracing -->
       <dependency>
         <groupId>org.apache.dubbo</groupId>
diff --git a/dubbo-metrics/dubbo-metrics-otlp/pom.xml 
b/dubbo-metrics/dubbo-metrics-otlp/pom.xml
new file mode 100644
index 0000000000..16f7b54e62
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-otlp/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.dubbo</groupId>
+    <artifactId>dubbo-metrics</artifactId>
+    <version>${revision}</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <artifactId>dubbo-metrics-otlp</artifactId>
+  <packaging>jar</packaging>
+  <name>${project.artifactId}</name>
+  <description>The otlp metrics module of dubbo project</description>
+  <properties>
+    <skip_maven_deploy>false</skip_maven_deploy>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-common</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-metrics-default</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-qos-api</artifactId>
+      <version>${project.parent.version}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>io.micrometer</groupId>
+      <artifactId>micrometer-registry-otlp</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-metrics-default</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.squareup.okhttp3</groupId>
+      <artifactId>mockwebserver</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git 
a/dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporter.java
 
b/dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporter.java
new file mode 100644
index 0000000000..5d8b938e98
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporter.java
@@ -0,0 +1,143 @@
+/*
+ * 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.dubbo.metrics.otlp;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.MetricsConstants;
+import org.apache.dubbo.config.MetricsConfig;
+import org.apache.dubbo.config.nested.OtlpMetricConfig;
+import org.apache.dubbo.metrics.report.AbstractMetricsReporter;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import io.micrometer.core.instrument.Clock;
+import io.micrometer.registry.otlp.AggregationTemporality;
+import io.micrometer.registry.otlp.OtlpConfig;
+import io.micrometer.registry.otlp.OtlpMeterRegistry;
+
+/**
+ * Metrics reporter for Otlp.
+ */
+public class OtlpMetricsReporter extends AbstractMetricsReporter {
+
+    private final OtlpMeterRegistry otlpMeterRegistry;
+
+    public OtlpMetricsReporter(final URL url, ApplicationModel 
applicationModel) {
+        super(url, applicationModel);
+        Optional<MetricsConfig> configOptional =
+                applicationModel.getApplicationConfigManager().getMetrics();
+        // If no specific metrics type is configured and there is no 
Prometheus dependency in the dependencies.
+        MetricsConfig metricsConfig = configOptional.orElse(new 
MetricsConfig(applicationModel));
+        OtlpMetricConfig otlpMetricConfig = metricsConfig.getOtlp();
+        // check protocol whether is otlp
+        if (otlpMetricConfig == null || 
!MetricsConstants.PROTOCOL_OTLP.equals(metricsConfig.getProtocol())) {
+            throw new IllegalStateException(
+                    "Otlp metrics reporter config is required oltp protocol 
but real does not match.");
+        }
+
+        OtlpConfig config = new OtlpWrapperConfig(otlpMetricConfig, 
applicationModel);
+        this.otlpMeterRegistry = new OtlpMeterRegistry(config, Clock.SYSTEM);
+    }
+
+    @Override
+    public void doInit() {
+        addMeterRegistry(this.otlpMeterRegistry);
+    }
+
+    @Override
+    public String getResponse() {
+        return null;
+    }
+
+    @Override
+    public void doDestroy() {
+        if (this.otlpMeterRegistry != null) {
+            this.otlpMeterRegistry.close();
+        }
+    }
+
+    public static class OtlpWrapperConfig implements OtlpConfig {
+
+        private final OtlpMetricConfig otlpMetricConfig;
+        private final ApplicationModel applicationModel;
+
+        public OtlpWrapperConfig(OtlpMetricConfig otlpMetricConfig, 
ApplicationModel applicationModel) {
+            this.otlpMetricConfig = otlpMetricConfig;
+            this.applicationModel = applicationModel;
+        }
+
+        @Override
+        public String get(String key) {
+            // just use default value
+            return OtlpConfig.DEFAULT.get(key);
+        }
+
+        @Override
+        public String url() {
+            if (this.otlpMetricConfig.getEndpoint() == null) {
+                return OtlpConfig.super.url();
+            }
+            return this.otlpMetricConfig.getEndpoint();
+        }
+
+        @Override
+        public Duration step() {
+            if (this.otlpMetricConfig.getStep() == null) {
+                return OtlpConfig.super.step();
+            }
+            return this.otlpMetricConfig.getStep();
+        }
+
+        @Override
+        public Map<String, String> resourceAttributes() {
+            Map<String, String> resourceAttributes = 
this.otlpMetricConfig.getResourceAttributes();
+            if (resourceAttributes == null) {
+                resourceAttributes = OtlpConfig.super.resourceAttributes();
+            }
+            // set service.name
+            resourceAttributes.computeIfAbsent("service.name", (key) -> 
getApplicationName());
+            return resourceAttributes;
+        }
+
+        @Override
+        public AggregationTemporality aggregationTemporality() {
+            return OtlpConfig.super.aggregationTemporality();
+        }
+
+        @Override
+        public Map<String, String> headers() {
+            Map<String, String> headers = this.otlpMetricConfig.getHeaders();
+            if (headers == null) {
+                headers = OtlpConfig.super.headers();
+            }
+            return headers;
+        }
+
+        @Override
+        public TimeUnit baseTimeUnit() {
+            return this.otlpMetricConfig.getBaseTimeUnit();
+        }
+
+        private String getApplicationName() {
+            return this.applicationModel.getApplicationName();
+        }
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactory.java
 
b/dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactory.java
new file mode 100644
index 0000000000..67dbc34e7f
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactory.java
@@ -0,0 +1,34 @@
+/*
+ * 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.dubbo.metrics.otlp;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.metrics.report.AbstractMetricsReporterFactory;
+import org.apache.dubbo.metrics.report.MetricsReporter;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+public class OtlpMetricsReporterFactory extends AbstractMetricsReporterFactory 
{
+
+    public OtlpMetricsReporterFactory(ApplicationModel applicationModel) {
+        super(applicationModel);
+    }
+
+    @Override
+    public MetricsReporter createMetricsReporter(URL url) {
+        return new OtlpMetricsReporter(url, getApplicationModel());
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-otlp/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory
 
b/dubbo-metrics/dubbo-metrics-otlp/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory
new file mode 100644
index 0000000000..4036456bc9
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-otlp/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory
@@ -0,0 +1 @@
+otlp=org.apache.dubbo.metrics.otlp.OtlpMetricsReporterFactory
diff --git 
a/dubbo-metrics/dubbo-metrics-otlp/src/test/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactoryTest.java
 
b/dubbo-metrics/dubbo-metrics-otlp/src/test/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactoryTest.java
new file mode 100644
index 0000000000..f04092c2a5
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-otlp/src/test/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactoryTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.dubbo.metrics.otlp;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MetricsConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.nested.AggregationConfig;
+import org.apache.dubbo.config.nested.OtlpMetricConfig;
+import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
+import org.apache.dubbo.metrics.report.MetricsReporter;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_OTLP;
+
+public class OtlpMetricsReporterFactoryTest {
+
+    private MockWebServer otlpMockServer;
+    private CopyOnWriteArrayList<byte[]> capturedRequests;
+    private ApplicationModel applicationModel;
+    private MetricsConfig metricsConfig;
+    private FrameworkModel frameworkModel;
+
+    @BeforeEach
+    public void setup() {
+        otlpMockServer = new MockWebServer();
+        for (int i = 0; i < 100; i++) {
+            otlpMockServer.enqueue(new MockResponse()
+                    .setResponseCode(200)
+                    .setBody("{}")
+                    .addHeader("Content-Type", "application/json"));
+        }
+        applicationModel = ApplicationModel.defaultModel();
+        ConfigManager applicationConfigManager = 
applicationModel.getApplicationConfigManager();
+        metricsConfig = new MetricsConfig();
+        metricsConfig.setEnableJvm(true);
+        metricsConfig.setProtocol(PROTOCOL_OTLP);
+        AggregationConfig aggregationConfig = new AggregationConfig();
+        aggregationConfig.setEnabled(false);
+        metricsConfig.setAggregation(aggregationConfig);
+        OtlpMetricConfig otlpMetricsConfig = new OtlpMetricConfig();
+        otlpMetricsConfig.setStep(Duration.ofSeconds(1));
+        metricsConfig.setOtlp(otlpMetricsConfig);
+        otlpMetricsConfig.setUrl(otlpMockServer.url("/v1/metrics").toString());
+        applicationConfigManager.setMetrics(metricsConfig);
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        applicationConfig.setName("test_app_name");
+        applicationConfigManager.setApplication(applicationConfig);
+        frameworkModel = FrameworkModel.defaultModel();
+        
frameworkModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);
+    }
+
+    @AfterEach
+    public void teardown() throws IOException {
+        applicationModel.destroy();
+        if (otlpMockServer != null) {
+            otlpMockServer.shutdown();
+        }
+    }
+
+    @Test
+    public void test_MetricsReporter() {
+
+        OtlpMetricsReporterFactory factory = new 
OtlpMetricsReporterFactory(applicationModel);
+        MetricsReporter reporter = 
factory.createMetricsReporter(metricsConfig.toUrl());
+        Assertions.assertTrue(reporter instanceof OtlpMetricsReporter);
+        applicationModel.destroy();
+    }
+
+    @Test
+    public void test_MetricsReporter_with_not_match_protocol() {
+        OtlpMetricsReporterFactory factory = new 
OtlpMetricsReporterFactory(applicationModel);
+        try {
+            factory.createMetricsReporter(metricsConfig.toUrl());
+        } catch (Exception ex) {
+            Assertions.assertInstanceOf(IllegalStateException.class, ex);
+        }
+    }
+
+    @Test
+    public void export_Test() throws IOException, InterruptedException {
+
+        OtlpMetricsReporter reporter = new 
OtlpMetricsReporter(metricsConfig.toUrl(), applicationModel);
+        reporter.init();
+        try {
+
+            List<String> requestBodies = new ArrayList<>();
+
+            long endTime = System.currentTimeMillis() + 3000;
+            while (System.currentTimeMillis() < endTime) {
+                RecordedRequest request = otlpMockServer.takeRequest(500, 
TimeUnit.MILLISECONDS);
+                if (request != null) {
+                    String body = 
request.getBody().readString(StandardCharsets.UTF_8);
+                    requestBodies.add(body);
+                }
+            }
+
+            Assertions.assertFalse(requestBodies.isEmpty(), "Expected OTLP 
metrics to be pushed");
+
+            boolean hasJvmMetrics = requestBodies.stream()
+                    .anyMatch(body -> body.contains("jvm")
+                            || body.contains("JVM")
+                            || body.contains("memory")
+                            || body.contains("gc")
+                            || body.contains("threads"));
+
+            Assertions.assertTrue(
+                    hasJvmMetrics,
+                    "Expected JVM metrics to be present in OTLP export.  
Captured bodies: " + requestBodies.size());
+
+        } finally {
+            reporter.destroy();
+        }
+    }
+}
diff --git a/dubbo-metrics/pom.xml b/dubbo-metrics/pom.xml
index 7176e2e182..af0ff2c692 100644
--- a/dubbo-metrics/pom.xml
+++ b/dubbo-metrics/pom.xml
@@ -37,6 +37,7 @@
     <module>dubbo-metrics-config-center</module>
     <module>dubbo-tracing</module>
     <module>dubbo-metrics-netty</module>
+    <module>dubbo-metrics-otlp</module>
   </modules>
   <properties>
     <skip_maven_deploy>false</skip_maven_deploy>
diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml 
b/dubbo-test/dubbo-dependencies-all/pom.xml
index fcdc9b593b..9d5b67d66e 100644
--- a/dubbo-test/dubbo-dependencies-all/pom.xml
+++ b/dubbo-test/dubbo-dependencies-all/pom.xml
@@ -190,7 +190,11 @@
       <artifactId>dubbo-tracing</artifactId>
       <version>${project.version}</version>
     </dependency>
-
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-metrics-otlp</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <!-- native -->
     <dependency>
       <groupId>org.apache.dubbo</groupId>

Reply via email to