Skip to content

Commit 473752a

Browse files
committed
Add gRPC export for profiles signal type.
1 parent a01bf6c commit 473752a

File tree

7 files changed

+632
-0
lines changed

7 files changed

+632
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.otlp.profiles;
7+
8+
// A Java object to correspond to the gRPC response for the ProfilesService.Export method. If fields
9+
// are added to the type in the future, this can be converted to an actual class.
10+
//
11+
// It may seem like Void could be used instead but gRPC does not allow response values to be
12+
// null.
13+
enum ExportProfilesServiceResponse {
14+
INSTANCE;
15+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.otlp.profiles;
7+
8+
import static io.grpc.MethodDescriptor.generateFullMethodName;
9+
10+
import com.google.common.util.concurrent.ListenableFuture;
11+
import io.grpc.CallOptions;
12+
import io.grpc.Channel;
13+
import io.grpc.MethodDescriptor;
14+
import io.grpc.stub.ClientCalls;
15+
import io.opentelemetry.exporter.internal.grpc.MarshalerInputStream;
16+
import io.opentelemetry.exporter.internal.grpc.MarshalerServiceStub;
17+
import io.opentelemetry.exporter.internal.marshal.Marshaler;
18+
import java.io.InputStream;
19+
import javax.annotation.Nullable;
20+
21+
// Adapted from the protoc generated code for ProfilesServiceGrpc.
22+
final class MarshalerProfilesServiceGrpc {
23+
24+
private static final String SERVICE_NAME =
25+
"opentelemetry.proto.collector.profiles.v1development.ProfilesService";
26+
27+
private static final MethodDescriptor.Marshaller<Marshaler> REQUEST_MARSHALLER =
28+
new MethodDescriptor.Marshaller<Marshaler>() {
29+
@Override
30+
public InputStream stream(Marshaler value) {
31+
return new MarshalerInputStream(value);
32+
}
33+
34+
@Override
35+
public Marshaler parse(InputStream stream) {
36+
throw new UnsupportedOperationException("Only for serializing");
37+
}
38+
};
39+
40+
private static final MethodDescriptor.Marshaller<ExportProfilesServiceResponse>
41+
RESPONSE_MARSHALER =
42+
new MethodDescriptor.Marshaller<ExportProfilesServiceResponse>() {
43+
@Override
44+
public InputStream stream(ExportProfilesServiceResponse value) {
45+
throw new UnsupportedOperationException("Only for parsing");
46+
}
47+
48+
@Override
49+
public ExportProfilesServiceResponse parse(InputStream stream) {
50+
return ExportProfilesServiceResponse.INSTANCE;
51+
}
52+
};
53+
54+
private static final MethodDescriptor<Marshaler, ExportProfilesServiceResponse> getExportMethod =
55+
MethodDescriptor.<Marshaler, ExportProfilesServiceResponse>newBuilder()
56+
.setType(MethodDescriptor.MethodType.UNARY)
57+
.setFullMethodName(generateFullMethodName(SERVICE_NAME, "Export"))
58+
.setRequestMarshaller(REQUEST_MARSHALLER)
59+
.setResponseMarshaller(RESPONSE_MARSHALER)
60+
.build();
61+
62+
static ProfilesServiceFutureStub newFutureStub(
63+
Channel channel, @Nullable String authorityOverride) {
64+
return ProfilesServiceFutureStub.newStub(
65+
(c, options) -> new ProfilesServiceFutureStub(c, options.withAuthority(authorityOverride)),
66+
channel);
67+
}
68+
69+
static final class ProfilesServiceFutureStub
70+
extends MarshalerServiceStub<
71+
Marshaler, ExportProfilesServiceResponse, ProfilesServiceFutureStub> {
72+
private ProfilesServiceFutureStub(Channel channel, CallOptions callOptions) {
73+
super(channel, callOptions);
74+
}
75+
76+
@Override
77+
protected MarshalerProfilesServiceGrpc.ProfilesServiceFutureStub build(
78+
Channel channel, CallOptions callOptions) {
79+
return new MarshalerProfilesServiceGrpc.ProfilesServiceFutureStub(channel, callOptions);
80+
}
81+
82+
@Override
83+
public ListenableFuture<ExportProfilesServiceResponse> export(Marshaler request) {
84+
return ClientCalls.futureUnaryCall(
85+
getChannel().newCall(getExportMethod, getCallOptions()), request);
86+
}
87+
}
88+
89+
private MarshalerProfilesServiceGrpc() {}
90+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.otlp.profiles;
7+
8+
import io.opentelemetry.sdk.common.CompletableResultCode;
9+
import java.util.ArrayList;
10+
import java.util.Arrays;
11+
import java.util.Collection;
12+
import java.util.List;
13+
import java.util.logging.Level;
14+
import java.util.logging.Logger;
15+
16+
/**
17+
* {@link ProfilesExporter} that forwards all received data to a list of {@link ProfilesExporter}s.
18+
*/
19+
final class MultiProfilesExporter implements ProfilesExporter {
20+
private static final Logger logger = Logger.getLogger(MultiProfilesExporter.class.getName());
21+
22+
private final ProfilesExporter[] profilesExporters;
23+
24+
/**
25+
* Constructs and returns an instance of this class.
26+
*
27+
* @param profilesExporters the exporters data should be sent to
28+
* @return the aggregate data exporter
29+
*/
30+
static ProfilesExporter create(List<ProfilesExporter> profilesExporters) {
31+
return new MultiProfilesExporter(profilesExporters.toArray(new ProfilesExporter[0]));
32+
}
33+
34+
@Override
35+
public CompletableResultCode export(Collection<ProfileData> items) {
36+
List<CompletableResultCode> results = new ArrayList<>(profilesExporters.length);
37+
for (ProfilesExporter profilesExporter : profilesExporters) {
38+
CompletableResultCode exportResult;
39+
try {
40+
exportResult = profilesExporter.export(items);
41+
} catch (RuntimeException e) {
42+
// If an exception was thrown by the exporter
43+
logger.log(Level.WARNING, "Exception thrown by the export.", e);
44+
results.add(CompletableResultCode.ofFailure());
45+
continue;
46+
}
47+
results.add(exportResult);
48+
}
49+
return CompletableResultCode.ofAll(results);
50+
}
51+
52+
/**
53+
* Flushes the data of all registered {@link ProfilesExporter}s.
54+
*
55+
* @return the result of the operation
56+
*/
57+
@Override
58+
public CompletableResultCode flush() {
59+
List<CompletableResultCode> results = new ArrayList<>(profilesExporters.length);
60+
for (ProfilesExporter profilesExporter : profilesExporters) {
61+
CompletableResultCode flushResult;
62+
try {
63+
flushResult = profilesExporter.flush();
64+
} catch (RuntimeException e) {
65+
// If an exception was thrown by the exporter
66+
logger.log(Level.WARNING, "Exception thrown by the flush.", e);
67+
results.add(CompletableResultCode.ofFailure());
68+
continue;
69+
}
70+
results.add(flushResult);
71+
}
72+
return CompletableResultCode.ofAll(results);
73+
}
74+
75+
@Override
76+
public CompletableResultCode shutdown() {
77+
List<CompletableResultCode> results = new ArrayList<>(profilesExporters.length);
78+
for (ProfilesExporter profilesExporter : profilesExporters) {
79+
CompletableResultCode shutdownResult;
80+
try {
81+
shutdownResult = profilesExporter.shutdown();
82+
} catch (RuntimeException e) {
83+
// If an exception was thrown by the exporter
84+
logger.log(Level.WARNING, "Exception thrown by the shutdown.", e);
85+
results.add(CompletableResultCode.ofFailure());
86+
continue;
87+
}
88+
results.add(shutdownResult);
89+
}
90+
return CompletableResultCode.ofAll(results);
91+
}
92+
93+
private MultiProfilesExporter(ProfilesExporter[] profilesExporters) {
94+
this.profilesExporters = profilesExporters;
95+
}
96+
97+
@Override
98+
public String toString() {
99+
return "MultiProfilesExporter{"
100+
+ "profilesExporters="
101+
+ Arrays.toString(profilesExporters)
102+
+ '}';
103+
}
104+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.otlp.profiles;
7+
8+
import io.opentelemetry.sdk.common.CompletableResultCode;
9+
import java.util.Collection;
10+
11+
final class NoopProfilesExporter implements ProfilesExporter {
12+
13+
private static final ProfilesExporter INSTANCE = new NoopProfilesExporter();
14+
15+
static ProfilesExporter getInstance() {
16+
return INSTANCE;
17+
}
18+
19+
@Override
20+
public CompletableResultCode export(Collection<ProfileData> spans) {
21+
return CompletableResultCode.ofSuccess();
22+
}
23+
24+
@Override
25+
public CompletableResultCode flush() {
26+
return CompletableResultCode.ofSuccess();
27+
}
28+
29+
@Override
30+
public CompletableResultCode shutdown() {
31+
return CompletableResultCode.ofSuccess();
32+
}
33+
34+
@Override
35+
public String toString() {
36+
return "NoopProfilesExporter{}";
37+
}
38+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.otlp.profiles;
7+
8+
import io.opentelemetry.exporter.internal.grpc.GrpcExporter;
9+
import io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder;
10+
import io.opentelemetry.exporter.internal.marshal.Marshaler;
11+
import io.opentelemetry.sdk.common.CompletableResultCode;
12+
import java.util.Collection;
13+
import java.util.StringJoiner;
14+
import javax.annotation.concurrent.ThreadSafe;
15+
16+
/** Exports profiles using OTLP via gRPC, using OpenTelemetry's protobuf model. */
17+
@ThreadSafe
18+
public class OtlpGrpcProfilesExporter implements ProfilesExporter {
19+
20+
private final GrpcExporterBuilder<Marshaler> builder;
21+
private final GrpcExporter<Marshaler> delegate;
22+
23+
/**
24+
* Returns a new {@link OtlpGrpcProfilesExporter} using the default values.
25+
*
26+
* <p>To load configuration values from environment variables and system properties, use <a
27+
* href="https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure">opentelemetry-sdk-extension-autoconfigure</a>.
28+
*
29+
* @return a new {@link OtlpGrpcProfilesExporter} instance.
30+
*/
31+
public static OtlpGrpcProfilesExporter getDefault() {
32+
return builder().build();
33+
}
34+
35+
/**
36+
* Returns a new builder instance for this exporter.
37+
*
38+
* @return a new builder instance for this exporter.
39+
*/
40+
public static OtlpGrpcProfilesExporterBuilder builder() {
41+
return new OtlpGrpcProfilesExporterBuilder();
42+
}
43+
44+
OtlpGrpcProfilesExporter(
45+
GrpcExporterBuilder<Marshaler> builder, GrpcExporter<Marshaler> delegate) {
46+
this.builder = builder;
47+
this.delegate = delegate;
48+
}
49+
50+
/**
51+
* Returns a builder with configuration values equal to those for this exporter.
52+
*
53+
* <p>IMPORTANT: Be sure to {@link #shutdown()} this instance if it will no longer be used.
54+
*/
55+
public OtlpGrpcProfilesExporterBuilder toBuilder() {
56+
return new OtlpGrpcProfilesExporterBuilder(builder.copy());
57+
}
58+
59+
/**
60+
* Submits all the given profiles in a single batch to the OpenTelemetry collector.
61+
*
62+
* @param profiles the list of sampled profiles to be exported.
63+
* @return the result of the operation
64+
*/
65+
@Override
66+
public CompletableResultCode export(Collection<ProfileData> profiles) {
67+
ProfilesRequestMarshaler request = ProfilesRequestMarshaler.create(profiles);
68+
return delegate.export(request, profiles.size());
69+
}
70+
71+
/**
72+
* The OTLP exporter does not batch items, so this method will immediately return with success.
73+
*
74+
* @return always Success
75+
*/
76+
@Override
77+
public CompletableResultCode flush() {
78+
return CompletableResultCode.ofSuccess();
79+
}
80+
81+
/**
82+
* Initiates an orderly shutdown in which preexisting calls continue but new calls are immediately
83+
* cancelled.
84+
*/
85+
@Override
86+
public CompletableResultCode shutdown() {
87+
return delegate.shutdown();
88+
}
89+
90+
@Override
91+
public String toString() {
92+
StringJoiner joiner = new StringJoiner(", ", "OtlpGrpcProfilesExporter{", "}");
93+
joiner.add(builder.toString(false));
94+
return joiner.toString();
95+
}
96+
}

0 commit comments

Comments
 (0)