You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2024/09/06 07:53:51 UTC

(skywalking) branch otelso117 updated (248f4abb40 -> 59b9b4c3d7)

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

kezhenxu94 pushed a change to branch otelso117
in repository https://gitbox.apache.org/repos/asf/skywalking.git


 discard 248f4abb40 Add self observability metrics for otel handler
     new 59b9b4c3d7 Add self observability metrics for otel handler

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (248f4abb40)
            \
             N -- N -- N   refs/heads/otelso117 (59b9b4c3d7)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../otel/otlp/OpenTelemetryLogHandler.java         |   8 +-
 .../otlp/OpenTelemetryMetricRequestProcessor.java  |   8 +-
 .../otel/otlp/OpenTelemetryTraceHandler.java       |   8 +-
 .../so11y_oap/so11y-instance.json                  | 142 +++++++++++++++++++++
 4 files changed, 154 insertions(+), 12 deletions(-)


(skywalking) 01/01: Add self observability metrics for otel handler

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch otelso117
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit 59b9b4c3d7ba8b7711055fdea9bcc397955ee08c
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Thu Sep 5 15:56:00 2024 +0800

    Add self observability metrics for otel handler
---
 .github/workflows/publish-docker.yaml              |   1 +
 .../otel/otlp/OpenTelemetryLogHandler.java         |  74 +++++++----
 .../otlp/OpenTelemetryMetricRequestProcessor.java  |  81 ++++++++----
 .../otel/otlp/OpenTelemetryTraceHandler.java       |  72 +++++++----
 .../src/main/resources/otel-rules/oap.yaml         |  35 +++--
 .../so11y_oap/so11y-instance.json                  | 142 +++++++++++++++++++++
 6 files changed, 322 insertions(+), 83 deletions(-)

diff --git a/.github/workflows/publish-docker.yaml b/.github/workflows/publish-docker.yaml
index 01c7e0b20d..ca6278dc33 100644
--- a/.github/workflows/publish-docker.yaml
+++ b/.github/workflows/publish-docker.yaml
@@ -20,6 +20,7 @@ on:
   push:
     branches:
       - master
+      - otelso117
   release:
     types:
       - released
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHandler.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHandler.java
index 3d6c6bc9db..5358aeb2ee 100644
--- a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHandler.java
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHandler.java
@@ -27,6 +27,7 @@ import io.opentelemetry.proto.common.v1.KeyValue;
 import io.opentelemetry.proto.logs.v1.LogRecord;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import lombok.Getter;
 import org.apache.skywalking.apm.network.common.v3.KeyStringValuePair;
 import org.apache.skywalking.apm.network.logging.v3.LogData;
 import org.apache.skywalking.apm.network.logging.v3.LogDataBody;
@@ -39,6 +40,11 @@ import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.module.ModuleStartException;
 import org.apache.skywalking.oap.server.receiver.otel.Handler;
 import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
+import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
+import org.apache.skywalking.oap.server.telemetry.api.CounterMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.HistogramMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
 
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -54,6 +60,24 @@ public class OpenTelemetryLogHandler
 
     private ILogAnalyzerService logAnalyzerService;
 
+    @Getter(lazy = true)
+    private final MetricsCreator metricsCreator = manager.find(TelemetryModule.NAME).provider().getService(MetricsCreator.class);
+
+    @Getter(lazy = true)
+    private final CounterMetrics receivedCounter = getMetricsCreator().createCounter(
+        "otel_logs_received",
+        "The number of log request received by the OTLP receiver",
+        MetricsTag.EMPTY_KEY,
+        MetricsTag.EMPTY_VALUE
+    );
+    @Getter(lazy = true)
+    private final HistogramMetrics processHistogram = getMetricsCreator().createHistogramMetric(
+        "otel_logs_latency",
+        "The latency to process the logs request",
+        MetricsTag.EMPTY_KEY,
+        MetricsTag.EMPTY_VALUE
+    );
+
     @Override
     public String type() {
         return "otlp-logs";
@@ -69,30 +93,32 @@ public class OpenTelemetryLogHandler
 
     @Override
     public void export(ExportLogsServiceRequest request, StreamObserver<ExportLogsServiceResponse> responseObserver) {
-        request.getResourceLogsList().forEach(resourceLogs -> {
-            final var resource = resourceLogs.getResource();
-            final var attributes = resource
-                .getAttributesList().stream()
-                .map(it -> Map.entry(it.getKey(), buildTagValue(it)))
-                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
-            final var service = attributes.get("service.name");
-            if (Strings.isNullOrEmpty(service)) {
-                log.warn("No service name found in resource attributes, discarding the log");
-                return;
-            }
-            final var layer = attributes.getOrDefault("service.layer", "");
-            final var serviceInstance = attributes.getOrDefault("service.instance", "");
-
-            resourceLogs
-                .getScopeLogsList()
-                .stream()
-                .flatMap(it -> it.getLogRecordsList().stream())
-                .forEach(
-                    logRecord ->
-                        doAnalysisQuietly(service, layer, serviceInstance, logRecord));
-            responseObserver.onNext(ExportLogsServiceResponse.getDefaultInstance());
-            responseObserver.onCompleted();
-        });
+        getReceivedCounter().inc();
+
+        try (final var timer = getProcessHistogram().createTimer()) {
+            request.getResourceLogsList().forEach(resourceLogs -> {
+                final var resource = resourceLogs.getResource();
+                final var attributes = resource
+                    .getAttributesList().stream()
+                    .map(it -> Map.entry(it.getKey(), buildTagValue(it)))
+                    .collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
+                final var service = attributes.get("service.name");
+                if (Strings.isNullOrEmpty(service)) {
+                    log.warn("No service name found in resource attributes, discarding the log");
+                    return;
+                }
+                final var layer = attributes.getOrDefault("service.layer", "");
+                final var serviceInstance = attributes.getOrDefault("service.instance", "");
+
+                resourceLogs
+                    .getScopeLogsList()
+                    .stream()
+                    .flatMap(it -> it.getLogRecordsList().stream())
+                    .forEach(logRecord -> doAnalysisQuietly(service, layer, serviceInstance, logRecord));
+                responseObserver.onNext(ExportLogsServiceResponse.getDefaultInstance());
+                responseObserver.onCompleted();
+            });
+        }
     }
 
     private void doAnalysisQuietly(String service, String layer, String serviceInstance, LogRecord logRecord) {
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricRequestProcessor.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricRequestProcessor.java
index 0be3aaaf2c..16f70bb10f 100644
--- a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricRequestProcessor.java
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricRequestProcessor.java
@@ -25,6 +25,7 @@ import io.opentelemetry.proto.common.v1.KeyValue;
 import io.opentelemetry.proto.metrics.v1.Sum;
 import io.opentelemetry.proto.metrics.v1.SummaryDataPoint;
 import io.vavr.Function1;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.meter.analyzer.MetricConvert;
@@ -42,6 +43,11 @@ import org.apache.skywalking.oap.server.library.util.prometheus.metrics.Histogra
 import org.apache.skywalking.oap.server.library.util.prometheus.metrics.Metric;
 import org.apache.skywalking.oap.server.library.util.prometheus.metrics.Summary;
 import org.apache.skywalking.oap.server.receiver.otel.OtelMetricReceiverConfig;
+import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
+import org.apache.skywalking.oap.server.telemetry.api.CounterMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.HistogramMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
 
 import java.io.IOException;
 import java.util.HashMap;
@@ -73,39 +79,60 @@ public class OpenTelemetryMetricRequestProcessor implements Service {
             .build();
     private List<PrometheusMetricConverter> converters;
 
+    @Getter(lazy = true)
+    private final MetricsCreator metricsCreator = manager.find(TelemetryModule.NAME).provider().getService(MetricsCreator.class);
+
+    @Getter(lazy = true)
+    private final CounterMetrics receivedCounter = getMetricsCreator().createCounter(
+        "otel_metrics_received",
+        "The number of metrics received by the OTLP receiver",
+        MetricsTag.EMPTY_KEY,
+        MetricsTag.EMPTY_VALUE
+    );
+    @Getter(lazy = true)
+    private final HistogramMetrics processHistogram = getMetricsCreator().createHistogramMetric(
+        "otel_metrics_latency",
+        "The latency to process the metrics request",
+        MetricsTag.EMPTY_KEY,
+        MetricsTag.EMPTY_VALUE
+    );
+
     public void processMetricsRequest(final ExportMetricsServiceRequest requests) {
-        requests.getResourceMetricsList().forEach(request -> {
-            if (log.isDebugEnabled()) {
-                log.debug("Resource attributes: {}", request.getResource().getAttributesList());
-            }
+        getReceivedCounter().inc();
+
+        try (final var unused = getProcessHistogram().createTimer()) {
+            requests.getResourceMetricsList().forEach(request -> {
+                if (log.isDebugEnabled()) {
+                    log.debug("Resource attributes: {}", request.getResource().getAttributesList());
+                }
 
-            final Map<String, String> nodeLabels =
-                request
-                    .getResource()
-                    .getAttributesList()
-                    .stream()
-                    .collect(toMap(
-                        it -> LABEL_MAPPINGS
+                final Map<String, String> nodeLabels =
+                    request
+                        .getResource()
+                        .getAttributesList()
+                        .stream()
+                        .collect(toMap(
+                            it -> LABEL_MAPPINGS
                             .getOrDefault(it.getKey(), it.getKey())
                             .replaceAll("\\.", "_"),
-                        it -> anyValueToString(it.getValue()),
+                            it -> anyValueToString(it.getValue()),
                         (v1, v2) -> v1
-                    ));
-
-            converters
-                .forEach(convert -> convert.toMeter(
-                    request
-                        .getScopeMetricsList().stream()
-                        .flatMap(scopeMetrics -> scopeMetrics
-                            .getMetricsList().stream()
-                            .flatMap(metric -> adaptMetrics(nodeLabels, metric))
-                            .map(Function1.liftTry(Function.identity()))
-                            .flatMap(tryIt -> MetricConvert.log(
-                                tryIt,
-                                "Convert OTEL metric to prometheus metric"
-                            )))));
-        });
+                        ));
 
+                converters
+                    .forEach(convert -> convert.toMeter(
+                        request
+                            .getScopeMetricsList().stream()
+                            .flatMap(scopeMetrics -> scopeMetrics
+                                .getMetricsList().stream()
+                                .flatMap(metric -> adaptMetrics(nodeLabels, metric))
+                                .map(Function1.liftTry(Function.identity()))
+                                .flatMap(tryIt -> MetricConvert.log(
+                                    tryIt,
+                                    "Convert OTEL metric to prometheus metric"
+                                )))));
+            });
+        }
     }
 
     public void start() throws ModuleStartException {
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHandler.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHandler.java
index 18e76bee34..93c2546ef1 100644
--- a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHandler.java
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHandler.java
@@ -30,6 +30,7 @@ import io.opentelemetry.proto.common.v1.KeyValue;
 import io.opentelemetry.proto.resource.v1.Resource;
 import io.opentelemetry.proto.trace.v1.ScopeSpans;
 import io.opentelemetry.proto.trace.v1.Status;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
@@ -40,6 +41,11 @@ import org.apache.skywalking.oap.server.receiver.otel.Handler;
 import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
 import org.apache.skywalking.oap.server.receiver.zipkin.SpanForwardService;
 import org.apache.skywalking.oap.server.receiver.zipkin.ZipkinReceiverModule;
+import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
+import org.apache.skywalking.oap.server.telemetry.api.CounterMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.HistogramMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
 import zipkin2.Endpoint;
 import zipkin2.Span;
 
@@ -64,6 +70,24 @@ public class OpenTelemetryTraceHandler
     private final ModuleManager manager;
     private SpanForwardService forwardService;
 
+    @Getter(lazy = true)
+    private final MetricsCreator metricsCreator = manager.find(TelemetryModule.NAME).provider().getService(MetricsCreator.class);
+
+    @Getter(lazy = true)
+    private final CounterMetrics receivedCounter = getMetricsCreator().createCounter(
+        "otel_spans_received",
+        "The number of span request received by the OTLP receiver",
+        MetricsTag.EMPTY_KEY,
+        MetricsTag.EMPTY_VALUE
+    );
+    @Getter(lazy = true)
+    private final HistogramMetrics processHistogram = getMetricsCreator().createHistogramMetric(
+        "otel_spans_latency",
+        "The latency to process the span request",
+        MetricsTag.EMPTY_KEY,
+        MetricsTag.EMPTY_VALUE
+    );
+
     @Override
     public String type() {
         return "otlp-traces";
@@ -79,33 +103,37 @@ public class OpenTelemetryTraceHandler
 
     @Override
     public void export(ExportTraceServiceRequest request, StreamObserver<ExportTraceServiceResponse> responseObserver) {
+        getReceivedCounter().inc();
+
         final ArrayList<Span> result = new ArrayList<>();
-        request.getResourceSpansList().forEach(resourceSpans -> {
-            final Resource resource = resourceSpans.getResource();
-            final List<ScopeSpans> scopeSpansList = resourceSpans.getScopeSpansList();
-            if (resource.getAttributesCount() == 0 && scopeSpansList.size() == 0) {
-                return;
-            }
 
-            final Map<String, String> resourceTags = convertAttributeToMap(resource.getAttributesList());
-            String serviceName = extractZipkinServiceName(resourceTags);
-            if (StringUtil.isEmpty(serviceName)) {
-                log.warn("No service name found in resource attributes, discarding the trace");
-                return;
-            }
+        try (final var unused = getProcessHistogram().createTimer()) {
+            request.getResourceSpansList().forEach(resourceSpans -> {
+                final Resource resource = resourceSpans.getResource();
+                final List<ScopeSpans> scopeSpansList = resourceSpans.getScopeSpansList();
+                if (resource.getAttributesCount() == 0 && scopeSpansList.size() == 0) {
+                    return;
+                }
+                final Map<String, String> resourceTags = convertAttributeToMap(resource.getAttributesList());
+                String serviceName = extractZipkinServiceName(resourceTags);
+                if (StringUtil.isEmpty(serviceName)) {
+                    log.warn("No service name found in resource attributes, discarding the trace");
+                    return;
+                }
 
-            try {
-                for (ScopeSpans scopeSpans : scopeSpansList) {
-                    extractScopeTag(scopeSpans.getScope(), resourceTags);
-                    for (io.opentelemetry.proto.trace.v1.Span span : scopeSpans.getSpansList()) {
-                        Span zipkinSpan = convertSpan(span, serviceName, resourceTags);
-                        result.add(zipkinSpan);
+                try {
+                    for (ScopeSpans scopeSpans : scopeSpansList) {
+                        extractScopeTag(scopeSpans.getScope(), resourceTags);
+                        for (io.opentelemetry.proto.trace.v1.Span span : scopeSpans.getSpansList()) {
+                            Span zipkinSpan = convertSpan(span, serviceName, resourceTags);
+                            result.add(zipkinSpan);
+                        }
                     }
+                } catch (Exception e) {
+                    log.warn("convert span error, discarding the span: {}", e.getMessage());
                 }
-            } catch (Exception e) {
-                log.warn("convert span error, discarding the span: {}", e.getMessage());
-            }
-        });
+            });
+        }
 
         getForwardService().send(result);
         responseObserver.onNext(ExportTraceServiceResponse.getDefaultInstance());
diff --git a/oap-server/server-starter/src/main/resources/otel-rules/oap.yaml b/oap-server/server-starter/src/main/resources/otel-rules/oap.yaml
index 6de0e00b53..aed86ae8e6 100644
--- a/oap-server/server-starter/src/main/resources/otel-rules/oap.yaml
+++ b/oap-server/server-starter/src/main/resources/otel-rules/oap.yaml
@@ -37,15 +37,17 @@ metricsRules:
   - name: instance_jvm_memory_bytes_used
     exp: jvm_memory_bytes_used.sum(['service', 'host_name'])
   - name: instance_jvm_gc_count
-    exp: "jvm_gc_collection_seconds_count.tagMatch('gc', 'PS Scavenge|Copy|ParNew|G1 Young Generation|PS MarkSweep|MarkSweepCompact|ConcurrentMarkSweep|G1 Old Generation')
-    .sum(['service', 'host_name', 'gc']).increase('PT1M')
-    .tag({tags -> if (tags['gc'] == 'PS Scavenge' || tags['gc'] == 'Copy' || tags['gc'] == 'ParNew' || tags['gc'] == 'G1 Young Generation') {tags.gc = 'young_gc_count'} })
-    .tag({tags -> if (tags['gc'] == 'PS MarkSweep' || tags['gc'] == 'MarkSweepCompact' || tags['gc'] == 'ConcurrentMarkSweep' || tags['gc'] == 'G1 Old Generation') {tags.gc = 'old_gc_count'} })"
+    exp: >
+      jvm_gc_collection_seconds_count.tagMatch('gc', 'PS Scavenge|Copy|ParNew|G1 Young Generation|PS MarkSweep|MarkSweepCompact|ConcurrentMarkSweep|G1 Old Generation')
+      .sum(['service', 'host_name', 'gc']).increase('PT1M')
+      .tag({tags -> if (tags['gc'] == 'PS Scavenge' || tags['gc'] == 'Copy' || tags['gc'] == 'ParNew' || tags['gc'] == 'G1 Young Generation') {tags.gc = 'young_gc_count'} })
+      .tag({tags -> if (tags['gc'] == 'PS MarkSweep' || tags['gc'] == 'MarkSweepCompact' || tags['gc'] == 'ConcurrentMarkSweep' || tags['gc'] == 'G1 Old Generation') {tags.gc = 'old_gc_count'} })
   - name: instance_jvm_gc_time
-    exp: "(jvm_gc_collection_seconds_sum * 1000).tagMatch('gc', 'PS Scavenge|Copy|ParNew|G1 Young Generation|PS MarkSweep|MarkSweepCompact|ConcurrentMarkSweep|G1 Old Generation')
-    .sum(['service', 'host_name', 'gc']).increase('PT1M')
-    .tag({tags -> if (tags['gc'] == 'PS Scavenge' || tags['gc'] == 'Copy' || tags['gc'] == 'ParNew' || tags['gc'] == 'G1 Young Generation') {tags.gc = 'young_gc_time'} })
-    .tag({tags -> if (tags['gc'] == 'PS MarkSweep' || tags['gc'] == 'MarkSweepCompact' || tags['gc'] == 'ConcurrentMarkSweep' || tags['gc'] == 'G1 Old Generation') {tags.gc = 'old_gc_time'} })"
+    exp: >
+      (jvm_gc_collection_seconds_sum * 1000).tagMatch('gc', 'PS Scavenge|Copy|ParNew|G1 Young Generation|PS MarkSweep|MarkSweepCompact|ConcurrentMarkSweep|G1 Old Generation')
+      .sum(['service', 'host_name', 'gc']).increase('PT1M')
+      .tag({tags -> if (tags['gc'] == 'PS Scavenge' || tags['gc'] == 'Copy' || tags['gc'] == 'ParNew' || tags['gc'] == 'G1 Young Generation') {tags.gc = 'young_gc_time'} })
+      .tag({tags -> if (tags['gc'] == 'PS MarkSweep' || tags['gc'] == 'MarkSweepCompact' || tags['gc'] == 'ConcurrentMarkSweep' || tags['gc'] == 'G1 Old Generation') {tags.gc = 'old_gc_time'} })
   - name: instance_trace_count
     exp: trace_in_latency_count.sum(['service', 'host_name']).increase('PT1M')
   - name: instance_trace_latency_percentile
@@ -59,8 +61,9 @@ metricsRules:
   - name: instance_mesh_analysis_error_count
     exp: mesh_analysis_error_count.sum(['service', 'host_name']).increase('PT1M')
   - name: instance_metrics_aggregation
-    exp: "metrics_aggregation.tagEqual('dimensionality', 'minute').sum(['service', 'host_name', 'level']).increase('PT1M')
-    .tag({tags -> if (tags['level'] == '1') {tags.level = 'L1 aggregation'} }).tag({tags -> if (tags['level'] == '2') {tags.level = 'L2 aggregation'} })"
+    exp: >
+      metrics_aggregation.tagEqual('dimensionality', 'minute').sum(['service', 'host_name', 'level']).increase('PT1M')
+      .tag({tags -> if (tags['level'] == '1') {tags.level = 'L1 aggregation'} }).tag({tags -> if (tags['level'] == '2') {tags.level = 'L2 aggregation'} })
   - name: instance_persistence_execute_percentile
     exp: persistence_timer_bulk_execute_latency.sum(['le', 'service', 'host_name']).increase('PT5M').histogram().histogram_percentile([50,70,90,99])
   - name: instance_persistence_prepare_percentile
@@ -99,3 +102,15 @@ metricsRules:
     exp: k8s_als_drop_count.sum(['service', 'host_name']).increase('PT1M')
   - name: instance_k8s_als_latency_percentile
     exp: k8s_als_in_latency.sum(['le', 'service', 'host_name']).increase('PT1M').histogram().histogram_percentile([50,70,90,99])
+  - name: otel_metrics_received
+    exp: otel_metrics_received.sum(['service', 'host_name']).increase('PT1M')
+  - name: otel_logs_received
+    exp: otel_logs_received.sum(['service', 'host_name']).increase('PT1M')
+  - name: otel_spans_received
+    exp: otel_spans_received.sum(['service', 'host_name']).increase('PT1M')
+  - name: otel_metrics_latency_percentile
+    exp: otel_metrics_latency.sum(['le', 'service', 'host_name']).increase('PT1M').histogram().histogram_percentile([50,70,90,99])
+  - name: otel_logs_latency_percentile
+    exp: otel_logs_latency.sum(['le', 'service', 'host_name']).increase('PT1M').histogram().histogram_percentile([50,70,90,99])
+  - name: otel_spans_latency_percentile
+    exp: otel_spans_latency.sum(['le', 'service', 'host_name']).increase('PT1M').histogram().histogram_percentile([50,70,90,99])
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json
index 090d3de9e2..078e704883 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json
@@ -467,6 +467,148 @@
                   "expressions": [
                     "relabels(meter_oap_instance_k8s_als_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',percentile='50,75,90,95,99')"
                   ]
+                },
+                {
+                  "x": 12,
+                  "y": 13,
+                  "w": 6,
+                  "h": 13,
+                  "i": "19",
+                  "type": "Widget",
+                  "expressions": [
+                    "meter_oap_otel_metrics_received"
+                  ],
+                  "graph": {
+                    "type": "Line",
+                    "step": false,
+                    "smooth": false,
+                    "showSymbol": true,
+                    "showXAxis": true,
+                    "showYAxis": true
+                  },
+                  "widget": {
+                    "title": "OpenTelemetry Metrics (Request / Second)"
+                  },
+                  "metricConfig": [
+                    {
+                      "label": "Received Requests"
+                    }
+                  ]
+                },
+                {
+                  "x": 12,
+                  "y": 26,
+                  "w": 6,
+                  "h": 13,
+                  "i": "20",
+                  "type": "Widget",
+                  "expressions": [
+                    "meter_oap_otel_logs_received"
+                  ],
+                  "graph": {
+                    "type": "Line",
+                    "step": false,
+                    "smooth": false,
+                    "showSymbol": true,
+                    "showXAxis": true,
+                    "showYAxis": true
+                  },
+                  "widget": {
+                    "title": "OpenTelemetry Logs (Request / Second)"
+                  }
+                },
+                {
+                  "x": 0,
+                  "y": 26,
+                  "w": 6,
+                  "h": 13,
+                  "i": "21",
+                  "type": "Widget",
+                  "expressions": [
+                    "meter_oap_otel_spans_received"
+                  ],
+                  "graph": {
+                    "type": "Line",
+                    "step": false,
+                    "smooth": false,
+                    "showSymbol": true,
+                    "showXAxis": true,
+                    "showYAxis": true
+                  },
+                  "widget": {
+                    "title": "OpenTelemetry Spans (Request / Second)"
+                  },
+                  "metricConfig": [
+                    {
+                      "unit": "Request / Second"
+                    }
+                  ]
+                },
+                {
+                  "x": 18,
+                  "y": 13,
+                  "w": 6,
+                  "h": 13,
+                  "i": "22",
+                  "type": "Widget",
+                  "expressions": [
+                    "relabels(meter_oap_otel_metrics_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',percentile='50,75,90,95,99')"
+                  ],
+                  "graph": {
+                    "type": "Line",
+                    "step": false,
+                    "smooth": false,
+                    "showSymbol": true,
+                    "showXAxis": true,
+                    "showYAxis": true
+                  },
+                  "widget": {
+                    "title": "OpenTelemetry Metrics Latency"
+                  }
+                },
+                {
+                  "x": 6,
+                  "y": 26,
+                  "w": 6,
+                  "h": 13,
+                  "i": "23",
+                  "type": "Widget",
+                  "expressions": [
+                    "relabels(meter_oap_otel_spans_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',percentile='50,75,90,95,99')"
+                  ],
+                  "graph": {
+                    "type": "Line",
+                    "step": false,
+                    "smooth": false,
+                    "showSymbol": true,
+                    "showXAxis": true,
+                    "showYAxis": true
+                  },
+                  "widget": {
+                    "title": "OpenTelemetry Spans Latency"
+                  }
+                },
+                {
+                  "x": 18,
+                  "y": 26,
+                  "w": 6,
+                  "h": 13,
+                  "i": "24",
+                  "type": "Widget",
+                  "expressions": [
+                    "relabels(meter_oap_otel_logs_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',percentile='50,75,90,95,99')"
+                  ],
+                  "graph": {
+                    "type": "Line",
+                    "step": false,
+                    "smooth": false,
+                    "showSymbol": true,
+                    "showXAxis": true,
+                    "showYAxis": true
+                  },
+                  "widget": {
+                    "title": "OpenTelemetry Logs Latency"
+                  }
                 }
               ]
             }