You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2026/04/16 07:40:38 UTC
(skywalking) 01/01: Add OTLP/HTTP receiver support for traces, logs, and metrics
This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch feature/otlp-http-receiver
in repository https://gitbox.apache.org/repos/asf/skywalking.git
commit ed9eb3543a06860b5083f3126557ba05b71b0cde
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Thu Apr 16 14:55:07 2026 +0800
Add OTLP/HTTP receiver support for traces, logs, and metrics
Each existing OTLP gRPC handler now also registers an HTTP handler
at startup. Supported endpoints:
- POST /v1/traces (protobuf + JSON)
- POST /v1/logs (protobuf + JSON)
- POST /v1/metrics (protobuf + JSON)
Processing logic extracted into shared processExport() methods
called by both gRPC and HTTP handlers. No new config needed —
HTTP endpoints are automatically available when the OTLP handler
is enabled.
Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
---
docs/en/changes/changes.md | 1 +
docs/en/setup/backend/otlp-trace.md | 13 +++-
.../otel/otlp/OpenTelemetryLogHTTPHandler.java | 85 ++++++++++++++++++++++
.../otel/otlp/OpenTelemetryLogHandler.java | 21 +++++-
.../otel/otlp/OpenTelemetryMetricHTTPHandler.java | 85 ++++++++++++++++++++++
.../otel/otlp/OpenTelemetryMetricHandler.java | 10 +++
.../otel/otlp/OpenTelemetryTraceHTTPHandler.java | 85 ++++++++++++++++++++++
.../otel/otlp/OpenTelemetryTraceHandler.java | 22 +++++-
8 files changed, 316 insertions(+), 6 deletions(-)
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 8ba337cd97..36cd8bc134 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -28,6 +28,7 @@
* LAL: add `sourceAttribute()` function for non-persistent OTLP resource attribute access in LAL scripts.
* LAL: add `layer: auto` mode for dynamic layer assignment when `service.layer` is absent.
* Add two-phase `SpanListener` SPI mechanism for extensible trace span processing. Refactor GenAI from hardcoded `SpanForward.processGenAILogic()` to `GenAISpanListener`.
+* Add OTLP/HTTP receiver support for traces, logs, and metrics (`/v1/traces`, `/v1/logs`, `/v1/metrics`). Supports both `application/x-protobuf` and `application/json` content types.
#### UI
diff --git a/docs/en/setup/backend/otlp-trace.md b/docs/en/setup/backend/otlp-trace.md
index 6afd5f984a..8bf250556b 100644
--- a/docs/en/setup/backend/otlp-trace.md
+++ b/docs/en/setup/backend/otlp-trace.md
@@ -1,10 +1,21 @@
# OpenTelemetry Trace Format
-SkyWalking can receive traces from Traces in OTLP format and convert them to Zipkin Trace format eventually.
+SkyWalking can receive traces from Traces in OTLP format and convert them to Zipkin Trace format eventually.
For data analysis and queries related to Zipkin Trace, please [refer to the relevant documentation](./zipkin-trace.md#zipkin-query).
OTLP Trace handler references the [Zipkin Exporter in the OpenTelemetry Collector](https://opentelemetry.io/docs/specs/otel/trace/sdk_exporters/zipkin/#summary) to convert the data format.
+## Supported Protocols
+
+Both **OTLP/gRPC** and **OTLP/HTTP** are supported:
+
+| Protocol | Port | Endpoint |
+|----------|------|----------|
+| OTLP/gRPC | 11800 (shared gRPC port) | gRPC `TraceService/Export` |
+| OTLP/HTTP | 12800 (shared HTTP port) | `POST /v1/traces` |
+
+OTLP/HTTP supports both `application/x-protobuf` and `application/json` content types.
+
## Set up backend receiver
1. Make sure to enable **otlp-traces** handler in OTLP receiver of `application.yml`.
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHTTPHandler.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHTTPHandler.java
new file mode 100644
index 0000000000..9b2dab70a2
--- /dev/null
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryLogHTTPHandler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.skywalking.oap.server.receiver.otel.otlp;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.util.JsonFormat;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.server.annotation.Consumes;
+import com.linecorp.armeria.server.annotation.ConsumesJson;
+import com.linecorp.armeria.server.annotation.Post;
+import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest;
+import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * OTLP/HTTP handler for log data. Supports both protobuf and JSON encoding.
+ * Delegates processing to {@link OpenTelemetryLogHandler#processExport}.
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class OpenTelemetryLogHTTPHandler {
+ private static final byte[] EMPTY_RESPONSE =
+ ExportLogsServiceResponse.getDefaultInstance().toByteArray();
+
+ private final OpenTelemetryLogHandler logHandler;
+
+ @Post("/v1/logs")
+ @Consumes("application/x-protobuf")
+ public HttpResponse collectProtobuf(HttpRequest req) {
+ return HttpResponse.from(req.aggregate().thenApply(request -> {
+ try (final HttpData data = request.content()) {
+ final ExportLogsServiceRequest exportRequest =
+ ExportLogsServiceRequest.parseFrom(data.byteBuf().nioBuffer());
+ logHandler.processExport(exportRequest);
+ return HttpResponse.of(HttpStatus.OK, MediaType.PROTOBUF, EMPTY_RESPONSE);
+ } catch (InvalidProtocolBufferException e) {
+ log.warn("Failed to parse OTLP/HTTP log request", e);
+ return HttpResponse.of(HttpStatus.BAD_REQUEST);
+ } catch (Exception e) {
+ log.error("Failed to process OTLP/HTTP log request", e);
+ return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }));
+ }
+
+ @Post("/v1/logs")
+ @ConsumesJson
+ public HttpResponse collectJson(HttpRequest req) {
+ return HttpResponse.from(req.aggregate().thenApply(request -> {
+ try (final HttpData data = request.content()) {
+ final ExportLogsServiceRequest.Builder builder =
+ ExportLogsServiceRequest.newBuilder();
+ JsonFormat.parser().merge(data.toStringUtf8(), builder);
+ logHandler.processExport(builder.build());
+ return HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{}");
+ } catch (InvalidProtocolBufferException e) {
+ log.warn("Failed to parse OTLP/HTTP JSON log request", e);
+ return HttpResponse.of(HttpStatus.BAD_REQUEST);
+ } catch (Exception e) {
+ log.error("Failed to process OTLP/HTTP JSON log request", e);
+ return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }));
+ }
+}
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 5f7983083d..4f7ae66b0e 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
@@ -36,7 +36,10 @@ import org.apache.skywalking.apm.network.logging.v3.TextLog;
import org.apache.skywalking.oap.server.core.source.LogMetadataUtils;
import org.apache.skywalking.oap.log.analyzer.v2.module.LogAnalyzerModule;
import org.apache.skywalking.oap.log.analyzer.v2.provider.log.ILogAnalyzerService;
+import com.linecorp.armeria.common.HttpMethod;
+import java.util.Collections;
import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.HTTPHandlerRegister;
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;
@@ -88,10 +91,26 @@ public class OpenTelemetryLogHandler
.provider()
.getService(GRPCHandlerRegister.class);
grpcHandlerRegister.addHandler(this);
+
+ HTTPHandlerRegister httpHandlerRegister = manager.find(SharingServerModule.NAME)
+ .provider()
+ .getService(HTTPHandlerRegister.class);
+ httpHandlerRegister.addHandler(
+ new OpenTelemetryLogHTTPHandler(this),
+ Collections.singletonList(HttpMethod.POST));
}
@Override
public void export(ExportLogsServiceRequest request, StreamObserver<ExportLogsServiceResponse> responseObserver) {
+ processExport(request);
+ responseObserver.onNext(ExportLogsServiceResponse.getDefaultInstance());
+ responseObserver.onCompleted();
+ }
+
+ /**
+ * Process an OTLP log export request. Shared by both gRPC and HTTP handlers.
+ */
+ void processExport(ExportLogsServiceRequest request) {
request.getResourceLogsList().forEach(resourceLogs -> {
final var resource = resourceLogs.getResource();
final var attributes = resource
@@ -122,8 +141,6 @@ public class OpenTelemetryLogHandler
}
});
});
- responseObserver.onNext(ExportLogsServiceResponse.getDefaultInstance());
- responseObserver.onCompleted();
}
private void doAnalysisQuietly(String service, String layer, String serviceInstance,
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHTTPHandler.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHTTPHandler.java
new file mode 100644
index 0000000000..4dbdb4e86e
--- /dev/null
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHTTPHandler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.skywalking.oap.server.receiver.otel.otlp;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.util.JsonFormat;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.server.annotation.Consumes;
+import com.linecorp.armeria.server.annotation.ConsumesJson;
+import com.linecorp.armeria.server.annotation.Post;
+import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
+import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * OTLP/HTTP handler for metric data. Supports both protobuf and JSON encoding.
+ * Delegates processing to {@link OpenTelemetryMetricRequestProcessor#processMetricsRequest}.
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class OpenTelemetryMetricHTTPHandler {
+ private static final byte[] EMPTY_RESPONSE =
+ ExportMetricsServiceResponse.getDefaultInstance().toByteArray();
+
+ private final OpenTelemetryMetricRequestProcessor metricProcessor;
+
+ @Post("/v1/metrics")
+ @Consumes("application/x-protobuf")
+ public HttpResponse collectProtobuf(HttpRequest req) {
+ return HttpResponse.from(req.aggregate().thenApply(request -> {
+ try (final HttpData data = request.content()) {
+ final ExportMetricsServiceRequest exportRequest =
+ ExportMetricsServiceRequest.parseFrom(data.byteBuf().nioBuffer());
+ metricProcessor.processMetricsRequest(exportRequest);
+ return HttpResponse.of(HttpStatus.OK, MediaType.PROTOBUF, EMPTY_RESPONSE);
+ } catch (InvalidProtocolBufferException e) {
+ log.warn("Failed to parse OTLP/HTTP metric request", e);
+ return HttpResponse.of(HttpStatus.BAD_REQUEST);
+ } catch (Exception e) {
+ log.error("Failed to process OTLP/HTTP metric request", e);
+ return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }));
+ }
+
+ @Post("/v1/metrics")
+ @ConsumesJson
+ public HttpResponse collectJson(HttpRequest req) {
+ return HttpResponse.from(req.aggregate().thenApply(request -> {
+ try (final HttpData data = request.content()) {
+ final ExportMetricsServiceRequest.Builder builder =
+ ExportMetricsServiceRequest.newBuilder();
+ JsonFormat.parser().merge(data.toStringUtf8(), builder);
+ metricProcessor.processMetricsRequest(builder.build());
+ return HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{}");
+ } catch (InvalidProtocolBufferException e) {
+ log.warn("Failed to parse OTLP/HTTP JSON metric request", e);
+ return HttpResponse.of(HttpStatus.BAD_REQUEST);
+ } catch (Exception e) {
+ log.error("Failed to process OTLP/HTTP JSON metric request", e);
+ return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }));
+ }
+}
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHandler.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHandler.java
index 5c69711ee6..d1abb2bf87 100644
--- a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHandler.java
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryMetricHandler.java
@@ -23,7 +23,10 @@ import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse;
import io.opentelemetry.proto.collector.metrics.v1.MetricsServiceGrpc;
import lombok.extern.slf4j.Slf4j;
+import com.linecorp.armeria.common.HttpMethod;
+import java.util.Collections;
import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.HTTPHandlerRegister;
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;
@@ -58,6 +61,13 @@ public class OpenTelemetryMetricHandler
.provider()
.getService(GRPCHandlerRegister.class);
grpcHandlerRegister.addHandler(this);
+
+ HTTPHandlerRegister httpHandlerRegister = manager.find(SharingServerModule.NAME)
+ .provider()
+ .getService(HTTPHandlerRegister.class);
+ httpHandlerRegister.addHandler(
+ new OpenTelemetryMetricHTTPHandler(metricRequestProcessor),
+ Collections.singletonList(HttpMethod.POST));
}
@Override
diff --git a/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHTTPHandler.java b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHTTPHandler.java
new file mode 100644
index 0000000000..cd1d016e6b
--- /dev/null
+++ b/oap-server/server-receiver-plugin/otel-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/otel/otlp/OpenTelemetryTraceHTTPHandler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.skywalking.oap.server.receiver.otel.otlp;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.util.JsonFormat;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.server.annotation.Consumes;
+import com.linecorp.armeria.server.annotation.ConsumesJson;
+import com.linecorp.armeria.server.annotation.Post;
+import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
+import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * OTLP/HTTP handler for trace data. Supports both protobuf and JSON encoding.
+ * Delegates processing to {@link OpenTelemetryTraceHandler#processExport}.
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class OpenTelemetryTraceHTTPHandler {
+ private static final byte[] EMPTY_RESPONSE =
+ ExportTraceServiceResponse.getDefaultInstance().toByteArray();
+
+ private final OpenTelemetryTraceHandler traceHandler;
+
+ @Post("/v1/traces")
+ @Consumes("application/x-protobuf")
+ public HttpResponse collectProtobuf(HttpRequest req) {
+ return HttpResponse.from(req.aggregate().thenApply(request -> {
+ try (final HttpData data = request.content()) {
+ final ExportTraceServiceRequest exportRequest =
+ ExportTraceServiceRequest.parseFrom(data.byteBuf().nioBuffer());
+ traceHandler.processExport(exportRequest);
+ return HttpResponse.of(HttpStatus.OK, MediaType.PROTOBUF, EMPTY_RESPONSE);
+ } catch (InvalidProtocolBufferException e) {
+ log.warn("Failed to parse OTLP/HTTP trace request", e);
+ return HttpResponse.of(HttpStatus.BAD_REQUEST);
+ } catch (Exception e) {
+ log.error("Failed to process OTLP/HTTP trace request", e);
+ return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }));
+ }
+
+ @Post("/v1/traces")
+ @ConsumesJson
+ public HttpResponse collectJson(HttpRequest req) {
+ return HttpResponse.from(req.aggregate().thenApply(request -> {
+ try (final HttpData data = request.content()) {
+ final ExportTraceServiceRequest.Builder builder =
+ ExportTraceServiceRequest.newBuilder();
+ JsonFormat.parser().merge(data.toStringUtf8(), builder);
+ traceHandler.processExport(builder.build());
+ return HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{}");
+ } catch (InvalidProtocolBufferException e) {
+ log.warn("Failed to parse OTLP/HTTP JSON trace request", e);
+ return HttpResponse.of(HttpStatus.BAD_REQUEST);
+ } catch (Exception e) {
+ log.error("Failed to process OTLP/HTTP JSON trace request", e);
+ return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }));
+ }
+}
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 6e769eb288..a03e9a4045 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
@@ -35,7 +35,10 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.trace.SpanListenerManager;
import org.apache.skywalking.oap.server.core.trace.SpanListenerResult;
+import com.linecorp.armeria.common.HttpMethod;
+import java.util.Collections;
import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.HTTPHandlerRegister;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
import org.apache.skywalking.oap.server.library.module.ModuleStartException;
import org.apache.skywalking.oap.server.library.util.StringUtil;
@@ -107,10 +110,26 @@ public class OpenTelemetryTraceHandler
.provider()
.getService(GRPCHandlerRegister.class);
grpcHandlerRegister.addHandler(this);
+
+ HTTPHandlerRegister httpHandlerRegister = manager.find(SharingServerModule.NAME)
+ .provider()
+ .getService(HTTPHandlerRegister.class);
+ httpHandlerRegister.addHandler(
+ new OpenTelemetryTraceHTTPHandler(this),
+ Collections.singletonList(HttpMethod.POST));
}
@Override
public void export(ExportTraceServiceRequest request, StreamObserver<ExportTraceServiceResponse> responseObserver) {
+ processExport(request);
+ responseObserver.onNext(ExportTraceServiceResponse.getDefaultInstance());
+ responseObserver.onCompleted();
+ }
+
+ /**
+ * Process an OTLP trace export request. Shared by both gRPC and HTTP handlers.
+ */
+ void processExport(ExportTraceServiceRequest request) {
final ArrayList<Span> result = new ArrayList<>();
try (final var unused = getProcessHistogram().createTimer()) {
@@ -167,9 +186,6 @@ public class OpenTelemetryTraceHandler
getDroppedSpans().inc(result.size() - processedSpans.size());
}
}
-
- responseObserver.onNext(ExportTraceServiceResponse.getDefaultInstance());
- responseObserver.onCompleted();
}
private Span convertSpan(io.opentelemetry.proto.trace.v1.Span span, String serviceName, Map<String, String> resourceTags) {