Add OTLP exporter
MODIFY
agent-tooling/agent-tooling.gradle
agent-tooling/agent-tooling.gradle
@@ -23,6 +23,8 @@ dependencies {
compile deps.opentelemetrySdk
compile deps.opentelemetrySdkAutoConfig
+ // TODO: move the interface in exporter-support into opentelemetry-sdk-contrib-auto-config
+ compile project(':exporter-support')
compile group: 'com.blogspot.mydailyjava', name: 'weak-lock-free', version: '0.15'
compile deps.bytebuddy

MODIFY
agent-tooling/src/main/java/io/opentelemetry/auto/tooling/TracerInstaller.java
agent-tooling/src/main/java/io/opentelemetry/auto/tooling/TracerInstaller.java
@@ -17,13 +17,17 @@ package io.opentelemetry.auto.tooling;
import com.google.common.annotations.VisibleForTesting;
import io.opentelemetry.auto.config.Config;
+import io.opentelemetry.auto.exportersupport.MetricExporterFactory;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.contrib.auto.config.SpanExporterFactory;
+import io.opentelemetry.sdk.metrics.export.IntervalMetricReader;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.trace.export.SimpleSpansProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Collections;
import java.util.Iterator;
import java.util.ServiceLoader;
import lombok.extern.slf4j.Slf4j;
@@ -37,14 +41,7 @@ public class TracerInstaller {
// Try to create an exporter
final String exporterJar = Config.get().getExporterJar();
if (exporterJar != null) {
- final SpanExporter exporter = loadFromJar(exporterJar);
- if (exporter != null) {
- OpenTelemetrySdk.getTracerProvider()
- .addSpanProcessor(SimpleSpansProcessor.newBuilder(exporter).build());
- log.info("Installed span exporter: " + exporter.getClass().getCanonicalName());
- } else {
- log.warn("No valid exporter found. Tracing will run but spans are dropped");
- }
+ installExportersFromJar(exporterJar);
} else {
log.warn("No exporter is specified. Tracing will run but spans are dropped");
}
@@ -54,29 +51,57 @@ public class TracerInstaller {
}
@VisibleForTesting
- private static synchronized SpanExporter loadFromJar(final String exporterJar) {
+ private static synchronized void installExportersFromJar(final String exporterJar) {
final URL url;
try {
url = new File(exporterJar).toURI().toURL();
} catch (final MalformedURLException e) {
log.warn("Filename could not be parsed: " + exporterJar + ". Exporter is not installed");
- return null;
+ log.warn("No valid exporter found. Tracing will run but spans are dropped");
+ return;
}
-
+ final DefaultExporterConfig config = new DefaultExporterConfig("exporter");
final ExporterClassLoader exporterLoader =
new ExporterClassLoader(new URL[] {url}, TracerInstaller.class.getClassLoader());
- final ServiceLoader<SpanExporterFactory> sl =
- ServiceLoader.load(SpanExporterFactory.class, exporterLoader);
- final Iterator<SpanExporterFactory> itor = sl.iterator();
- if (itor.hasNext()) {
- final SpanExporterFactory f = itor.next();
- if (itor.hasNext()) {
+
+ final SpanExporterFactory spanExporterFactory =
+ getExporterFactory(SpanExporterFactory.class, exporterLoader);
+ if (spanExporterFactory != null) {
+ final SpanExporter spanExporter = spanExporterFactory.fromConfig(config);
+ OpenTelemetrySdk.getTracerProvider()
+ .addSpanProcessor(SimpleSpansProcessor.newBuilder(spanExporter).build());
+ log.info("Installed span exporter: " + spanExporter.getClass().getName());
+ } else {
+ log.warn("No matching providers in jar " + exporterJar);
+ log.warn("No valid exporter found. Tracing will run but spans are dropped");
+ }
+
+ final MetricExporterFactory metricExporterFactory =
+ getExporterFactory(MetricExporterFactory.class, exporterLoader);
+ if (metricExporterFactory != null) {
+ final MetricExporter metricExporter = metricExporterFactory.fromConfig(config);
+ IntervalMetricReader.builder()
+ .setMetricExporter(metricExporter)
+ .setMetricProducers(
+ Collections.singleton(OpenTelemetrySdk.getMeterProvider().getMetricProducer()))
+ .build();
+ log.info("Installed metric exporter: " + metricExporter.getClass().getName());
+ }
+ }
+
+ private static <F> F getExporterFactory(
+ final Class<F> service, final ExporterClassLoader exporterLoader) {
+ final ServiceLoader<F> serviceLoader = ServiceLoader.load(service, exporterLoader);
+ final Iterator<F> i = serviceLoader.iterator();
+ if (i.hasNext()) {
+ final F factory = i.next();
+ if (i.hasNext()) {
log.warn(
- "Exporter JAR defines more than one factory. Only the first one found will be used");
+ "Exporter JAR defines more than one {}. Only the first one found will be used",
+ service.getName());
}
- return f.fromConfig(new DefaultExporterConfig("exporter"));
+ return factory;
}
- log.warn("No matching providers in jar " + exporterJar);
return null;
}

ADD
auto-exporters/otlp/otlp.gradle
+plugins {
+ id "com.github.johnrengelman.shadow"
+}
+
+apply from: "${rootDir}/gradle/java.gradle"
+
+dependencies {
+ compile(deps.opentelemetryOtlp) {
+ exclude group: 'io.opentelemetry', module: 'opentelemetry-sdk'
+ }
+ compileOnly deps.opentelemetrySdkAutoConfig
+ // TODO: move the interface in exporter-support into opentelemetry-sdk-contrib-auto-config
+ compile project(':exporter-support')
+ compile group: 'io.grpc', name: 'grpc-api', version: '1.24.0'
+ compile group: 'io.grpc', name: 'grpc-netty-shaded', version: '1.24.0'
+}
+
+shadowJar {
+ archiveClassifier = ''
+}

ADD
auto-exporters/otlp/src/main/java/io/opentelemetry/auto/exporters/otlp/OtlpMetricExporterFactory.java
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.opentelemetry.auto.exporters.otlp;
+
+import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.auto.exportersupport.MetricExporterFactory;
+import io.opentelemetry.exporters.otlp.OtlpGrpcMetricExporter;
+import io.opentelemetry.sdk.contrib.auto.config.Config;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
+
+public class OtlpMetricExporterFactory implements MetricExporterFactory {
+ private static final String OTLP_ENDPOINT = "otlp.endpoint";
+
+ @Override
+ public MetricExporter fromConfig(final Config config) {
+ final String otlpEndpoint = config.getString(OTLP_ENDPOINT, "");
+ if (otlpEndpoint.isEmpty()) {
+ throw new IllegalStateException("ota.exporter.otlp.endpoint is required");
+ }
+ return OtlpGrpcMetricExporter.newBuilder()
+ .setChannel(ManagedChannelBuilder.forTarget(otlpEndpoint).usePlaintext().build())
+ .build();
+ }
+}

ADD
auto-exporters/otlp/src/main/java/io/opentelemetry/auto/exporters/otlp/OtlpSpanExporterFactory.java
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.opentelemetry.auto.exporters.otlp;
+
+import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.exporters.otlp.OtlpGrpcSpanExporter;
+import io.opentelemetry.sdk.contrib.auto.config.Config;
+import io.opentelemetry.sdk.contrib.auto.config.SpanExporterFactory;
+import io.opentelemetry.sdk.trace.export.SpanExporter;
+
+public class OtlpSpanExporterFactory implements SpanExporterFactory {
+ private static final String OTLP_ENDPOINT = "otlp.endpoint";
+
+ @Override
+ public SpanExporter fromConfig(final Config config) {
+ final String otlpEndpoint = config.getString(OTLP_ENDPOINT, "");
+ if (otlpEndpoint.isEmpty()) {
+ throw new IllegalStateException("ota.exporter.otlp.endpoint is required");
+ }
+ return OtlpGrpcSpanExporter.newBuilder()
+ .setChannel(ManagedChannelBuilder.forTarget(otlpEndpoint).usePlaintext().build())
+ .build();
+ }
+}

ADD
auto-exporters/otlp/src/main/resources/META-INF/services/io.opentelemetry.auto.exportersupport.MetricExporterFactory
+io.opentelemetry.auto.exporters.otlp.OtlpMetricExporterFactory

ADD
auto-exporters/otlp/src/main/resources/META-INF/services/io.opentelemetry.sdk.contrib.auto.config.SpanExporterFactory
+io.opentelemetry.auto.exporters.otlp.OtlpSpanExporterFactory

ADD
exporter-support/exporter-support.gradle
+apply from: "${rootDir}/gradle/java.gradle"
+
+dependencies {
+ compileOnly deps.opentelemetrySdk
+ compileOnly deps.opentelemetrySdkAutoConfig
+}

ADD
exporter-support/src/main/java/io/opentelemetry/auto/exportersupport/MetricExporterFactory.java
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.opentelemetry.auto.exportersupport;
+
+import io.opentelemetry.sdk.contrib.auto.config.Config;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
+
+public interface MetricExporterFactory {
+ MetricExporter fromConfig(Config config);
+}

MODIFY
gradle/dependencies.gradle
gradle/dependencies.gradle
@@ -24,6 +24,7 @@ ext {
opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry),
opentelemetrySdkAutoConfig: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-contrib-auto-config', version: versions.opentelemetry),
opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-jaeger', version: versions.opentelemetry),
+ opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-otlp', version: versions.opentelemetry),
// General
slf4j : "org.slf4j:slf4j-api:${versions.slf4j}",

MODIFY
settings.gradle
settings.gradle
@@ -137,10 +137,14 @@ include ':instrumentation:trace-annotation'
include ':instrumentation:twilio-6.6'
include ':instrumentation:vertx-testing'
+// exporter support
+include ':exporter-support'
+
// exporter adapters
include ":auto-exporters"
include ":auto-exporters:jaeger"
include ":auto-exporters:logging"
+include ":auto-exporters:otlp"
// benchmark
include ':benchmark'
@@ -162,3 +166,4 @@ project(':agent-tooling').name = 'auto-tooling'
project(':java-agent').name = 'opentelemetry-auto'
project(':auto-exporters:jaeger').name = 'opentelemetry-auto-exporters-jaeger'
project(':auto-exporters:logging').name = 'opentelemetry-auto-exporters-logging'
+project(':auto-exporters:otlp').name = 'opentelemetry-auto-exporters-otlp'

Add OTLP exporter (#289)