Skip to content

Commit 6b320ff

Browse files
committed
Create a bridge to instanciate StandardComponentId objects
1 parent 1dadceb commit 6b320ff

File tree

6 files changed

+154
-21
lines changed

6 files changed

+154
-21
lines changed

bom/application/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<resteasy-microprofile.version>3.0.1.Final</resteasy-microprofile.version>
3030
<resteasy-spring-web.version>3.2.0.Final</resteasy-spring-web.version>
3131
<resteasy.version>6.2.12.Final</resteasy.version>
32-
<opentelemetry-instrumentation.version>2.15.0-alpha</opentelemetry-instrumentation.version> <!-- OTel SDk 1.49.0-->
32+
<opentelemetry-instrumentation.version>2.17.1-alpha</opentelemetry-instrumentation.version> <!-- OTel SDk 1.51.0-->
3333
<opentelemetry-semconv.version>1.32.0-alpha</opentelemetry-semconv.version>
3434
<quarkus-http.version>5.3.5</quarkus-http.version>
3535
<micrometer.version>1.14.7</micrometer.version><!-- keep in sync with hdrhistogram: https://central.sonatype.com/artifact/io.micrometer/micrometer-core -->

extensions/opentelemetry/deployment/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
<groupId>io.quarkus</groupId>
3030
<artifactId>quarkus-arc-deployment</artifactId>
3131
</dependency>
32+
<dependency>
33+
<groupId>io.quarkus.gizmo</groupId>
34+
<artifactId>gizmo2</artifactId>
35+
</dependency>
3236
<dependency>
3337
<groupId>io.quarkus</groupId>
3438
<artifactId>quarkus-vertx-deployment</artifactId>

extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.function.BooleanSupplier;
88
import java.util.logging.Level;
99

10+
import jakarta.enterprise.context.ApplicationScoped;
1011
import jakarta.enterprise.inject.Instance;
1112
import jakarta.inject.Singleton;
1213

@@ -15,22 +16,31 @@
1516
import org.jboss.jandex.DotName;
1617
import org.jboss.jandex.ParameterizedType;
1718
import org.jboss.jandex.Type;
19+
import org.objectweb.asm.Opcodes;
1820

21+
import io.opentelemetry.sdk.internal.StandardComponentId;
1922
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
2023
import io.opentelemetry.sdk.metrics.export.MetricExporter;
2124
import io.opentelemetry.sdk.trace.SpanProcessor;
2225
import io.opentelemetry.sdk.trace.export.SpanExporter;
2326
import io.quarkus.arc.deployment.BeanDiscoveryFinishedBuildItem;
27+
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
28+
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
2429
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
2530
import io.quarkus.arc.deployment.ValidationPhaseBuildItem;
31+
import io.quarkus.arc.processor.MethodDescriptors;
2632
import io.quarkus.deployment.annotations.*;
2733
import io.quarkus.deployment.annotations.Record;
2834
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
2935
import io.quarkus.deployment.builditem.LogCategoryBuildItem;
3036
import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem;
37+
import io.quarkus.gizmo.ClassCreator;
38+
import io.quarkus.gizmo.MethodCreator;
39+
import io.quarkus.gizmo.MethodDescriptor;
3140
import io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig;
3241
import io.quarkus.opentelemetry.runtime.config.build.exporter.OtlpExporterBuildConfig;
3342
import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterConfigBuilder;
43+
import io.quarkus.opentelemetry.runtime.exporter.otlp.ExporterBridge;
3444
import io.quarkus.opentelemetry.runtime.exporter.otlp.OTelExporterRecorder;
3545
import io.quarkus.opentelemetry.runtime.exporter.otlp.tracing.LateBoundSpanProcessor;
3646
import io.quarkus.runtime.configuration.ConfigurationException;
@@ -44,6 +54,7 @@ public class OtlpExporterProcessor {
4454
private static final DotName METRIC_EXPORTER = DotName.createSimple(MetricExporter.class.getName());
4555
private static final DotName LOG_RECORD_EXPORTER = DotName.createSimple(LogRecordExporter.class.getName());
4656
private static final DotName OKHTTP_INTERCEPTOR = DotName.createSimple("okhttp3.Interceptor");
57+
private static final String BRIDGE_NAME = "io.opentelemetry.sdk.internal.StandardComponentIdBridge";
4758

4859
static class OtlpTracingExporterEnabled implements BooleanSupplier {
4960
OtlpExporterBuildConfig exportBuildConfig;
@@ -109,6 +120,59 @@ private boolean isTracesOtlp(OTelBuildConfig otelBuildConfig) {
109120
}
110121
}
111122

123+
/**
124+
* Make constructor public for io.opentelemetry.sdk.internal.StandardComponentId
125+
*
126+
* <pre>
127+
* @ApplicationScoped
128+
* public class StandardComponentIdBridge implements ExporterBridge {
129+
* public StandardComponentIdBridge() {
130+
* }
131+
*
132+
* public StandardComponentId createStandardComponentId(StandardComponentId.ExporterType standardType) {
133+
* return new StandardComponentId(standardType);
134+
* }
135+
* }
136+
* </pre>
137+
*/
138+
@BuildStep
139+
void generateBridgeService(BuildProducer<GeneratedBeanBuildItem> generatedBeanClasses) {
140+
// Create a ClassOutput instance
141+
GeneratedBeanGizmoAdaptor gizmoAdaptor = new GeneratedBeanGizmoAdaptor(
142+
generatedBeanClasses);
143+
144+
try (ClassCreator classCreator = ClassCreator.builder()
145+
.className(BRIDGE_NAME)
146+
.interfaces(ExporterBridge.class)
147+
.classOutput(gizmoAdaptor)
148+
.build()) {
149+
150+
classCreator.addAnnotation(ApplicationScoped.class);
151+
MethodCreator constructor = classCreator.getMethodCreator("<init>", "V");
152+
// Invoke super()
153+
constructor.invokeSpecialMethod(
154+
MethodDescriptors.OBJECT_CONSTRUCTOR,
155+
constructor.getThis());
156+
constructor.returnValue(null);
157+
158+
// public static StandardComponentId createStandardComponentId(StandardComponentId.ExporterType standardType)
159+
try (MethodCreator method = classCreator.getMethodCreator("createStandardComponentId",
160+
StandardComponentId.class,
161+
StandardComponentId.ExporterType.class)) {
162+
method.setModifiers(Opcodes.ACC_PUBLIC);
163+
var in = method.getMethodParam(0);
164+
165+
166+
// calls package-private constructor: StandardComponentId(ExporterType standardType)
167+
MethodDescriptor target = MethodDescriptor.ofConstructor(
168+
StandardComponentId.class, StandardComponentId.ExporterType.class);
169+
170+
var result = method.newInstance(target, in);
171+
method.returnValue(result);
172+
}
173+
}
174+
}
175+
112176
@BuildStep
113177
void logging(BuildProducer<LogCategoryBuildItem> log) {
114178
// Reduce the log level of the exporters because it's too much, and we do log important things ourselves.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.quarkus.opentelemetry.deployment.exporter.otlp;
2+
3+
import static io.opentelemetry.sdk.internal.StandardComponentId.ExporterType.OTLP_HTTP_SPAN_EXPORTER;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertNotNull;
6+
7+
import io.opentelemetry.sdk.internal.ComponentId;
8+
import io.quarkus.opentelemetry.deployment.common.exporter.TestSpanExporter;
9+
import io.quarkus.opentelemetry.deployment.common.exporter.TestSpanExporterProvider;
10+
import jakarta.inject.Inject;
11+
12+
import org.jboss.shrinkwrap.api.ShrinkWrap;
13+
import org.jboss.shrinkwrap.api.asset.StringAsset;
14+
import org.jboss.shrinkwrap.api.spec.JavaArchive;
15+
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.api.extension.RegisterExtension;
17+
18+
import io.opentelemetry.sdk.internal.StandardComponentId;
19+
import io.quarkus.opentelemetry.runtime.exporter.otlp.ExporterBridge;
20+
import io.quarkus.test.QuarkusUnitTest;
21+
22+
public class ExportBridgeTest {
23+
@RegisterExtension
24+
static final QuarkusUnitTest TEST = new QuarkusUnitTest()
25+
.setArchiveProducer(
26+
() -> ShrinkWrap.create(JavaArchive.class)
27+
.addClasses(ExporterBridge.class, StandardComponentId.class, ComponentId.class)
28+
.addClasses(TestSpanExporter.class, TestSpanExporterProvider.class)
29+
.addAsResource(new StringAsset(TestSpanExporterProvider.class.getCanonicalName()),
30+
"META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider"))
31+
.withConfigurationResource("resource-config/application-no-metrics.properties");
32+
33+
@Inject
34+
ExporterBridge bridge;
35+
36+
@Test
37+
void testBridge() {
38+
StandardComponentId standardComponentId = bridge.createStandardComponentId(OTLP_HTTP_SPAN_EXPORTER);
39+
assertNotNull(standardComponentId);
40+
assertEquals(OTLP_HTTP_SPAN_EXPORTER, standardComponentId.getStandardType());
41+
}
42+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.quarkus.opentelemetry.runtime.exporter.otlp;
2+
3+
import io.opentelemetry.sdk.internal.StandardComponentId;
4+
5+
/**
6+
* Bytecode implementation living in the processor.
7+
*/
8+
public interface ExporterBridge {
9+
StandardComponentId createStandardComponentId(StandardComponentId.ExporterType standardType);
10+
}

extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OTelExporterRecorder.java

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.quarkus.opentelemetry.runtime.exporter.otlp;
22

3-
import static io.quarkus.opentelemetry.runtime.config.build.ExporterType.Constants.OTLP_VALUE;
43
import static io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterConfig.Protocol.GRPC;
54
import static io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterConfig.Protocol.HTTP_PROTOBUF;
65
import static io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterRuntimeConfig.DEFAULT_GRPC_BASE_URI;
@@ -27,6 +26,8 @@
2726
import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler;
2827
import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent;
2928
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
29+
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
30+
import io.opentelemetry.sdk.internal.StandardComponentId;
3031
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
3132
import io.opentelemetry.sdk.metrics.Aggregation;
3233
import io.opentelemetry.sdk.metrics.InstrumentType;
@@ -75,14 +76,17 @@ public class OTelExporterRecorder {
7576
private final OTelBuildConfig buildConfig;
7677
private final RuntimeValue<OTelRuntimeConfig> runtimeConfig;
7778
private final RuntimeValue<OtlpExporterRuntimeConfig> exporterRuntimeConfig;
79+
private final RuntimeValue<ExporterBridge> exporterBridge;
7880

7981
public OTelExporterRecorder(
8082
final OTelBuildConfig buildConfig,
8183
final RuntimeValue<OTelRuntimeConfig> runtimeConfig,
82-
final RuntimeValue<OtlpExporterRuntimeConfig> exporterRuntimeConfig) {
84+
final RuntimeValue<OtlpExporterRuntimeConfig> exporterRuntimeConfig,
85+
final RuntimeValue<ExporterBridge> exporterBridge) {
8386
this.buildConfig = buildConfig;
8487
this.runtimeConfig = runtimeConfig;
8588
this.exporterRuntimeConfig = exporterRuntimeConfig;
89+
this.exporterBridge = exporterBridge;
8690
}
8791

8892
public Function<SyntheticCreationalContext<LateBoundSpanProcessor>, LateBoundSpanProcessor> spanProcessorForOtlp(
@@ -156,8 +160,6 @@ private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig export
156160
OtlpExporterTracesConfig tracesConfig = exporterRuntimeConfig.traces();
157161

158162
return new VertxGrpcSpanExporter(new GrpcExporter<TraceRequestMarshaler>(
159-
OTLP_VALUE, // use the same as OTel does
160-
"span", // use the same as OTel does
161163
new VertxGrpcSender(
162164
baseUri,
163165
VertxGrpcSender.GRPC_TRACE_SERVICE_NAME,
@@ -166,7 +168,11 @@ private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig export
166168
populateTracingExportHttpHeaders(tracesConfig),
167169
new HttpClientOptionsConsumer(tracesConfig, baseUri, tlsConfigurationRegistry),
168170
vertx),
169-
MeterProvider::noop));
171+
InternalTelemetryVersion.LATEST,
172+
exporterBridge.getValue()
173+
.createStandardComponentId(StandardComponentId.ExporterType.OTLP_GRPC_SPAN_EXPORTER), // use the same as OTel does
174+
MeterProvider::noop,
175+
baseUri.toASCIIString()));
170176
}
171177

172178
private SpanExporter createHttpSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig, Vertx vertx,
@@ -178,8 +184,8 @@ private SpanExporter createHttpSpanExporter(OtlpExporterRuntimeConfig exporterRu
178184
boolean exportAsJson = false; //TODO: this will be enhanced in the future
179185

180186
return new VertxHttpSpanExporter(new HttpExporter<TraceRequestMarshaler>(
181-
OTLP_VALUE, // use the same as OTel does
182-
"span", // use the same as OTel does
187+
exporterBridge.getValue()
188+
.createStandardComponentId(StandardComponentId.ExporterType.OTLP_HTTP_SPAN_EXPORTER),
183189
new VertxHttpSender(
184190
baseUri,
185191
VertxHttpSender.TRACES_PATH,
@@ -190,7 +196,8 @@ private SpanExporter createHttpSpanExporter(OtlpExporterRuntimeConfig exporterRu
190196
new HttpClientOptionsConsumer(tracesConfig, baseUri, tlsConfigurationRegistry),
191197
vertx),
192198
MeterProvider::noop,
193-
exportAsJson));
199+
InternalTelemetryVersion.LATEST,
200+
baseUri.toASCIIString()));
194201
}
195202
};
196203
}
@@ -222,8 +229,6 @@ public MetricExporter apply(SyntheticCreationalContext<MetricExporter> context)
222229
if (GRPC.equals(protocol)) {
223230
metricExporter = new VertxGrpcMetricExporter(
224231
new GrpcExporter<MetricsRequestMarshaler>(
225-
OTLP_VALUE, // use the same as OTel does
226-
"metric", // use the same as OTel does
227232
new VertxGrpcSender(
228233
baseUri,
229234
VertxGrpcSender.GRPC_METRIC_SERVICE_NAME,
@@ -232,15 +237,19 @@ public MetricExporter apply(SyntheticCreationalContext<MetricExporter> context)
232237
populateTracingExportHttpHeaders(metricsConfig),
233238
new HttpClientOptionsConsumer(metricsConfig, baseUri, tlsConfigurationRegistry),
234239
vertx.get()),
235-
MeterProvider::noop),
240+
InternalTelemetryVersion.LATEST,
241+
exporterBridge.getValue().createStandardComponentId(
242+
StandardComponentId.ExporterType.OTLP_GRPC_METRIC_EXPORTER), // use the same as OTel does
243+
MeterProvider::noop,
244+
baseUri.toASCIIString()),
236245
aggregationTemporalityResolver(metricsConfig),
237246
aggregationResolver(metricsConfig));
238247
} else if (HTTP_PROTOBUF.equals(protocol)) {
239248
boolean exportAsJson = false; //TODO: this will be enhanced in the future
240249
metricExporter = new VertxHttpMetricsExporter(
241250
new HttpExporter<MetricsRequestMarshaler>(
242-
OTLP_VALUE, // use the same as OTel does
243-
"metric", // use the same as OTel does
251+
exporterBridge.getValue().createStandardComponentId(
252+
StandardComponentId.ExporterType.OTLP_HTTP_METRIC_EXPORTER),
244253
new VertxHttpSender(
245254
baseUri,
246255
VertxHttpSender.METRICS_PATH,
@@ -251,7 +260,8 @@ public MetricExporter apply(SyntheticCreationalContext<MetricExporter> context)
251260
new HttpClientOptionsConsumer(metricsConfig, baseUri, tlsConfigurationRegistry),
252261
vertx.get()),
253262
MeterProvider::noop,
254-
exportAsJson),
263+
InternalTelemetryVersion.LATEST,
264+
baseUri.toASCIIString()),
255265
aggregationTemporalityResolver(metricsConfig),
256266
aggregationResolver(metricsConfig));
257267
} else {
@@ -294,8 +304,6 @@ public LogRecordExporter apply(SyntheticCreationalContext<LogRecordExporter> con
294304
if (GRPC.equals(protocol)) {
295305
logRecordExporter = new VertxGrpcLogRecordExporter(
296306
new GrpcExporter<LogsRequestMarshaler>(
297-
OTLP_VALUE, // use the same as OTel does
298-
"log", // use the same as OTel does
299307
new VertxGrpcSender(
300308
baseUri,
301309
VertxGrpcSender.GRPC_LOG_SERVICE_NAME,
@@ -304,13 +312,17 @@ public LogRecordExporter apply(SyntheticCreationalContext<LogRecordExporter> con
304312
populateTracingExportHttpHeaders(logsConfig),
305313
new HttpClientOptionsConsumer(logsConfig, baseUri, tlsConfigurationRegistry),
306314
vertx.get()),
307-
MeterProvider::noop));
315+
InternalTelemetryVersion.LATEST,
316+
exporterBridge.getValue().createStandardComponentId(
317+
StandardComponentId.ExporterType.OTLP_GRPC_LOG_EXPORTER), // use the same as OTel does
318+
MeterProvider::noop,
319+
baseUri.toASCIIString()));
308320
} else if (HTTP_PROTOBUF.equals(protocol)) {
309321
boolean exportAsJson = false; //TODO: this will be enhanced in the future
310322
logRecordExporter = new VertxHttpLogRecordExporter(
311323
new HttpExporter<LogsRequestMarshaler>(
312-
OTLP_VALUE, // use the same as OTel does
313-
"log", // use the same as OTel does
324+
exporterBridge.getValue().createStandardComponentId(
325+
StandardComponentId.ExporterType.OTLP_HTTP_LOG_EXPORTER),
314326
new VertxHttpSender(
315327
baseUri,
316328
VertxHttpSender.LOGS_PATH,
@@ -321,7 +333,8 @@ public LogRecordExporter apply(SyntheticCreationalContext<LogRecordExporter> con
321333
new HttpClientOptionsConsumer(logsConfig, baseUri, tlsConfigurationRegistry),
322334
vertx.get()),
323335
MeterProvider::noop,
324-
exportAsJson));
336+
InternalTelemetryVersion.LATEST,
337+
baseUri.toASCIIString()));
325338
} else {
326339
throw new IllegalArgumentException(String.format("Unsupported OTLP protocol %s specified. " +
327340
"Please check `quarkus.otel.exporter.otlp.logs.protocol` property", protocol));

0 commit comments

Comments
 (0)