Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON export option #4435

Merged

Conversation

jonahaapala
Copy link
Contributor

I am working on adding JSON support for the New Relic OTLP Metrics consumer and while writing functional tests (written in Java) to exercise the new protocol I noticed that there wasn't an OOTB way to configure the OkHttpExporter to send payloads as JSON. For now I've copied the classes I need and changed them like I have in this PR, but figured it would be a nice addition to the opentelemetry-java project as it's not too much code and makes testing more convenient.

I recognize that clients will want to configure themselves to send things as Protobuf, but it might be nice to have the JSON option if only for testing. I wanted to just add the option to the OkHttpExporter (which is what we use directly in our tests) so that it wouldn't need to be exposed in the OtlpHttpMetricExporterBuilder, but the existing tests seem to exercise the OkHttpExporter via the OtlpHttpMetricExporterBuilder so I added the extra wiring to keep testing similar.

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented May 4, 2022

CLA Signed

The committers listed above are authorized under a signed CLA.

import okhttp3.RequestBody;
import okio.BufferedSink;

public class JsonRequestBody extends RequestBody {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pretty much a copy paste of ProtoResponseBody

Copy link
Member

Choose a reason for hiding this comment

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

I believe this can be package private, and final. (ProtoResponseBody can be package private as well.)

@codecov
Copy link

codecov bot commented May 4, 2022

Codecov Report

Merging #4435 (3b77cf7) into main (6606020) will decrease coverage by 0.00%.
The diff coverage is 100.00%.

@@             Coverage Diff              @@
##               main    #4435      +/-   ##
============================================
- Coverage     90.02%   90.02%   -0.01%     
- Complexity     4970     4979       +9     
============================================
  Files           570      571       +1     
  Lines         15384    15401      +17     
  Branches       1472     1473       +1     
============================================
+ Hits          13850    13864      +14     
- Misses         1064     1067       +3     
  Partials        470      470              
Impacted Files Coverage Δ
...try/exporter/internal/okhttp/ProtoRequestBody.java 100.00% <ø> (ø)
...lp/http/metrics/OtlpHttpMetricExporterBuilder.java 100.00% <100.00%> (ø)
...etry/exporter/internal/okhttp/JsonRequestBody.java 100.00% <100.00%> (ø)
...metry/exporter/internal/okhttp/OkHttpExporter.java 95.23% <100.00%> (+0.07%) ⬆️
...xporter/internal/okhttp/OkHttpExporterBuilder.java 90.00% <100.00%> (+0.63%) ⬆️
...entelemetry/exporter/jaeger/PostSpansResponse.java 0.00% <0.00%> (-100.00%) ⬇️
...exporter/jaeger/MarshalerCollectorServiceGrpc.java 85.71% <0.00%> (-4.77%) ⬇️
...ava/io/opentelemetry/micrometer1shim/Bridging.java 100.00% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6606020...3b77cf7. Read the comment docs.

@jonahaapala
Copy link
Contributor Author

I have signed the CLA, not sure when the PR will update with that fact though.


/** Creates a new {@link JsonRequestBody}. */
public JsonRequestBody(Marshaler marshaler) {
preserializedJson = preserializeJson(marshaler);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Initially I wanted to save off the marshaler like ProtoResponseBody does and substitute writeBinaryTo() with writeJsonTo() in the overridden writeTo() method below. However there wasn't an equivalent method for getting the contentLength like ProtoResponseBody does in its constructor, so this seemed like the simplest way to do this with the existing code at my disposal.

I copied the implementation from MarshalerUtil.preserializeJsonFields() but omit the part that trims the beginning and ending brackets.

Copy link
Contributor

Choose a reason for hiding this comment

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

How about just sticking with -1 for contentLength without preserializing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting. I initially didn't think we could leave the contentLength unset because we do some validation on our end to see that it is a positive value. But I don't see anything in the spec that indicates the Content-Length header must be set and I don't see anything in our code that relies on it other than for monitoring. Asking my team for any context around this choice, but so far I'm inclined to do as you suggest and return -1.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though, might I ask, is there a downside to leaving this as is? I think it's just a matter of when this serialization logic gets called. It's a bit wasteful to do it this way as there is an extra copy cost to transfer the bytes into the final buffer, but I don't think by very much.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not a big deal either way if only for tests - but OkHttp's intended usage is to "do work" on its I/O thread, so it's a bit more correct to do serialization within writeTo, whereas preserialization in the constructor is serializing on the hot path in principle (not if it's a test, but otherwise it would be).

@jonahaapala
Copy link
Contributor Author

Using these changes locally I was able to verify that it exports as proper JSON that can be parsed by our consumers.

@jonahaapala jonahaapala closed this May 4, 2022
@jonahaapala jonahaapala reopened this May 4, 2022
@jonahaapala
Copy link
Contributor Author

/easycla

@jonahaapala
Copy link
Contributor Author

\easycla

@jonahaapala
Copy link
Contributor Author

easycla

@jonahaapala jonahaapala force-pushed the jhaapala/add-json-export-option branch from 4d66f31 to 0d2b580 Compare May 6, 2022 16:53
@@ -117,6 +117,11 @@ public OtlpHttpMetricExporterBuilder setAggregationTemporality(
return this;
}

OtlpHttpMetricExporterBuilder exportAsJson() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

not exposing as a public API. Keeping the one on OkHttpExporterBuilder public though for testing purposes.

@@ -70,4 +70,9 @@ public static ExporterMetrics createGrpcOkHttp(String type, MeterProvider meterP
public static ExporterMetrics createHttpProtobuf(String type, MeterProvider meterProvider) {
return new ExporterMetrics(meterProvider.get("io.opentelemetry.exporters.otlp-http"), type);
}

public static ExporterMetrics createHttpJson(String type, MeterProvider meterProvider) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is only really for testing anyways, we probably don't need a separate metrics for it


/** Creates a new {@link JsonRequestBody}. */
public JsonRequestBody(Marshaler marshaler) {
preserializedJson = preserializeJson(marshaler);
Copy link
Contributor

Choose a reason for hiding this comment

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

How about just sticking with -1 for contentLength without preserializing?

@jonahaapala jonahaapala force-pushed the jhaapala/add-json-export-option branch from 0d2b580 to 4fdbc5c Compare May 9, 2022 22:49
README.md Outdated
| Logs SDK | v<!--VERSION_UNSTABLE-->1.15.0-SNAPSHOT-alpha<!--/VERSION_UNSTABLE--> |
| Prometheus Metrics Exporter | v<!--VERSION_UNSTABLE-->1.15.0-SNAPSHOT-alpha<!--/VERSION_UNSTABLE--> |
| OpenTracing Bridge | v<!--VERSION_UNSTABLE-->1.15.0-SNAPSHOT-alpha<!--/VERSION_UNSTABLE--> |
| OpenCensus Bridge | v<!--VERSION_UNSTABLE-->1.15.0-SNAPSHOT-alpha<!--/VERSION_UNSTABLE--> |
Copy link
Contributor Author

Choose a reason for hiding this comment

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

yikes, idk what's going on with this and all of the apidiffs updates. This is what the ./gradlew check did...

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry about that @jonahaapala, you got caught in a race condition with our release. I pushed a commit to this branch to pull in HEAD to fix it

@anuraaga anuraaga mentioned this pull request May 10, 2022
@jonahaapala
Copy link
Contributor Author

@anuraaga thanks for the review! What are the next steps now that you've approved? I don't have the ability to merge this. Are we waiting on more approvers?

Copy link
Member

@jack-berg jack-berg 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 minor comment about package privacy.

@jack-berg jack-berg merged commit 20bd019 into open-telemetry:main May 11, 2022
@jonahaapala jonahaapala deleted the jhaapala/add-json-export-option branch May 17, 2022 17:51
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.

None yet

3 participants