diff --git a/api/src/main/java/io/opentelemetry/OpenTelemetry.java b/api/src/main/java/io/opentelemetry/OpenTelemetry.java index 74049c8e8d3..cbce580e7c4 100644 --- a/api/src/main/java/io/opentelemetry/OpenTelemetry.java +++ b/api/src/main/java/io/opentelemetry/OpenTelemetry.java @@ -22,9 +22,11 @@ import io.opentelemetry.metrics.DefaultMeter; import io.opentelemetry.metrics.Meter; import io.opentelemetry.metrics.spi.MeterProvider; -import io.opentelemetry.trace.DefaultTracer; +import io.opentelemetry.trace.DefaultTracerFactory; +import io.opentelemetry.trace.DefaultTracerFactoryProvider; import io.opentelemetry.trace.Tracer; -import io.opentelemetry.trace.spi.TracerProvider; +import io.opentelemetry.trace.TracerFactory; +import io.opentelemetry.trace.spi.TracerFactoryProvider; import java.util.ServiceLoader; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -35,7 +37,7 @@ * *

The telemetry objects are lazy-loaded singletons resolved via {@link ServiceLoader} mechanism. * - * @see TracerProvider + * @see TracerFactory * @see MeterProvider * @see DistributedContextManagerProvider */ @@ -44,19 +46,20 @@ public final class OpenTelemetry { @Nullable private static volatile OpenTelemetry instance; - private final Tracer tracer; + private final TracerFactory tracerFactory; private final Meter meter; private final DistributedContextManager contextManager; /** - * Returns a singleton {@link Tracer}. + * Returns a singleton {@link TracerFactory}. * - * @return registered tracer or default via {@link DefaultTracer#getInstance()}. - * @throws IllegalStateException if a specified tracer (via system properties) could not be found. + * @return registered TracerFactory of default via {@link DefaultTracerFactory#getInstance()}. + * @throws IllegalStateException if a specified TracerFactory (via system properties) could not be + * found. * @since 0.1.0 */ - public static Tracer getTracer() { - return getInstance().tracer; + public static TracerFactory getTracerFactory() { + return getInstance().tracerFactory; } /** @@ -83,6 +86,35 @@ public static DistributedContextManager getDistributedContextManager() { return getInstance().contextManager; } + /** Lazy loads an instance. */ + private static OpenTelemetry getInstance() { + if (instance == null) { + synchronized (OpenTelemetry.class) { + if (instance == null) { + instance = new OpenTelemetry(); + } + } + } + return instance; + } + + private OpenTelemetry() { + TracerFactoryProvider tracerFactoryProvider = loadSpi(TracerFactoryProvider.class); + this.tracerFactory = + tracerFactoryProvider != null + ? tracerFactoryProvider.create() + : DefaultTracerFactoryProvider.getInstance().create(); + + MeterProvider meterProvider = loadSpi(MeterProvider.class); + meter = meterProvider != null ? meterProvider.create() : DefaultMeter.getInstance(); + DistributedContextManagerProvider contextManagerProvider = + loadSpi(DistributedContextManagerProvider.class); + contextManager = + contextManagerProvider != null + ? contextManagerProvider.create() + : DefaultDistributedContextManager.getInstance(); + } + /** * Load provider class via {@link ServiceLoader}. A specific provider class can be requested via * setting a system property with FQCN. @@ -108,31 +140,6 @@ private static T loadSpi(Class providerClass) { return null; } - /** Lazy loads an instance. */ - private static OpenTelemetry getInstance() { - if (instance == null) { - synchronized (OpenTelemetry.class) { - if (instance == null) { - instance = new OpenTelemetry(); - } - } - } - return instance; - } - - private OpenTelemetry() { - TracerProvider tracerProvider = loadSpi(TracerProvider.class); - tracer = tracerProvider != null ? tracerProvider.create() : DefaultTracer.getInstance(); - MeterProvider meterProvider = loadSpi(MeterProvider.class); - meter = meterProvider != null ? meterProvider.create() : DefaultMeter.getInstance(); - DistributedContextManagerProvider contextManagerProvider = - loadSpi(DistributedContextManagerProvider.class); - contextManager = - contextManagerProvider != null - ? contextManagerProvider.create() - : DefaultDistributedContextManager.getInstance(); - } - // for testing static void reset() { instance = null; diff --git a/api/src/main/java/io/opentelemetry/trace/DefaultTracerFactory.java b/api/src/main/java/io/opentelemetry/trace/DefaultTracerFactory.java new file mode 100644 index 00000000000..72a31145c12 --- /dev/null +++ b/api/src/main/java/io/opentelemetry/trace/DefaultTracerFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019, 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.trace; + +public class DefaultTracerFactory implements TracerFactory { + + private static final TracerFactory instance = new DefaultTracerFactory(); + + public static TracerFactory getInstance() { + return instance; + } + + @Override + public Tracer get(String instrumentationName) { + return get(instrumentationName, null); + } + + @Override + public Tracer get(String instrumentationName, String instrumentationVersion) { + return DefaultTracer.getInstance(); + } +} diff --git a/api/src/main/java/io/opentelemetry/trace/DefaultTracerFactoryProvider.java b/api/src/main/java/io/opentelemetry/trace/DefaultTracerFactoryProvider.java new file mode 100644 index 00000000000..0b31d4bd7b0 --- /dev/null +++ b/api/src/main/java/io/opentelemetry/trace/DefaultTracerFactoryProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019, 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.trace; + +import io.opentelemetry.trace.spi.TracerFactoryProvider; + +public class DefaultTracerFactoryProvider implements TracerFactoryProvider { + private static final TracerFactoryProvider instance = new DefaultTracerFactoryProvider(); + + public static TracerFactoryProvider getInstance() { + return instance; + } + + @Override + public TracerFactory create() { + return DefaultTracerFactory.getInstance(); + } +} diff --git a/api/src/main/java/io/opentelemetry/trace/TracerFactory.java b/api/src/main/java/io/opentelemetry/trace/TracerFactory.java new file mode 100644 index 00000000000..f1ef1b671ca --- /dev/null +++ b/api/src/main/java/io/opentelemetry/trace/TracerFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019, 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.trace; + +import javax.annotation.concurrent.ThreadSafe; + +/** + * A factory for creating named {@link Tracer}s. + * + * @see io.opentelemetry.OpenTelemetry + * @see io.opentelemetry.trace.Tracer + * @since 0.1.0 + */ +@ThreadSafe +public interface TracerFactory { + + /** + * Gets or creates a named tracer instance. + * + * @param instrumentationName The name of the instrumentation library, not the name of the + * instrument*ed* library. + * @return a tracer instance. + * @since 0.1.0 + */ + Tracer get(String instrumentationName); + + /** + * Gets or creates a named and versioned tracer instance. + * + * @param instrumentationName The name of the instrumentation library, not the name of the + * instrument*ed* library. + * @param instrumentationVersion The version of the instrumentation library. + * @return a tracer instance. + * @since 0.1.0 + */ + Tracer get(String instrumentationName, String instrumentationVersion); +} diff --git a/api/src/main/java/io/opentelemetry/trace/spi/TracerProvider.java b/api/src/main/java/io/opentelemetry/trace/spi/TracerFactoryProvider.java similarity index 63% rename from api/src/main/java/io/opentelemetry/trace/spi/TracerProvider.java rename to api/src/main/java/io/opentelemetry/trace/spi/TracerFactoryProvider.java index 08949bb1a52..8f052284862 100644 --- a/api/src/main/java/io/opentelemetry/trace/spi/TracerProvider.java +++ b/api/src/main/java/io/opentelemetry/trace/spi/TracerFactoryProvider.java @@ -16,27 +16,27 @@ package io.opentelemetry.trace.spi; -import io.opentelemetry.trace.Tracer; +import io.opentelemetry.trace.TracerFactory; import javax.annotation.concurrent.ThreadSafe; /** - * TracerProvider is a service provider for {@link Tracer}. Fully qualified class name of the - * implementation should be registered in {@code - * META-INF/services/io.opentelemetry.trace.spi.TracerProvider}.
+ * TracerFactoryProvider is a service provider for a {@link TracerFactory}. Fully qualified class + * name of the implementation should be registered in {@code + * META-INF/services/io.opentelemetry.trace.spi.TracerFactoryProvider}.
*
* A specific implementation can be selected by a system property {@code - * io.opentelemetry.trace.spi.TracerProvider} with value of fully qualified class name. + * io.opentelemetry.trace.spi.TracerFactoryProvider} with value of fully qualified class name. * * @see io.opentelemetry.OpenTelemetry */ @ThreadSafe -public interface TracerProvider { +public interface TracerFactoryProvider { /** - * Creates a new tracer instance. + * Creates a new TracerFactory. * - * @return a tracer instance. + * @return a new TracerFactory. * @since 0.1.0 */ - Tracer create(); + TracerFactory create(); } diff --git a/api/src/test/java/io/opentelemetry/OpenTelemetryTest.java b/api/src/test/java/io/opentelemetry/OpenTelemetryTest.java index d05f24e4631..7c64e7c3700 100644 --- a/api/src/test/java/io/opentelemetry/OpenTelemetryTest.java +++ b/api/src/test/java/io/opentelemetry/OpenTelemetryTest.java @@ -42,7 +42,8 @@ import io.opentelemetry.trace.Span; import io.opentelemetry.trace.SpanContext; import io.opentelemetry.trace.Tracer; -import io.opentelemetry.trace.spi.TracerProvider; +import io.opentelemetry.trace.TracerFactory; +import io.opentelemetry.trace.spi.TracerFactoryProvider; import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -70,15 +71,17 @@ public static void beforeClass() { @After public void after() { OpenTelemetry.reset(); - System.clearProperty(TracerProvider.class.getName()); + System.clearProperty(TracerFactoryProvider.class.getName()); System.clearProperty(MeterProvider.class.getName()); System.clearProperty(DistributedContextManagerProvider.class.getName()); } @Test public void testDefault() { - assertThat(OpenTelemetry.getTracer()).isInstanceOf(DefaultTracer.getInstance().getClass()); - assertThat(OpenTelemetry.getTracer()).isEqualTo(OpenTelemetry.getTracer()); + assertThat(OpenTelemetry.getTracerFactory().get("testTracer")) + .isInstanceOf(DefaultTracer.getInstance().getClass()); + assertThat(OpenTelemetry.getTracerFactory().get("testTracer")) + .isEqualTo(OpenTelemetry.getTracerFactory().get("testTracer")); assertThat(OpenTelemetry.getMeter()).isInstanceOf(DefaultMeter.getInstance().getClass()); assertThat(OpenTelemetry.getMeter()).isEqualTo(OpenTelemetry.getMeter()); assertThat(OpenTelemetry.getDistributedContextManager()) @@ -89,12 +92,13 @@ public void testDefault() { @Test public void testTracerLoadArbitrary() throws IOException { - File serviceFile = createService(TracerProvider.class, FirstTracer.class, SecondTracer.class); + File serviceFile = + createService( + TracerFactoryProvider.class, FirstTracerFactory.class, SecondTracerFactory.class); try { assertTrue( - (OpenTelemetry.getTracer() instanceof FirstTracer) - || (OpenTelemetry.getTracer() instanceof SecondTracer)); - assertThat(OpenTelemetry.getTracer()).isEqualTo(OpenTelemetry.getTracer()); + (OpenTelemetry.getTracerFactory() instanceof FirstTracerFactory) + || (OpenTelemetry.getTracerFactory() instanceof SecondTracerFactory)); } finally { serviceFile.delete(); } @@ -102,11 +106,12 @@ public void testTracerLoadArbitrary() throws IOException { @Test public void testTracerSystemProperty() throws IOException { - File serviceFile = createService(TracerProvider.class, FirstTracer.class, SecondTracer.class); - System.setProperty(TracerProvider.class.getName(), SecondTracer.class.getName()); + File serviceFile = + createService( + TracerFactoryProvider.class, FirstTracerFactory.class, SecondTracerFactory.class); + System.setProperty(TracerFactoryProvider.class.getName(), SecondTracerFactory.class.getName()); try { - assertThat(OpenTelemetry.getTracer()).isInstanceOf(SecondTracer.class); - assertThat(OpenTelemetry.getTracer()).isEqualTo(OpenTelemetry.getTracer()); + assertThat(OpenTelemetry.getTracerFactory()).isInstanceOf(SecondTracerFactory.class); } finally { serviceFile.delete(); } @@ -114,9 +119,9 @@ public void testTracerSystemProperty() throws IOException { @Test public void testTracerNotFound() { - System.setProperty(TracerProvider.class.getName(), "io.does.not.exists"); + System.setProperty(TracerFactoryProvider.class.getName(), "io.does.not.exists"); thrown.expect(IllegalStateException.class); - OpenTelemetry.getTracer(); + OpenTelemetry.getTracerFactory().get("testTracer"); } @Test @@ -212,17 +217,32 @@ private static File createService(Class service, Class... impls) throws IO return file; } - public static class SecondTracer extends FirstTracer { + public static class SecondTracerFactory extends FirstTracerFactory { + @Override + public Tracer get(String instrumentationName) { + return new SecondTracerFactory(); + } + + @Override + public Tracer get(String instrumentationName, String instrumentationVersion) { + return get(instrumentationName); + } + @Override - public Tracer create() { - return new SecondTracer(); + public TracerFactory create() { + return new SecondTracerFactory(); } } - public static class FirstTracer implements Tracer, TracerProvider { + public static class FirstTracerFactory implements Tracer, TracerFactory, TracerFactoryProvider { + @Override + public Tracer get(String instrumentationName) { + return new FirstTracerFactory(); + } + @Override - public Tracer create() { - return new FirstTracer(); + public Tracer get(String instrumentationName, String instrumentationVersion) { + return get(instrumentationName); } @Nullable @@ -254,6 +274,11 @@ public BinaryFormat getBinaryFormat() { public HttpTextFormat getHttpTextFormat() { return null; } + + @Override + public TracerFactory create() { + return new FirstTracerFactory(); + } } public static class SecondMeter extends FirstMeter { diff --git a/opentracing_shim/src/main/java/io/opentelemetry/opentracingshim/TraceShim.java b/opentracing_shim/src/main/java/io/opentelemetry/opentracingshim/TraceShim.java index 50086716ed2..68ac7baca6f 100644 --- a/opentracing_shim/src/main/java/io/opentelemetry/opentracingshim/TraceShim.java +++ b/opentracing_shim/src/main/java/io/opentelemetry/opentracingshim/TraceShim.java @@ -32,7 +32,9 @@ private TraceShim() {} */ public static io.opentracing.Tracer createTracerShim() { return new TracerShim( - new TelemetryInfo(OpenTelemetry.getTracer(), OpenTelemetry.getDistributedContextManager())); + new TelemetryInfo( + OpenTelemetry.getTracerFactory().get("openTracingShim"), + OpenTelemetry.getDistributedContextManager())); } /** diff --git a/sdk/src/main/java/io/opentelemetry/sdk/OpenTelemetrySdk.java b/sdk/src/main/java/io/opentelemetry/sdk/OpenTelemetrySdk.java index a85b75e6fec..7d3d6c66194 100644 --- a/sdk/src/main/java/io/opentelemetry/sdk/OpenTelemetrySdk.java +++ b/sdk/src/main/java/io/opentelemetry/sdk/OpenTelemetrySdk.java @@ -20,6 +20,7 @@ import io.opentelemetry.sdk.distributedcontext.DistributedContextManagerSdk; import io.opentelemetry.sdk.metrics.MeterSdk; import io.opentelemetry.sdk.trace.TracerSdk; +import io.opentelemetry.sdk.trace.TracerSdkFactory; import javax.annotation.concurrent.ThreadSafe; /** @@ -34,13 +35,13 @@ @ThreadSafe public final class OpenTelemetrySdk { /** - * Returns a {@link TracerSdk}. + * Returns a {@link TracerSdkFactory}. * - * @return tracer returned by {@link OpenTelemetry#getTracer()}. + * @return TracerFactory returned by {@link OpenTelemetry#getTracerFactory()}. * @since 0.1.0 */ - public static TracerSdk getTracer() { - return (TracerSdk) OpenTelemetry.getTracer(); + public static TracerSdkFactory getTracerFactory() { + return (TracerSdkFactory) OpenTelemetry.getTracerFactory(); } /** diff --git a/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkFactory.java b/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkFactory.java new file mode 100644 index 00000000000..0081d93fb3b --- /dev/null +++ b/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019, 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.sdk.trace; + +import io.opentelemetry.trace.Tracer; +import io.opentelemetry.trace.TracerFactory; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * {@code Tracer} provider implementation for {@link TracerFactory}. + * + *

This class is not intended to be used in application code and it is used only by {@link + * io.opentelemetry.OpenTelemetry}. + */ +public class TracerSdkFactory implements TracerFactory { + private final Map tracersByKey = + Collections.synchronizedMap(new HashMap()); + + @Override + public Tracer get(String instrumentationName) { + return get(instrumentationName, null); + } + + @Override + public Tracer get(String instrumentationName, String instrumentationVersion) { + String key = instrumentationName + "/" + instrumentationVersion; + Tracer tracer = tracersByKey.get(key); + if (tracer == null) { + // todo: pass in the name & version here to the implementation to be used for purposes. + tracer = new TracerSdk(); + tracersByKey.put(key, tracer); + } + return tracer; + } +} diff --git a/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkProvider.java b/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkFactoryProvider.java similarity index 61% rename from sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkProvider.java rename to sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkFactoryProvider.java index faf3271819d..cf1a7ba2155 100644 --- a/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkProvider.java +++ b/sdk/src/main/java/io/opentelemetry/sdk/trace/TracerSdkFactoryProvider.java @@ -16,18 +16,13 @@ package io.opentelemetry.sdk.trace; -import io.opentelemetry.trace.Tracer; - -/** - * {@code Tracer} provider implementation for {@link io.opentelemetry.trace.spi.TracerProvider}. - * - *

This class is not intended to be used in application code and it is used only by {@link - * io.opentelemetry.OpenTelemetry}. - */ -public class TracerSdkProvider implements io.opentelemetry.trace.spi.TracerProvider { +import io.opentelemetry.trace.TracerFactory; +import io.opentelemetry.trace.spi.TracerFactoryProvider; +/** SDK implementation of the TracerProviderFactory for SPI. */ +public class TracerSdkFactoryProvider implements TracerFactoryProvider { @Override - public Tracer create() { - return new TracerSdk(); + public TracerFactory create() { + return new TracerSdkFactory(); } } diff --git a/sdk/src/main/resources/META-INF/services/io.opentelemetry.trace.spi.TracerFactoryProvider b/sdk/src/main/resources/META-INF/services/io.opentelemetry.trace.spi.TracerFactoryProvider new file mode 100644 index 00000000000..6be0bc33c27 --- /dev/null +++ b/sdk/src/main/resources/META-INF/services/io.opentelemetry.trace.spi.TracerFactoryProvider @@ -0,0 +1 @@ +io.opentelemetry.sdk.trace.TracerSdkFactoryProvider diff --git a/sdk/src/main/resources/META-INF/services/io.opentelemetry.trace.spi.TracerProvider b/sdk/src/main/resources/META-INF/services/io.opentelemetry.trace.spi.TracerProvider deleted file mode 100644 index c7d60538e5e..00000000000 --- a/sdk/src/main/resources/META-INF/services/io.opentelemetry.trace.spi.TracerProvider +++ /dev/null @@ -1 +0,0 @@ -io.opentelemetry.sdk.trace.TracerSdkProvider diff --git a/sdk/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java b/sdk/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java index d4391c0b5a8..87c543edfb8 100644 --- a/sdk/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java +++ b/sdk/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java @@ -28,7 +28,8 @@ public class OpenTelemetrySdkTest { @Test public void testDefault() { - assertThat(OpenTelemetrySdk.getTracer()).isSameInstanceAs(OpenTelemetry.getTracer()); + assertThat(OpenTelemetrySdk.getTracerFactory()) + .isSameInstanceAs(OpenTelemetry.getTracerFactory()); assertThat(OpenTelemetrySdk.getDistributedContextManager()) .isSameInstanceAs(OpenTelemetry.getDistributedContextManager()); assertThat(OpenTelemetrySdk.getMeter()).isSameInstanceAs(OpenTelemetry.getMeter()); diff --git a/sdk/src/test/java/io/opentelemetry/sdk/trace/TracerSdkProviderTest.java b/sdk/src/test/java/io/opentelemetry/sdk/trace/TracerSdkProviderTest.java index c0431b979d8..b92088bc411 100644 --- a/sdk/src/test/java/io/opentelemetry/sdk/trace/TracerSdkProviderTest.java +++ b/sdk/src/test/java/io/opentelemetry/sdk/trace/TracerSdkProviderTest.java @@ -27,6 +27,6 @@ public class TracerSdkProviderTest { @Test public void testDefault() { - assertThat(new TracerSdkProvider().create()).isInstanceOf(TracerSdk.class); + assertThat(new TracerSdkFactory().get("testInstrumentation")).isInstanceOf(TracerSdk.class); } }