Skip to content

Conversation

@jack-berg
Copy link
Member

@jack-berg jack-berg commented Oct 22, 2025

Resolves #6718.

Promote the HttpSender, GrpcSender interfaces to the public API. There's a lot. Summary:

  • We need to hide Marshaler and related APIs, since they balloon the API surface area and would take lot of work to get ready for public. Introducing narrow focused MessageWriter to serve the function currently performed by Marshaler.
  • Need to get rid of MarshalerServiceStub and related APIs from the gRPC senders stuff. It drags in a bunch of unnecessary cruft and io.grpc.stub dependency.
  • Need to hide the HttpSenderConfig#getExportAsJson() option. Senders don't need to be burdened with understanding whether the request is binary or JSON. They just need to be told the content type and a way to write the request body.
  • Compressor and related APIs need to get promoted as well.
  • Need to refine GrpcSenderConfig, HttpSenderConfig
    • Need to be interfaces instead of autovalue classes
    • Need javadoc
    • Make endpoint URI instead of string
    • Provide grpc senders the fully qualified service name and method name
    • Hide the Object GrpcSenderConfig#getManagedChannel(), which is required for backwards compatibility and for UpstreamGrpcSender, behind an internal-only ExtendedGrpcSenderConfig

@brunobat
Copy link
Contributor

brunobat commented Nov 6, 2025

@jack-berg, I didn't forgot this issue. I'm planning to give you a response in the week of Nov. 17.

Copy link
Contributor

@brunobat brunobat left a comment

Choose a reason for hiding this comment

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

@jack-berg, thanks very much for this.
The end user changes are fair enough and after updating the Quarkus code, it worked out of the box and the IT tests with a real OTel Collector pass.
I'm adding a couple of comments.

Copy link
Contributor

@brunobat brunobat left a comment

Choose a reason for hiding this comment

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

I've taken a look at the declarative config being proposed. We currently don't use it but I have a few comments.

@zeitlinger
Copy link
Member

The end user changes are fair enough and after updating the Quarkus code

Why is this relavant for Quarkus? I'm asking because the spring starter doesn't care - and I'm trying to understand what the difference is

@jack-berg
Copy link
Member Author

I've taken a look at the declarative config being proposed.

There's actually nothing in here related to declarative config. The getters in HttpSenderConfig, GrpcSenderConfig reflect the standard configuration options we expose via programmatic config for OTLP exporters (e.g. OtlpHttpSpanExporterBuilder, OtlpGrpcSpanExporterBuilder).

As the set of configuration options we expose via the Otlp{Signal}{Protocol}ExporterBuilders evolves, HttpSenderConfig and GrpcSenderConfig will evolve along side.

I would say that if a sender ignores any of those options, its technically not compliant. Non-compliant doesn't mean its not useful, but it does mean that the sender isn't able to behave like the user expects based on how they configured the builder.

@brunobat
Copy link
Contributor

brunobat commented Nov 25, 2025

The end user changes are fair enough and after updating the Quarkus code

Why is this relavant for Quarkus? I'm asking because the spring starter doesn't care - and I'm trying to understand what the difference is

Because Quarkus has it's own senders based on a Vert.x client. It does not use OkHttp. See #6718 and its comments for more details.

@brunobat
Copy link
Contributor

I've taken a look at the declarative config being proposed.

There's actually nothing in here related to declarative config. The getters in HttpSenderConfig, GrpcSenderConfig reflect the standard configuration options we expose via programmatic config for OTLP exporters (e.g. OtlpHttpSpanExporterBuilder, OtlpGrpcSpanExporterBuilder).

As the set of configuration options we expose via the Otlp{Signal}{Protocol}ExporterBuilders evolves, HttpSenderConfig and GrpcSenderConfig will evolve along side.

I would say that if a sender ignores any of those options, its technically not compliant. Non-compliant doesn't mean its not useful, but it does mean that the sender isn't able to behave like the user expects based on how they configured the builder.

Thanks for the explanation @jack-berg.
If those properties are not used, the compliance is left to the implementator.
As in the other properties, we always try to match the property behavior, even if properties are handled by Quarkus and some behavior is not implemented directly on the SDK. We have other examples with samplers and several customizations we provide for the SDK.
The Idea is to melt the OTel experience into Quarkus and have minimal friction for people with knowledge of both frameworks.

@jack-berg
Copy link
Member Author

Ok so it seems like something close to this will work for quarkus. There are still some small tweaks (example), but its mostly correct.

The next step will be to coordinate with @jkwatson and @open-telemetry/java-approvers to choose a strategy and schedule to get this merged. I opened this as one big PR to make the whole picture clear, but I'm happy to break it up in smaller more reviewable pieces as long as we can commit to work quickly to get all those pieces merged for a single release. This will be important to minimize churn.

Copy link
Member

@trask trask left a comment

Choose a reason for hiding this comment

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

(got through the easy 75/94 files in this first round)

@brunobat
Copy link
Contributor

brunobat commented Jan 8, 2026

Hi @jack-berg Any news about the split of this work into several PRs?

@trask
Copy link
Member

trask commented Jan 8, 2026

I agreed to review this one big PR. Once @jack-berg addresses the first round of comments I'll make the next pass.

@jack-berg
Copy link
Member Author

Thanks for the poke @trask - will clean this up, incorporate your first round of fedback, and mark it ready for review.

@codecov
Copy link

codecov bot commented Jan 8, 2026

Codecov Report

❌ Patch coverage is 85.71429% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.12%. Comparing base (a15659d) to head (4a4757e).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...orter/sender/okhttp/internal/OkHttpGrpcSender.java 60.86% 8 Missing and 1 partial ⚠️
...ension/trace/jaeger/sampler/OkHttpGrpcService.java 54.54% 3 Missing and 2 partials ⚠️
...pc/managedchannel/internal/UpstreamGrpcSender.java 91.11% 2 Missing and 2 partials ⚠️
...edchannel/internal/UpstreamGrpcSenderProvider.java 71.42% 2 Missing and 2 partials ⚠️
...y/exporter/internal/grpc/MarshalerInputStream.java 57.14% 3 Missing ⚠️
...telemetry/exporter/internal/marshal/Marshaler.java 50.00% 1 Missing and 2 partials ⚠️
...orter/sender/okhttp/internal/OkHttpHttpSender.java 85.00% 3 Missing ⚠️
...io/opentelemetry/exporter/grpc/GrpcStatusCode.java 92.30% 1 Missing and 1 partial ⚠️
...a/io/opentelemetry/exporter/grpc/GrpcResponse.java 0.00% 1 Missing ⚠️
...a/io/opentelemetry/exporter/http/HttpResponse.java 0.00% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff            @@
##               main    #7782   +/-   ##
=========================================
  Coverage     90.12%   90.12%           
- Complexity     7468     7481   +13     
=========================================
  Files           834      834           
  Lines         22589    22601   +12     
  Branches       2239     2250   +11     
=========================================
+ Hits          20359    20370   +11     
+ Misses         1529     1527    -2     
- Partials        701      704    +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jack-berg jack-berg marked this pull request as ready for review January 8, 2026 23:05
@jack-berg jack-berg requested a review from a team as a code owner January 8, 2026 23:05
@jack-berg
Copy link
Member Author

Ready for review. Updated the description to match the current state of things.

Copy link
Member

@trask trask left a comment

Choose a reason for hiding this comment

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

(just the next round)

public abstract class ImmutableGrpcResponse implements GrpcResponse {

public static ImmutableGrpcResponse create(
GrpcStatusCode grpcStatusCode, @Nullable String grpcStatusDescription, byte[] responseBody) {
Copy link
Member

Choose a reason for hiding this comment

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

(just to match the accessors)

Suggested change
GrpcStatusCode grpcStatusCode, @Nullable String grpcStatusDescription, byte[] responseBody) {
GrpcStatusCode statusCode, @Nullable String statusDescription, byte[] responseMessage) {

/** Write the message to the {@link OutputStream}. */
void writeMessage(OutputStream output) throws IOException;

/** Return the message length in bytes. */
Copy link
Member

Choose a reason for hiding this comment

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

something about returning -1 in some cases?

this.methodDescriptor =
MethodDescriptor.<MessageWriter, byte[]>newBuilder()
.setType(MethodDescriptor.MethodType.UNARY)
.setFullMethodName(serviceAndMethodName)
Copy link
Member

Choose a reason for hiding this comment

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

wdyt of renaming serviceAndMethodName everywhere to fullMethodName? (fwiw grpc defines grpc.method attribute as the full method name: https://github.com/grpc/proposal/blob/master/A66-otel-stats.md#attributes)

@Override
public InputStream stream(SamplingStrategyParametersMarshaler value) {
return new MarshalerInputStream(value);
return new MarshalerInputStream(value.toMessageWriter(false));
Copy link
Member

Choose a reason for hiding this comment

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

maybe worth toJsonMessageWriter to avoid the boolean flag? realize it's internal so not important (not even sure if it's a good idea)

return new OkHttpGrpcSender(
grpcSenderConfig
.getEndpoint()
.resolve("/" + grpcSenderConfig.getServiceAndMethodName())
Copy link
Member

Choose a reason for hiding this comment

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

I don't think the / should be needed

Suggested change
.resolve("/" + grpcSenderConfig.getServiceAndMethodName())
.resolve(grpcSenderConfig.getServiceAndMethodName())

Copy link
Member Author

Choose a reason for hiding this comment

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

The build was falling without it! Couldn't recreate it locally. Need to dig into it more.

Copy link
Member Author

Choose a reason for hiding this comment

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

The build was falling without it! Couldn't recreate it locally. Need to dig into it more.

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.

Make the exporter sender a public SPI

4 participants