Skip to content

Otel metrics source http service#6604

Merged
KarstenSchnitter merged 6 commits intoopensearch-project:mainfrom
sternadsoftware:otel-metrics-source-http-service
Mar 17, 2026
Merged

Otel metrics source http service#6604
KarstenSchnitter merged 6 commits intoopensearch-project:mainfrom
sternadsoftware:otel-metrics-source-http-service

Conversation

@TomasLongo
Copy link
Copy Markdown
Contributor

Description

Introduce HTTP/protobuf and HTTP/JSON support for OTel Metrics source.
Adds endpoint to receive OTLP data over HTTP. Aligns with similar support
for OTelTraceSource.

Issues Resolved

Check List

  • New functionality includes testing.
  • New functionality has a documentation issue. Please link to it in this PR.
    • New functionality has javadoc added
  • Commits are signed with a real name per the DCO

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@TomasLongo TomasLongo force-pushed the otel-metrics-source-http-service branch 3 times, most recently from b702577 to 7083df5 Compare March 5, 2026 11:37
@TomasLongo
Copy link
Copy Markdown
Contributor Author

Note: I added the E2E Test for the metrics source to the log sub module in the e2e-test project.

It seemed a bit of an overkill to me to create a new module. Especially, since the already present tests for logs really just cover the happy path of the process.

I'd suggest to rename the log module to signals (or something similar) to encourage adding basic e2e tests that cover signals in that module.

More specialized/complex use cases can still be put into separate modules.

@TomasLongo TomasLongo force-pushed the otel-metrics-source-http-service branch from 7083df5 to 48d9981 Compare March 5, 2026 12:21
@kaimst kaimst force-pushed the otel-metrics-source-http-service branch from bed11cb to 117d402 Compare March 6, 2026 09:41
Integrates an HTTP (non-gRPC) service into the OTel metrics source plugin,
mirroring the existing pattern from otel_trace_source and otel_logs_source.
Both gRPC and HTTP services now run on the same Armeria server.

Key changes:
- Add ArmeriaHttpService for handling HTTP metric export requests
- Add HttpExceptionHandler for HTTP-specific error handling
- Support compression, authentication, throttling, and health checks for HTTP
- Add configurable http_path option
- Refactor OTelMetricsSource to directly configure the server
- Remove ConvertConfiguration (inlined into source)
- Split monolithic test into focused test classes (gRPC, HTTP, RetryInfo)
- Add E2E tests for HTTP, gRPC, protobuf, and unframed requests

Signed-off-by: Tomas Longo <tlongo@sternad.de>
Signed-off-by: Kai Sternad <kai@sternad.de>
@kaimst kaimst force-pushed the otel-metrics-source-http-service branch from d7121b8 to 01df9df Compare March 6, 2026 12:39
kaimst added 3 commits March 6, 2026 13:55
Signed-off-by: Kai Sternad <kai@sternad.de>
  1. createServer() — configureHttpService() is now guarded with if (getHttpPath() != null), preventing the NPE
  2. HTTP health check — moved from configureHttpService() into createServer(), so it registers when either httpPath or enableUnframedRequests is set (matching the OTelLogsSource pattern)
  3. configureHttpService() — removed the duplicate health check registration

Signed-off-by: Kai Sternad <kai@sternad.de>
Signed-off-by: Kai Sternad <kai@sternad.de>
Copy link
Copy Markdown
Collaborator

@KarstenSchnitter KarstenSchnitter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for providing this PR. This already looks pretty good. I found some minor issues with that.

Comment on lines +58 to +67
public static final int DEFAULT_REQUEST_TIMEOUT_MS = 10000;
public static final int DEFAULT_PORT = 21891;
public static final int DEFAULT_THREAD_COUNT = 200;
public static final int DEFAULT_MAX_CONNECTION_COUNT = 500;
public static final boolean DEFAULT_SSL = true;
public static final boolean DEFAULT_ENABLED_UNFRAMED_REQUESTS = false;
public static final boolean DEFAULT_HEALTH_CHECK = false;
public static final boolean DEFAULT_PROTO_REFLECTION_SERVICE = false;
public static final boolean DEFAULT_USE_ACM_CERT_FOR_SSL = false;
public static final int DEFAULT_ACM_CERT_ISSUE_TIME_OUT_MILLIS = 120000;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do these constants need to be public now? Can't they keep the scope they had before?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@JsonProperty(RETRY_INFO)
private RetryInfoConfig retryInfo;

@JsonProperty("http_path")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"http_path" should probably be extracted to a constant similar to all other property names.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ScheduledThreadPoolExecutor executor = configureServer(serverBuilder);

configureGrpcService(serverBuilder, buffer);
if (oTelMetricsSourceConfig.getHttpPath() != null) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly, that the gRPC endpoint is always created but the HTTP endpoint relies on the definition of a path? Or is there alway a default path making this check pass always? I am wondering on the different checks for logs, metrics and traces to configure the HTTP endpoint:

  • metrics: see above
  • logs: always
  • traces: if unframed requests is not true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should unify http-service creation.

If I'm not mistaken, we haven't had a discussion for the trace-source to flesh out the exact mechanic how we want to treat the creation of the two services:

  • should both be mandatory?
  • should they be optional, in which case we would need to make sure that at least one service is configured?
  • [other approaches]

Any preferences?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's create an issue in this project to discuss this. The behaviour should be aligned. This will be necessary for adding the support to the OTelSource later on.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KarstenSchnitter Regarding the inconsistency across the three sources: metrics and logs have been aligned with the latest commit. Both gate the HTTP endpoint on httpPath != null:

if (!oTelTraceSourceConfig.enableUnframedRequests()) HTTP is created by default, when unframed_requests is enabled, the gRPC service itself accepts plain HTTP/JSON requests, making a separate HTTP endpoint redundant.

The HTTP health check condition is also aligned now between metrics and logs: both use (enableUnframedRequests || httpPath != null) && healthCheck.

/**
* Returns the used thread pool. Can be used by other parts of the server configuration
*/
private @NonNull ScheduledThreadPoolExecutor configureServer(ServerBuilder serverBuilder) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange naming considering the return value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, wasn't happy either.

I pulled out the creation of the task executor.

.exceptionHandler(createGrpcExceptionHandler(oTelMetricsSourceConfig));
final OTelMetricsGrpcService oTelmetricsGrpcService = new OTelMetricsGrpcService(
(int) (oTelMetricsSourceConfig.getRequestTimeoutInMillis() * 0.8),
oTelMetricsSourceConfig.getOutputFormat() == OTelOutputFormat.OPENSEARCH ? new OTelProtoOpensearchCodec.OTelProtoDecoder() : new OTelProtoStandardCodec.OTelProtoDecoder(),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
oTelMetricsSourceConfig.getOutputFormat() == OTelOutputFormat.OPENSEARCH ? new OTelProtoOpensearchCodec.OTelProtoDecoder() : new OTelProtoStandardCodec.OTelProtoDecoder(),
createOtelProtoDecoder(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomasLongo did you missed this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I thought you were reviewing an outdated version.

Everything's good on my machine 🤷 . This is what I see locally and git tells me, that everything is up to date.

Image

What do you see on your machine?

Comment thread RELEASING.md
}

@Test
void start_with_Health_configured_includes_HealthCheck_service() throws IOException {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use CamelCase naming adjust the other tests as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


@ParameterizedTest
@MethodSource("getPathParams")
void httpRequest_writesToBuffer_returnsSuccessfulResponse(String givenPath, String resolvedRequestPath) throws Exception {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use CamelCase naming. Please adjust the other tests as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Signed-off-by: Tomas Longo <tlongo@sternad.de>
@TomasLongo TomasLongo force-pushed the otel-metrics-source-http-service branch from bd48863 to a818f7a Compare March 11, 2026 09:15
Copy link
Copy Markdown
Collaborator

@KarstenSchnitter KarstenSchnitter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for applying the latest changes. There are still two open comments, can you address those as well? Please also comment on the failing tests: Is this caused by this PR or by other factors?

ScheduledThreadPoolExecutor executor = configureServer(serverBuilder);

configureGrpcService(serverBuilder, buffer);
if (oTelMetricsSourceConfig.getHttpPath() != null) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's create an issue in this project to discuss this. The behaviour should be aligned. This will be necessary for adding the support to the OTelSource later on.

Comment thread RELEASING.md
Comment on lines +66 to +75
#### Update the version of DataPrepperVersion

If you have just created a release branch, you should also create a PR on the `main` branch to bump the version in `DataPrepperVersion`.

Steps:
1. Modify the `DataPrepperVersion` class to update `CURRENT_VERSION` to the next version.
2. Create a PR targeting `main`

Note: This step can be automated through [#4877](https://github.com/opensearch-project/data-prepper/issues/4877).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still looks like an accidental change. Are you sure this should be contained in this PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. The file doesn't appear in the changeset.

I thought the accidental change was the removal of the section.

.exceptionHandler(createGrpcExceptionHandler(oTelMetricsSourceConfig));
final OTelMetricsGrpcService oTelmetricsGrpcService = new OTelMetricsGrpcService(
(int) (oTelMetricsSourceConfig.getRequestTimeoutInMillis() * 0.8),
oTelMetricsSourceConfig.getOutputFormat() == OTelOutputFormat.OPENSEARCH ? new OTelProtoOpensearchCodec.OTelProtoDecoder() : new OTelProtoStandardCodec.OTelProtoDecoder(),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomasLongo did you missed this?

Signed-off-by: Kai Sternad <kai@sternad.de>
Copy link
Copy Markdown
Collaborator

@KarstenSchnitter KarstenSchnitter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. @dlvenable or @kkondaka do you have anything against this?

@KarstenSchnitter KarstenSchnitter merged commit bb61dbe into opensearch-project:main Mar 17, 2026
70 of 72 checks passed
graytaylor0 added a commit to graytaylor0/data-prepper that referenced this pull request Mar 19, 2026
graytaylor0 added a commit to graytaylor0/data-prepper that referenced this pull request Mar 19, 2026
Signed-off-by: Taylor Gray <tylgry@amazon.com>
This reverts commit bb61dbe.
graytaylor0 added a commit that referenced this pull request Mar 19, 2026
This reverts commit bb61dbe.

Signed-off-by: Taylor Gray <tylgry@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants