From c783de61d41f336ea7a27abd9d7ece1ab7ada76d Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 4 Jun 2024 09:32:59 -0500 Subject: [PATCH 1/3] Refactor ExtendedTracer, ExtendedSpanBuilder to reflect incubating API conventions --- api/incubator/README.md | 174 +------------- .../incubator/trace/ExtendedSpanBuilder.java | 155 +------------ .../api/incubator/trace/ExtendedTracer.java | 44 ---- .../trace/ExtendedTraceApiUsageTest.java | 211 +++++++++++++++++ .../incubator/trace/ExtendedTracerTest.java | 214 ------------------ sdk/trace/build.gradle.kts | 2 + .../sdk/trace/SdkSpanBuilder.java | 67 +++++- 7 files changed, 295 insertions(+), 572 deletions(-) delete mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java create mode 100644 api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java delete mode 100644 api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTracerTest.java diff --git a/api/incubator/README.md b/api/incubator/README.md index 68769849e5c..068f54a3ca5 100644 --- a/api/incubator/README.md +++ b/api/incubator/README.md @@ -35,170 +35,10 @@ Features: See [ExtendedContextPropagatorsUsageTest](./src/test/java/io/opentelemetry/api/incubator/propagation/ExtendedContextPropagatorsUsageTest.java). -## ExtendedTracer - -Utility methods to make it easier to use the OpenTelemetry tracer. - -Here are some examples how the utility methods can help reduce boilerplate code. - -TODO: translate examples to test to ensure no java compilation issues. - -### Tracing a function - -Before: - - -```java -Span span = tracer.spanBuilder("reset_checkout").startSpan(); -String transactionId; -try (Scope scope = span.makeCurrent()) { - transactionId = resetCheckout(cartId); -} catch (Throwable e) { - span.setStatus(StatusCode.ERROR); - span.recordException(e); - throw e; // or throw new RuntimeException(e) - depending on your error handling strategy -} finally { - span.end(); -} -``` - - -After: - -```java -import io.opentelemetry.extension.incubator.trace.ExtendedTracer; - -ExtendedTracer extendedTracer = ExtendedTracer.create(tracer); -String transactionId = extendedTracer.spanBuilder("reset_checkout").startAndCall(() -> resetCheckout(cartId)); -``` - -If you want to set attributes on the span, you can use the `startAndCall` method on the span builder: - -```java -import io.opentelemetry.extension.incubator.trace.ExtendedTracer; - -ExtendedTracer extendedTracer = ExtendedTracer.create(tracer); -String transactionId = extendedTracer.spanBuilder("reset_checkout") - .setAttribute("foo", "bar") - .startAndCall(() -> resetCheckout(cartId)); -``` - -Note: - -- Use `startAndRun` instead of `startAndCall` if the function returns `void` (both on the tracer and span builder). -- Exceptions are re-thrown without modification - see [Exception handling](#exception-handling) - for more details. - -### Trace context propagation - -Before: - -```java -Map propagationHeaders = new HashMap<>(); -openTelemetry - .getPropagators() - .getTextMapPropagator() - .inject( - Context.current(), - propagationHeaders, - (map, key, value) -> { - if (map != null) { - map.put(key, value); - } - }); - -// add propagationHeaders to request headers and call checkout service -``` - - -```java -// in checkout service: get request headers into a Map requestHeaders -Map requestHeaders = new HashMap<>(); -String cartId = "cartId"; - -SpanBuilder spanBuilder = tracer.spanBuilder("checkout_cart"); - -TextMapGetter> TEXT_MAP_GETTER = - new TextMapGetter>() { - @Override - public Set keys(Map carrier) { - return carrier.keySet(); - } - - @Override - @Nullable - public String get(@Nullable Map carrier, String key) { - return carrier == null ? null : carrier.get(key); - } - }; - -Map normalizedTransport = - requestHeaders.entrySet().stream() - .collect( - Collectors.toMap( - entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)); -Context newContext = openTelemetry - .getPropagators() - .getTextMapPropagator() - .extract(Context.current(), normalizedTransport, TEXT_MAP_GETTER); -String transactionId; -try (Scope ignore = newContext.makeCurrent()) { - Span span = spanBuilder.setSpanKind(SERVER).startSpan(); - try (Scope scope = span.makeCurrent()) { - transactionId = processCheckout(cartId); - } catch (Throwable e) { - span.setStatus(StatusCode.ERROR); - span.recordException(e); - throw e; // or throw new RuntimeException(e) - depending on your error handling strategy - } finally { - span.end(); - } -} -``` - - -After: - -```java -import io.opentelemetry.extension.incubator.propagation.ExtendedContextPropagators; - -Map propagationHeaders = - ExtendedContextPropagators.getTextMapPropagationContext(openTelemetry.getPropagators()); -// add propagationHeaders to request headers and call checkout service -``` - -```java -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.extension.incubator.trace.ExtendedTracer; - -// in checkout service: get request headers into a Map requestHeaders -Map requestHeaders = new HashMap<>(); -String cartId = "cartId"; - -ExtendedTracer extendedTracer = ExtendedTracer.create(tracer); -String transactionId = extendedTracer.spanBuilder("checkout_cart") - .setSpanKind(SpanKind.SERVER) - .setParentFrom(openTelemetry.getPropagators(), requestHeaders) - .startAndCall(() -> processCheckout(cartId)); -``` - -### Exception handling - -`ExtendedTracer` re-throws exceptions without modification. This means you can -catch exceptions around `ExtendedTracer` calls and handle them as you would without `ExtendedTracer`. - -When an exception is encountered during an `ExtendedTracer` call, the span is marked as error and -the exception is recorded. - -If you want to customize this behaviour, e.g. to only record the exception, because you are -able to recover from the error, you can call the overloaded method of `startAndCall` or -`startAndRun` that takes an exception handler: - -```java -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.extension.incubator.trace.ExtendedTracer; - -ExtendedTracer extendedTracer = ExtendedTracer.create(tracer); -String transactionId = extendedTracer.spanBuilder("checkout_cart") - .startAndCall(() -> processCheckout(cartId), Span::recordException); -``` +## Extended Trace APIs + +Features: + +* Utility methods to reduce boilerplace using span API, including extracting context, and wrapping runnables / callables with spans + +See [ExtendedTraceApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java). diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedSpanBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedSpanBuilder.java index 32f7a7a3d90..715b79f70c4 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedSpanBuilder.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedSpanBuilder.java @@ -6,106 +6,14 @@ package io.opentelemetry.api.incubator.trace; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.propagation.ExtendedContextPropagators; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.ContextPropagators; -import java.time.Instant; import java.util.Map; -import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; -public final class ExtendedSpanBuilder implements SpanBuilder { - private final SpanBuilder delegate; - - ExtendedSpanBuilder(SpanBuilder delegate) { - this.delegate = delegate; - } - - @Override - public ExtendedSpanBuilder setParent(Context context) { - delegate.setParent(context); - return this; - } - - @Override - public ExtendedSpanBuilder setNoParent() { - delegate.setNoParent(); - return this; - } - - @Override - public ExtendedSpanBuilder addLink(SpanContext spanContext) { - delegate.addLink(spanContext); - return this; - } - - @Override - public ExtendedSpanBuilder addLink(SpanContext spanContext, Attributes attributes) { - delegate.addLink(spanContext, attributes); - return this; - } - - @Override - public ExtendedSpanBuilder setAttribute(String key, String value) { - delegate.setAttribute(key, value); - return this; - } - - @Override - public ExtendedSpanBuilder setAttribute(String key, long value) { - delegate.setAttribute(key, value); - return this; - } - - @Override - public ExtendedSpanBuilder setAttribute(String key, double value) { - delegate.setAttribute(key, value); - return this; - } - - @Override - public ExtendedSpanBuilder setAttribute(String key, boolean value) { - delegate.setAttribute(key, value); - return this; - } - - @Override - public ExtendedSpanBuilder setAttribute(AttributeKey key, T value) { - delegate.setAttribute(key, value); - return this; - } - - @Override - public ExtendedSpanBuilder setAllAttributes(Attributes attributes) { - delegate.setAllAttributes(attributes); - return this; - } - - @Override - public ExtendedSpanBuilder setSpanKind(SpanKind spanKind) { - delegate.setSpanKind(spanKind); - return this; - } - - @Override - public ExtendedSpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { - delegate.setStartTimestamp(startTimestamp, unit); - return this; - } - - @Override - public ExtendedSpanBuilder setStartTimestamp(Instant startTimestamp) { - delegate.setStartTimestamp(startTimestamp); - return this; - } +/** Extended {@link SpanBuilder} with experimental APIs. */ +public interface ExtendedSpanBuilder extends SpanBuilder { /** * Extract a span context from the given carrier and set it as parent of the span for {@link @@ -124,16 +32,7 @@ public ExtendedSpanBuilder setStartTimestamp(Instant startTimestamp) { * @param propagators provide the propagators from {@link OpenTelemetry#getPropagators()} * @param carrier the string map where to extract the span context from */ - public ExtendedSpanBuilder setParentFrom( - ContextPropagators propagators, Map carrier) { - setParent(ExtendedContextPropagators.extractTextMapPropagationContext(carrier, propagators)); - return this; - } - - @Override - public Span startSpan() { - return delegate.startSpan(); - } + ExtendedSpanBuilder setParentFrom(ContextPropagators propagators, Map carrier); /** * Runs the given {@link SpanCallable} inside of the span created by the given {@link @@ -147,9 +46,7 @@ public Span startSpan() { * @param the type of the exception * @return the result of the {@link SpanCallable} */ - public T startAndCall(SpanCallable spanCallable) throws E { - return startAndCall(spanCallable, ExtendedSpanBuilder::setSpanError); - } + T startAndCall(SpanCallable spanCallable) throws E; /** * Runs the given {@link SpanCallable} inside of the span created by the given {@link @@ -165,20 +62,8 @@ public T startAndCall(SpanCallable spanCallable) * @param the type of the exception * @return the result of the {@link SpanCallable} */ - public T startAndCall( - SpanCallable spanCallable, BiConsumer handleException) throws E { - Span span = startSpan(); - - //noinspection unused - try (Scope unused = span.makeCurrent()) { - return spanCallable.callInSpan(); - } catch (Throwable e) { - handleException.accept(span, e); - throw e; - } finally { - span.end(); - } - } + T startAndCall( + SpanCallable spanCallable, BiConsumer handleException) throws E; /** * Runs the given {@link SpanRunnable} inside of the span created by the given {@link @@ -190,10 +75,7 @@ public T startAndCall( * @param runnable the {@link SpanRunnable} to run * @param the type of the exception */ - @SuppressWarnings("NullAway") - public void startAndRun(SpanRunnable runnable) throws E { - startAndRun(runnable, ExtendedSpanBuilder::setSpanError); - } + void startAndRun(SpanRunnable runnable) throws E; /** * Runs the given {@link SpanRunnable} inside of the span created by the given {@link @@ -206,25 +88,6 @@ public void startAndRun(SpanRunnable runnable) throws E * @param runnable the {@link SpanRunnable} to run * @param the type of the exception */ - @SuppressWarnings("NullAway") - public void startAndRun( - SpanRunnable runnable, BiConsumer handleException) throws E { - startAndCall( - () -> { - runnable.runInSpan(); - return null; - }, - handleException); - } - - /** - * Marks a span as error. This is the default exception handler. - * - * @param span the span - * @param exception the exception that caused the error - */ - private static void setSpanError(Span span, Throwable exception) { - span.setStatus(StatusCode.ERROR); - span.recordException(exception); - } + void startAndRun( + SpanRunnable runnable, BiConsumer handleException) throws E; } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java deleted file mode 100644 index 86ed57df1df..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.trace; - -import io.opentelemetry.api.trace.Tracer; - -/** - * Utility class to simplify tracing. - * - *

The README - * explains the use cases in more detail. - */ -public final class ExtendedTracer implements Tracer { - - private final Tracer delegate; - - private ExtendedTracer(Tracer delegate) { - this.delegate = delegate; - } - - /** - * Creates a new instance of {@link ExtendedTracer}. - * - * @param delegate the {@link Tracer} to use - */ - public static ExtendedTracer create(Tracer delegate) { - return new ExtendedTracer(delegate); - } - - /** - * Creates a new {@link ExtendedSpanBuilder} with the given span name. - * - * @param spanName the name of the span - * @return the {@link ExtendedSpanBuilder} - */ - @Override - public ExtendedSpanBuilder spanBuilder(String spanName) { - return new ExtendedSpanBuilder(delegate.spanBuilder(spanName)); - } -} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java new file mode 100644 index 00000000000..18bc1ec78a8 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java @@ -0,0 +1,211 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.IdGenerator; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import org.junit.jupiter.api.Test; + +/** Demonstrating usage of extended Trace API. */ +class ExtendedTraceApiUsageTest { + + /** Demonstrates {@link ExtendedSpanBuilder#setParentFrom(ContextPropagators, Map)}. */ + @Test + void setParentFrom() { + // Setup SdkTracerProvider + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // SimpleSpanProcessor with InMemorySpanExporter used for demonstration purposes + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + + // Setup ContextPropagators + ContextPropagators contextPropagators = + ContextPropagators.create( + TextMapPropagator.composite(W3CTraceContextPropagator.getInstance())); + + // Get a Tracer for a scope + Tracer tracer = tracerProvider.get("org.foo.my-scope"); + + // Populate a map with W3C trace context + Map contextCarrier = new HashMap<>(); + SpanContext remoteParentContext = + SpanContext.createFromRemoteParent( + IdGenerator.random().generateTraceId(), + IdGenerator.random().generateSpanId(), + TraceFlags.getSampled(), + TraceState.getDefault()); + W3CTraceContextPropagator.getInstance() + .inject( + Context.current().with(Span.wrap(remoteParentContext)), + contextCarrier, + (carrier, key, value) -> { + if (carrier != null) { + carrier.put(key, value); + } + }); + + // Set parent from the Map context carrier + ((ExtendedSpanBuilder) tracer.spanBuilder("local_root")) + .setParentFrom(contextPropagators, contextCarrier) + .startSpan() + .end(); + + // Verify the span has the correct parent context + assertThat(spanExporter.getFinishedSpanItems()) + .satisfiesExactly( + span -> + assertThat(span) + .hasName("local_root") + .hasParentSpanId(remoteParentContext.getSpanId()) + .hasTraceId(remoteParentContext.getTraceId())); + } + + /** + * Demonstrates {@link ExtendedSpanBuilder#startAndCall(SpanCallable)}, {@link + * ExtendedSpanBuilder#startAndCall(SpanCallable, BiConsumer)}, {@link + * ExtendedSpanBuilder#startAndRun(SpanRunnable)}, {@link + * ExtendedSpanBuilder#startAndRun(SpanRunnable, BiConsumer)}. + */ + @Test + void startAndCallOrRun() { + // Setup SdkTracerProvider + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // SimpleSpanProcessor with InMemorySpanExporter used for demonstration purposes + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + + // Get a Tracer for a scope + Tracer tracer = tracerProvider.get("org.foo.my-scope"); + + // Wrap the resetCheckout method in a span + String cartId = + ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout_and_return")) + .startAndCall(() -> resetCheckoutAndReturn("abc123", /* throwException= */ false)); + assertThat(cartId).isEqualTo("abc123"); + // ...or runnable variation + ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout")) + .startAndRun(() -> resetCheckout("abc123", /* throwException= */ false)); + + // Wrap the resetCheckout method in a span; resetCheckout throws an exception + try { + ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout_and_return")) + .startAndCall(() -> resetCheckoutAndReturn("def456", /* throwException= */ true)); + } catch (Throwable e) { + // Ignore expected exception + } + // ...or runnable variation + try { + ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout")) + .startAndRun(() -> resetCheckout("def456", /* throwException= */ true)); + } catch (Throwable e) { + // Ignore expected exception + } + + // Wrap the resetCheckout method in a span; resetCheckout throws an exception; use custom error + // handler + try { + ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout_and_return")) + .startAndCall( + () -> resetCheckoutAndReturn("ghi789", /* throwException= */ true), + (span, throwable) -> span.setAttribute("my-attribute", "error")); + } catch (Throwable e) { + // Ignore expected exception + } + // ...or runnable variation + try { + ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout")) + .startAndRun( + () -> resetCheckout("ghi789", /* throwException= */ true), + (span, throwable) -> span.setAttribute("my-attribute", "error")); + } catch (Throwable e) { + // Ignore expected exception + } + + // Verify the spans are as expected + assertThat(spanExporter.getFinishedSpanItems()) + .satisfiesExactly( + span -> + assertThat(span) + .hasName("reset_checkout_and_return") + .hasAttribute(AttributeKey.stringKey("cartId"), "abc123") + .hasStatus(StatusData.unset()) + .hasTotalRecordedEvents(0), + span -> + assertThat(span) + .hasName("reset_checkout") + .hasAttribute(AttributeKey.stringKey("cartId"), "abc123") + .hasStatus(StatusData.unset()) + .hasTotalRecordedEvents(0), + span -> + assertThat(span) + .hasName("reset_checkout_and_return") + .hasAttribute(AttributeKey.stringKey("cartId"), "def456") + .hasStatus(StatusData.error()) + .hasEventsSatisfyingExactly(event -> event.hasName("exception")), + span -> + assertThat(span) + .hasName("reset_checkout") + .hasAttribute(AttributeKey.stringKey("cartId"), "def456") + .hasStatus(StatusData.error()) + .hasEventsSatisfyingExactly(event -> event.hasName("exception")), + span -> + assertThat(span) + .hasName("reset_checkout_and_return") + .hasAttribute(AttributeKey.stringKey("cartId"), "ghi789") + .hasAttribute(AttributeKey.stringKey("my-attribute"), "error") + .hasStatus(StatusData.unset()) + .hasTotalRecordedEvents(0), + span -> + assertThat(span) + .hasName("reset_checkout") + .hasAttribute(AttributeKey.stringKey("cartId"), "ghi789") + .hasAttribute(AttributeKey.stringKey("my-attribute"), "error") + .hasStatus(StatusData.unset()) + .hasTotalRecordedEvents(0)); + } + + private static String resetCheckoutAndReturn(String cartId, boolean throwException) { + Span.current().setAttribute("cartId", cartId); + if (throwException) { + throw new RuntimeException("Error!"); + } + return cartId; + } + + private static void resetCheckout(String cartId, boolean throwException) { + Span.current().setAttribute("cartId", cartId); + if (throwException) { + throw new RuntimeException("Error!"); + } + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTracerTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTracerTest.java deleted file mode 100644 index 20ad50ca0be..00000000000 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTracerTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.trace; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatException; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.junit.jupiter.api.Named.named; - -import com.google.errorprone.annotations.Keep; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.propagation.ExtendedContextPropagators; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; -import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; -import io.opentelemetry.sdk.trace.data.StatusData; -import io.opentelemetry.semconv.ClientAttributes; -import io.opentelemetry.semconv.ExceptionAttributes; -import java.time.Instant; -import java.util.Collections; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class ExtendedTracerTest { - - interface ThrowingBiConsumer { - void accept(T t, U u) throws Throwable; - } - - @RegisterExtension - static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); - - private final ExtendedTracer extendedTracer = - ExtendedTracer.create(otelTesting.getOpenTelemetry().getTracer("test")); - - @Test - void wrapInSpan() { - assertThatIllegalStateException() - .isThrownBy( - () -> - extendedTracer - .spanBuilder("test") - .startAndRun( - () -> { - // runs in span - throw new IllegalStateException("ex"); - })); - - String result = - extendedTracer - .spanBuilder("another test") - .startAndCall( - () -> { - // runs in span - return "result"; - }); - assertThat(result).isEqualTo("result"); - - otelTesting - .assertTraces() - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("test") - .hasStatus(StatusData.error()) - .hasEventsSatisfyingExactly( - event -> - event - .hasName("exception") - .hasAttributesSatisfyingExactly( - equalTo( - ExceptionAttributes.EXCEPTION_TYPE, - "java.lang.IllegalStateException"), - satisfies( - ExceptionAttributes.EXCEPTION_STACKTRACE, - string -> - string.contains( - "java.lang.IllegalStateException: ex")), - equalTo(ExceptionAttributes.EXCEPTION_MESSAGE, "ex")))), - trace -> trace.hasSpansSatisfyingExactly(a -> a.hasName("another test"))); - } - - @Test - void propagation() { - extendedTracer - .spanBuilder("parent") - .startAndRun( - () -> { - ContextPropagators propagators = otelTesting.getOpenTelemetry().getPropagators(); - Map propagationHeaders = - ExtendedContextPropagators.getTextMapPropagationContext(propagators); - assertThat(propagationHeaders).hasSize(1).containsKey("traceparent"); - - // make sure the parent span is not stored in a thread local anymore - Span invalid = Span.getInvalid(); - //noinspection unused - try (Scope unused = invalid.makeCurrent()) { - extendedTracer - .spanBuilder("child") - .setSpanKind(SpanKind.SERVER) - .setParent(Context.current()) - .setNoParent() - .setParentFrom(propagators, propagationHeaders) - .setAttribute( - "key", - "value") // any method can be called here on the span (and we increase the - // test coverage) - .setAttribute("key2", 0) - .setAttribute("key3", 0.0) - .setAttribute("key4", false) - .setAttribute(ClientAttributes.CLIENT_PORT, 1234L) - .addLink(invalid.getSpanContext()) - .addLink(invalid.getSpanContext(), Attributes.empty()) - .setAllAttributes(Attributes.empty()) - .setStartTimestamp(0, java.util.concurrent.TimeUnit.NANOSECONDS) - .setStartTimestamp(Instant.MIN) - .startAndRun(() -> {}); - } - }); - - otelTesting - .assertTraces() - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - SpanDataAssert::hasNoParent, span -> span.hasParent(trace.getSpan(0)))); - } - - private static class ExtractAndRunParameter { - private final ThrowingBiConsumer> extractAndRun; - private final SpanKind wantKind; - private final StatusData wantStatus; - - private ExtractAndRunParameter( - ThrowingBiConsumer> extractAndRun, - SpanKind wantKind, - StatusData wantStatus) { - this.extractAndRun = extractAndRun; - this.wantKind = wantKind; - this.wantStatus = wantStatus; - } - } - - @Keep - private static Stream extractAndRun() { - BiConsumer ignoreException = - (span, throwable) -> { - // ignore - }; - return Stream.of( - Arguments.of( - named( - "server", - new ExtractAndRunParameter( - (t, c) -> - t.spanBuilder("span") - .setSpanKind(SpanKind.SERVER) - .setParentFrom( - otelTesting.getOpenTelemetry().getPropagators(), - Collections.emptyMap()) - .startAndCall(c), - SpanKind.SERVER, - StatusData.error()))), - Arguments.of( - named( - "server - ignore exception", - new ExtractAndRunParameter( - (t, c) -> - t.spanBuilder("span") - .setSpanKind(SpanKind.SERVER) - .setParentFrom( - otelTesting.getOpenTelemetry().getPropagators(), - Collections.emptyMap()) - .startAndCall(c, ignoreException), - SpanKind.SERVER, - StatusData.unset())))); - } - - @ParameterizedTest - @MethodSource - void extractAndRun(ExtractAndRunParameter parameter) { - assertThatException() - .isThrownBy( - () -> - parameter.extractAndRun.accept( - extendedTracer, - () -> { - throw new RuntimeException("ex"); - })); - - otelTesting - .assertTraces() - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> span.hasKind(parameter.wantKind).hasStatus(parameter.wantStatus))); - } -} diff --git a/sdk/trace/build.gradle.kts b/sdk/trace/build.gradle.kts index ae87071507a..34690eaeeca 100644 --- a/sdk/trace/build.gradle.kts +++ b/sdk/trace/build.gradle.kts @@ -22,6 +22,8 @@ dependencies { api(project(":api:all")) api(project(":sdk:common")) + implementation(project(":api:incubator")) + compileOnly(project(":sdk:trace-shaded-deps")) annotationProcessor("com.google.auto.value:auto-value") diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpanBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpanBuilder.java index fa823fa179a..1a9a946ae5b 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpanBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpanBuilder.java @@ -12,14 +12,21 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.propagation.ExtendedContextPropagators; +import io.opentelemetry.api.incubator.trace.ExtendedSpanBuilder; +import io.opentelemetry.api.incubator.trace.SpanCallable; +import io.opentelemetry.api.incubator.trace.SpanRunnable; import io.opentelemetry.api.internal.ImmutableSpanContext; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.AttributeUtil; import io.opentelemetry.sdk.internal.AttributesMap; @@ -29,11 +36,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import javax.annotation.Nullable; /** {@link SdkSpanBuilder} is SDK implementation of {@link SpanBuilder}. */ -final class SdkSpanBuilder implements SpanBuilder { +final class SdkSpanBuilder implements ExtendedSpanBuilder { private final String spanName; private final InstrumentationScopeInfo instrumentationScopeInfo; @@ -163,6 +172,13 @@ public SpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { return this; } + @Override + public ExtendedSpanBuilder setParentFrom( + ContextPropagators propagators, Map carrier) { + setParent(ExtendedContextPropagators.extractTextMapPropagationContext(carrier, propagators)); + return this; + } + @Override @SuppressWarnings({"unchecked", "rawtypes"}) public Span startSpan() { @@ -234,6 +250,44 @@ public Span startSpan() { startEpochNanos); } + @Override + public T startAndCall(SpanCallable spanCallable) throws E { + return startAndCall(spanCallable, SdkSpanBuilder::setSpanError); + } + + @Override + public T startAndCall( + SpanCallable spanCallable, BiConsumer handleException) throws E { + Span span = startSpan(); + + //noinspection unused + try (Scope unused = span.makeCurrent()) { + return spanCallable.callInSpan(); + } catch (Throwable e) { + handleException.accept(span, e); + throw e; + } finally { + span.end(); + } + } + + @Override + public void startAndRun(SpanRunnable runnable) throws E { + startAndRun(runnable, SdkSpanBuilder::setSpanError); + } + + @SuppressWarnings("NullAway") + @Override + public void startAndRun( + SpanRunnable runnable, BiConsumer handleException) throws E { + startAndCall( + () -> { + runnable.runInSpan(); + return null; + }, + handleException); + } + private AttributesMap attributes() { AttributesMap attributes = this.attributes; if (attributes == null) { @@ -255,4 +309,15 @@ static boolean isRecording(SamplingDecision decision) { static boolean isSampled(SamplingDecision decision) { return SamplingDecision.RECORD_AND_SAMPLE.equals(decision); } + + /** + * Marks a span as error. This is the default exception handler. + * + * @param span the span + * @param exception the exception that caused the error + */ + private static void setSpanError(Span span, Throwable exception) { + span.setStatus(StatusCode.ERROR); + span.recordException(exception); + } } From d6316ef634278f866d3c082acb44bb920eb56b16 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 4 Jun 2024 13:48:40 -0500 Subject: [PATCH 2/3] Implement Tracer, Meter (instrument), Tracer enabled APIs --- .../api/incubator/logs/ExtendedLogger.java | 23 +++ .../metrics/ExtendedDoubleCounter.java | 26 +++ .../metrics/ExtendedDoubleGauge.java | 26 +++ .../metrics/ExtendedDoubleHistogram.java | 26 +++ .../metrics/ExtendedDoubleUpDownCounter.java | 26 +++ .../metrics/ExtendedLongCounter.java | 27 +++ .../incubator/metrics/ExtendedLongGauge.java | 26 +++ .../metrics/ExtendedLongHistogram.java | 26 +++ .../metrics/ExtendedLongUpDownCounter.java | 26 +++ .../api/incubator/trace/ExtendedTracer.java | 23 +++ .../logs/ExtendedLogsBridgeApiUsageTest.java | 61 +++++++ .../metrics/ExtendedMetricsApiUsageTest.java | 56 +++++++ .../trace/ExtendedTraceApiUsageTest.java | 60 +++++++ .../io/opentelemetry/sdk/logs/SdkLogger.java | 14 +- .../sdk/logs/LoggerConfigTest.java | 5 + .../sdk/metrics/InstrumentBuilder.java | 14 +- .../sdk/metrics/SdkDoubleCounter.java | 16 +- .../sdk/metrics/SdkDoubleGauge.java | 16 +- .../sdk/metrics/SdkDoubleHistogram.java | 16 +- .../sdk/metrics/SdkDoubleUpDownCounter.java | 16 +- .../sdk/metrics/SdkLongCounter.java | 16 +- .../sdk/metrics/SdkLongGauge.java | 16 +- .../sdk/metrics/SdkLongHistogram.java | 16 +- .../sdk/metrics/SdkLongUpDownCounter.java | 15 +- .../opentelemetry/sdk/metrics/SdkMeter.java | 16 +- .../DefaultSynchronousMetricStorage.java | 5 + .../internal/state/EmptyMetricStorage.java | 5 + .../internal/state/MeterSharedState.java | 26 ++- .../state/MultiWritableMetricStorage.java | 10 ++ .../state/WriteableMetricStorage.java | 6 + .../sdk/metrics/InstrumentBuilderTest.java | 3 +- .../sdk/metrics/MeterConfigTest.java | 156 ++++++++++++++---- .../metrics/SdkObservableInstrumentTest.java | 7 +- .../state/MetricStorageRegistryTest.java | 5 + .../io/opentelemetry/sdk/trace/SdkTracer.java | 14 +- .../sdk/trace/TracerConfigTest.java | 5 + 36 files changed, 769 insertions(+), 81 deletions(-) create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java new file mode 100644 index 00000000000..ea5dc49fac5 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.logs; + +import io.opentelemetry.api.logs.Logger; + +/** Extended {@link Logger} with experimental APIs. */ +public interface ExtendedLogger extends Logger { + + /** + * Returns {@code true} if the logger is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #logRecordBuilder()}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java new file mode 100644 index 00000000000..fcd6e26771b --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleCounter} with experimental APIs. */ +public interface ExtendedDoubleCounter extends DoubleCounter { + + /** + * Returns {@code true} if the counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(double)}, {@link #add(double, Attributes)}, or {@link #add(double, + * Attributes, Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java new file mode 100644 index 00000000000..c149de023ff --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleGauge; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleGauge} with experimental APIs. */ +public interface ExtendedDoubleGauge extends DoubleGauge { + + /** + * Returns {@code true} if the gauge is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #set(double)}, {@link #set(double, Attributes)}, or {@link #set(double, + * Attributes, Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java new file mode 100644 index 00000000000..62136270565 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleHistogram} with experimental APIs. */ +public interface ExtendedDoubleHistogram extends DoubleHistogram { + + /** + * Returns {@code true} if the histogram is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #record(double)}, {@link #record(double, Attributes)}, or {@link #record(double, + * Attributes, Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java new file mode 100644 index 00000000000..7bed94da09e --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleUpDownCounter} with experimental APIs. */ +public interface ExtendedDoubleUpDownCounter extends DoubleUpDownCounter { + + /** + * Returns {@code true} if the up down counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(double)}, {@link #add(double, Attributes)}, or {@link #add(double, + * Attributes, Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java new file mode 100644 index 00000000000..2df247e5065 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleCounter} with experimental APIs. */ +public interface ExtendedLongCounter extends LongCounter { + + /** + * Returns {@code true} if the counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(long)}, {@link #add(long, Attributes)}, or {@link #add(long, Attributes, + * Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java new file mode 100644 index 00000000000..e8058179e27 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.context.Context; + +/** Extended {@link LongGauge} with experimental APIs. */ +public interface ExtendedLongGauge extends LongGauge { + + /** + * Returns {@code true} if the gauge is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #set(long)}, {@link #set(long, Attributes)}, or {@link #set(long, Attributes, + * Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java new file mode 100644 index 00000000000..86aecd0e11f --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.context.Context; + +/** Extended {@link LongHistogram} with experimental APIs. */ +public interface ExtendedLongHistogram extends LongHistogram { + + /** + * Returns {@code true} if the histogram is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #record(long)}, {@link #record(long, Attributes)}, or {@link #record(long, + * Attributes, Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java new file mode 100644 index 00000000000..7b8d50fe623 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link LongUpDownCounter} with experimental APIs. */ +public interface ExtendedLongUpDownCounter extends LongUpDownCounter { + + /** + * Returns {@code true} if the up down counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(long)}, {@link #add(long, Attributes)}, or {@link #add(long, Attributes, + * Context)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java new file mode 100644 index 00000000000..66bdb31a21c --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import io.opentelemetry.api.trace.Tracer; + +/** Extended {@link Tracer} with experimental APIs. */ +public interface ExtendedTracer extends Tracer { + + /** + * Returns {@code true} if the tracer is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #spanBuilder(String)}. + */ + default boolean enabled() { + return true; + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java index 7a1f82e64d0..8c55abcef71 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java @@ -5,21 +5,82 @@ package io.opentelemetry.api.incubator.logs; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.logs.internal.LoggerConfig.disabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import com.google.common.collect.ImmutableMap; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; import io.opentelemetry.sdk.logs.internal.AnyValueBody; +import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import java.util.Random; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Logs Bridge API. */ class ExtendedLogsBridgeApiUsageTest { + @Test + void loggerEnabled() { + // Setup SdkLoggerProvider + InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); + SdkLoggerProviderBuilder loggerProviderBuilder = + SdkLoggerProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // In-memory exporter used for demonstration purposes + .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)); + // Disable loggerB + SdkLoggerProviderUtil.addLoggerConfiguratorCondition( + loggerProviderBuilder, nameEquals("loggerB"), disabled()); + SdkLoggerProvider loggerProvider = loggerProviderBuilder.build(); + + // Create loggerA and loggerB + ExtendedLogger loggerA = (ExtendedLogger) loggerProvider.get("loggerA"); + ExtendedLogger loggerB = (ExtendedLogger) loggerProvider.get("loggerB"); + + // Check if logger is enabled before emitting log and avoid unnecessary computation + if (loggerA.enabled()) { + loggerA + .logRecordBuilder() + .setBody("hello world!") + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .emit(); + } + if (loggerB.enabled()) { + loggerB + .logRecordBuilder() + .setBody("hello world!") + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .emit(); + } + + // loggerA is enabled, loggerB is disabled + assertThat(loggerA.enabled()).isTrue(); + assertThat(loggerB.enabled()).isFalse(); + + // Collected data only consists of logs from loggerA. Note, loggerB's logs would be + // omitted from the results even if logs were emitted. The check if enabled simply avoids + // unnecessary computation. + assertThat(exporter.getFinishedLogRecordItems()) + .allSatisfy( + logRecordData -> + assertThat(logRecordData.getInstrumentationScopeInfo().getName()) + .isEqualTo("loggerA")); + } + + private static final Random random = new Random(); + + private static String flipCoin() { + return random.nextBoolean() ? "heads" : "tails"; + } + @Test void extendedLogRecordBuilderUsage() { // Setup SdkLoggerProvider diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java index 5ae6297a2c7..eb2d69ba302 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java @@ -5,6 +5,8 @@ package io.opentelemetry.api.incubator.metrics; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.metrics.internal.MeterConfig.disabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import com.google.common.collect.ImmutableList; @@ -15,14 +17,68 @@ import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.metrics.InstrumentSelector; import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.View; +import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import java.util.Random; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Metrics API. */ class ExtendedMetricsApiUsageTest { + @Test + void meterEnabled() { + // Setup SdkMeterProvider + InMemoryMetricReader reader = InMemoryMetricReader.create(); + SdkMeterProviderBuilder meterProviderBuilder = + SdkMeterProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // In-memory reader used for demonstration purposes + .registerMetricReader(reader); + // Disable meterB + SdkMeterProviderUtil.addMeterConfiguratorCondition( + meterProviderBuilder, nameEquals("meterB"), disabled()); + SdkMeterProvider meterProvider = meterProviderBuilder.build(); + + // Create meterA and meterB, and corresponding instruments + Meter meterA = meterProvider.get("meterA"); + Meter meterB = meterProvider.get("meterB"); + ExtendedDoubleHistogram histogramA = + (ExtendedDoubleHistogram) meterA.histogramBuilder("histogramA").build(); + ExtendedDoubleHistogram histogramB = + (ExtendedDoubleHistogram) meterB.histogramBuilder("histogramB").build(); + + // Check if instrument is enabled before recording measurement and avoid unnecessary computation + if (histogramA.enabled()) { + histogramA.record(1.0, Attributes.builder().put("result", flipCoin()).build()); + } + if (histogramB.enabled()) { + histogramA.record(1.0, Attributes.builder().put("result", flipCoin()).build()); + } + + // histogramA is enabled since meterA is enabled, histogramB is disabled since meterB is + // disabled + assertThat(histogramA.enabled()).isTrue(); + assertThat(histogramB.enabled()).isFalse(); + + // Collected data only consists of metrics from meterA. Note, meterB's histogramB would be + // omitted from the results even if values were recorded. The check if enabled simply avoids + // unnecessary computation. + assertThat(reader.collectAllMetrics()) + .allSatisfy( + metric -> + assertThat(metric.getInstrumentationScopeInfo().getName()).isEqualTo("meterA")); + } + + private static final Random random = new Random(); + + private static String flipCoin() { + return random.nextBoolean() ? "heads" : "tails"; + } + @Test void attributesAdvice() { // Setup SdkMeterProvider diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java index 18bc1ec78a8..cdefd2d84c3 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java @@ -5,9 +5,12 @@ package io.opentelemetry.api.incubator.trace; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.trace.internal.TracerConfig.disabled; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.TraceFlags; @@ -21,16 +24,73 @@ import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.IdGenerator; import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import io.opentelemetry.sdk.trace.internal.SdkTracerProviderUtil; import java.util.HashMap; import java.util.Map; +import java.util.Random; import java.util.function.BiConsumer; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Trace API. */ class ExtendedTraceApiUsageTest { + @Test + void tracerEnabled() { + // Setup SdkTracerProvider + InMemorySpanExporter exporter = InMemorySpanExporter.create(); + SdkTracerProviderBuilder tracerProviderBuilder = + SdkTracerProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // In-memory exporter used for demonstration purposes + .addSpanProcessor(SimpleSpanProcessor.create(exporter)); + // Disable tracerB + SdkTracerProviderUtil.addTracerConfiguratorCondition( + tracerProviderBuilder, nameEquals("tracerB"), disabled()); + SdkTracerProvider tracerProvider = tracerProviderBuilder.build(); + + // Create tracerA and tracerB + ExtendedTracer tracerA = (ExtendedTracer) tracerProvider.get("tracerA"); + ExtendedTracer tracerB = (ExtendedTracer) tracerProvider.get("tracerB"); + + // Check if tracer is enabled before recording span and avoid unnecessary computation + if (tracerA.enabled()) { + tracerA + .spanBuilder("span name") + .startSpan() + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .end(); + } + if (tracerB.enabled()) { + tracerB + .spanBuilder("span name") + .startSpan() + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .end(); + } + + // tracerA is enabled, tracerB is disabled + assertThat(tracerA.enabled()).isTrue(); + assertThat(tracerB.enabled()).isFalse(); + + // Collected data only consists of spans from tracerA. Note, tracerB's spans would be + // omitted from the results even if spans were recorded. The check if enabled simply avoids + // unnecessary computation. + assertThat(exporter.getFinishedSpanItems()) + .allSatisfy( + spanData -> + assertThat(spanData.getInstrumentationScopeInfo().getName()).isEqualTo("tracerA")); + } + + private static final Random random = new Random(); + + private static String flipCoin() { + return random.nextBoolean() ? "heads" : "tails"; + } + /** Demonstrates {@link ExtendedSpanBuilder#setParentFrom(ContextPropagators, Map)}. */ @Test void setParentFrom() { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index 74bad693bfa..39c6592c3fd 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.logs; +import io.opentelemetry.api.incubator.logs.ExtendedLogger; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; @@ -12,13 +13,13 @@ import io.opentelemetry.sdk.logs.internal.LoggerConfig; /** SDK implementation of {@link Logger}. */ -final class SdkLogger implements Logger { +final class SdkLogger implements ExtendedLogger { private static final Logger NOOP_LOGGER = LoggerProvider.noop().get("noop"); private final LoggerSharedState loggerSharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; - private final LoggerConfig loggerConfig; + private final boolean loggerEnabled; SdkLogger( LoggerSharedState loggerSharedState, @@ -26,12 +27,12 @@ final class SdkLogger implements Logger { LoggerConfig loggerConfig) { this.loggerSharedState = loggerSharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; - this.loggerConfig = loggerConfig; + this.loggerEnabled = loggerConfig.isEnabled(); } @Override public LogRecordBuilder logRecordBuilder() { - if (loggerConfig.isEnabled()) { + if (loggerEnabled) { return new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); } return NOOP_LOGGER.logRecordBuilder(); @@ -41,4 +42,9 @@ public LogRecordBuilder logRecordBuilder() { InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + + @Override + public boolean enabled() { + return loggerEnabled; + } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 371098267eb..3dabd823adf 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -11,6 +11,7 @@ import static io.opentelemetry.sdk.logs.internal.LoggerConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import io.opentelemetry.api.incubator.logs.ExtendedLogger; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ScopeConfigurator; @@ -59,6 +60,10 @@ void disableScopes() { assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerB"))).isNull(); assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerC"))).hasSize(1); }); + // loggerA and loggerC are enabled, loggerB is disabled. + assertThat(((ExtendedLogger) loggerA).enabled()).isTrue(); + assertThat(((ExtendedLogger) loggerB).enabled()).isFalse(); + assertThat(((ExtendedLogger) loggerC).enabled()).isTrue(); } @ParameterizedTest diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java index f1da522e15b..afed0778796 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java @@ -17,7 +17,6 @@ import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage; import java.util.Collections; import java.util.List; -import java.util.function.BiFunction; import java.util.function.Consumer; /** Helper to make implementing builders easier. */ @@ -65,12 +64,21 @@ T swapBuilder(SwapBuilder swapper) { meterProviderSharedState, meterSharedState, name, description, unit, adviceBuilder); } + @FunctionalInterface + interface SynchronousInstrumentConstructor { + + I createInstrument( + InstrumentDescriptor instrumentDescriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage); + } + I buildSynchronousInstrument( - BiFunction instrumentFactory) { + SynchronousInstrumentConstructor instrumentFactory) { InstrumentDescriptor descriptor = newDescriptor(); WriteableMetricStorage storage = meterSharedState.registerSynchronousMetricStorage(descriptor, meterProviderSharedState); - return instrumentFactory.apply(descriptor, storage); + return instrumentFactory.createInstrument(descriptor, meterSharedState, storage); } SdkObservableInstrument buildDoubleAsynchronousInstrument( diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java index d7aa5f47cad..14a0aa18a1e 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounter; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounterBuilder; -import io.opentelemetry.api.metrics.DoubleCounter; import io.opentelemetry.api.metrics.DoubleCounterBuilder; import io.opentelemetry.api.metrics.ObservableDoubleCounter; import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; @@ -24,14 +24,19 @@ import java.util.logging.Level; import java.util.logging.Logger; -final class SdkDoubleCounter extends AbstractInstrument implements DoubleCounter { +final class SdkDoubleCounter extends AbstractInstrument implements ExtendedDoubleCounter { private static final Logger logger = Logger.getLogger(SdkDoubleCounter.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -58,6 +63,11 @@ public void add(double increment) { add(increment, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleCounterBuilder implements ExtendedDoubleCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java index 1c834b18e10..a414d44269e 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGauge; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGaugeBuilder; -import io.opentelemetry.api.metrics.DoubleGauge; import io.opentelemetry.api.metrics.DoubleGaugeBuilder; import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableDoubleGauge; @@ -21,12 +21,17 @@ import java.util.List; import java.util.function.Consumer; -final class SdkDoubleGauge extends AbstractInstrument implements DoubleGauge { +final class SdkDoubleGauge extends AbstractInstrument implements ExtendedDoubleGauge { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleGauge(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleGauge( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +50,11 @@ public void set(double increment) { set(increment, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleGaugeBuilder implements ExtendedDoubleGaugeBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java index 15dd7d2f8c7..ba39d892406 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogram; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogramBuilder; -import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.DoubleHistogramBuilder; import io.opentelemetry.api.metrics.LongHistogramBuilder; import io.opentelemetry.context.Context; @@ -23,14 +23,19 @@ import java.util.logging.Level; import java.util.logging.Logger; -final class SdkDoubleHistogram extends AbstractInstrument implements DoubleHistogram { +final class SdkDoubleHistogram extends AbstractInstrument implements ExtendedDoubleHistogram { private static final Logger logger = Logger.getLogger(SdkDoubleHistogram.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleHistogram(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleHistogram( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -57,6 +62,11 @@ public void record(double value) { record(value, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleHistogramBuilder implements ExtendedDoubleHistogramBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java index 57188aa6a23..b391315f780 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleUpDownCounter; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleUpDownCounterBuilder; import io.opentelemetry.api.metrics.DoubleUpDownCounter; import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder; @@ -21,12 +22,18 @@ import java.util.List; import java.util.function.Consumer; -final class SdkDoubleUpDownCounter extends AbstractInstrument implements DoubleUpDownCounter { +final class SdkDoubleUpDownCounter extends AbstractInstrument + implements ExtendedDoubleUpDownCounter { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleUpDownCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleUpDownCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +52,11 @@ public void add(double increment) { add(increment, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleUpDownCounterBuilder implements ExtendedDoubleUpDownCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java index 3847bf716f3..387a47d93cd 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java @@ -7,9 +7,9 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongCounter; import io.opentelemetry.api.incubator.metrics.ExtendedLongCounterBuilder; import io.opentelemetry.api.metrics.DoubleCounterBuilder; -import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongCounterBuilder; import io.opentelemetry.api.metrics.ObservableLongCounter; import io.opentelemetry.api.metrics.ObservableLongMeasurement; @@ -24,15 +24,20 @@ import java.util.logging.Level; import java.util.logging.Logger; -final class SdkLongCounter extends AbstractInstrument implements LongCounter { +final class SdkLongCounter extends AbstractInstrument implements ExtendedLongCounter { private static final Logger logger = Logger.getLogger(SdkLongCounter.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -59,6 +64,11 @@ public void add(long increment) { add(increment, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongCounterBuilder implements ExtendedLongCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java index ad7db428bdf..cc27bf8486e 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongGauge; import io.opentelemetry.api.incubator.metrics.ExtendedLongGaugeBuilder; -import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableLongGauge; import io.opentelemetry.api.metrics.ObservableLongMeasurement; @@ -21,12 +21,17 @@ import java.util.List; import java.util.function.Consumer; -final class SdkLongGauge extends AbstractInstrument implements LongGauge { +final class SdkLongGauge extends AbstractInstrument implements ExtendedLongGauge { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongGauge(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongGauge( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +50,11 @@ public void set(long increment) { set(increment, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongGaugeBuilder implements ExtendedLongGaugeBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java index b2975886565..3a495324137 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogram; import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogramBuilder; -import io.opentelemetry.api.metrics.LongHistogram; import io.opentelemetry.api.metrics.LongHistogramBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.internal.ThrottlingLogger; @@ -24,14 +24,19 @@ import java.util.logging.Logger; import java.util.stream.Collectors; -final class SdkLongHistogram extends AbstractInstrument implements LongHistogram { +final class SdkLongHistogram extends AbstractInstrument implements ExtendedLongHistogram { private static final Logger logger = Logger.getLogger(SdkLongHistogram.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongHistogram(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongHistogram( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -58,6 +63,11 @@ public void record(long value) { record(value, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongHistogramBuilder implements ExtendedLongHistogramBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java index 4530f3b8405..fd0d417c541 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongUpDownCounter; import io.opentelemetry.api.incubator.metrics.ExtendedLongUpDownCounterBuilder; import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder; import io.opentelemetry.api.metrics.LongUpDownCounter; @@ -21,12 +22,17 @@ import java.util.List; import java.util.function.Consumer; -final class SdkLongUpDownCounter extends AbstractInstrument implements LongUpDownCounter { +final class SdkLongUpDownCounter extends AbstractInstrument implements ExtendedLongUpDownCounter { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongUpDownCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongUpDownCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +51,11 @@ public void add(long increment) { add(increment, Attributes.empty()); } + @Override + public boolean enabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongUpDownCounterBuilder implements ExtendedLongUpDownCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java index bb76fe6701a..da57ef3506c 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java @@ -56,7 +56,6 @@ final class SdkMeter implements Meter { private final InstrumentationScopeInfo instrumentationScopeInfo; private final MeterProviderSharedState meterProviderSharedState; private final MeterSharedState meterSharedState; - private final MeterConfig meterConfig; SdkMeter( MeterProviderSharedState meterProviderSharedState, @@ -65,8 +64,8 @@ final class SdkMeter implements Meter { MeterConfig meterConfig) { this.instrumentationScopeInfo = instrumentationScopeInfo; this.meterProviderSharedState = meterProviderSharedState; - this.meterSharedState = MeterSharedState.create(instrumentationScopeInfo, registeredReaders); - this.meterConfig = meterConfig; + this.meterSharedState = + MeterSharedState.create(instrumentationScopeInfo, registeredReaders, meterConfig); } // Visible for testing @@ -86,14 +85,14 @@ void resetForTest() { @Override public LongCounterBuilder counterBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkLongCounter.SdkLongCounterBuilder(meterProviderSharedState, meterSharedState, name) : NOOP_METER.counterBuilder(NOOP_INSTRUMENT_NAME); } @Override public LongUpDownCounterBuilder upDownCounterBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkLongUpDownCounter.SdkLongUpDownCounterBuilder( meterProviderSharedState, meterSharedState, name) : NOOP_METER.upDownCounterBuilder(NOOP_INSTRUMENT_NAME); @@ -101,7 +100,7 @@ public LongUpDownCounterBuilder upDownCounterBuilder(String name) { @Override public DoubleHistogramBuilder histogramBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkDoubleHistogram.SdkDoubleHistogramBuilder( meterProviderSharedState, meterSharedState, name) : NOOP_METER.histogramBuilder(NOOP_INSTRUMENT_NAME); @@ -109,7 +108,7 @@ public DoubleHistogramBuilder histogramBuilder(String name) { @Override public DoubleGaugeBuilder gaugeBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkDoubleGauge.SdkDoubleGaugeBuilder(meterProviderSharedState, meterSharedState, name) : NOOP_METER.gaugeBuilder(NOOP_INSTRUMENT_NAME); } @@ -119,9 +118,6 @@ public BatchCallback batchCallback( Runnable callback, ObservableMeasurement observableMeasurement, ObservableMeasurement... additionalMeasurements) { - if (!meterConfig.isEnabled()) { - return NOOP_METER.batchCallback(callback, observableMeasurement, additionalMeasurements); - } Set measurements = new HashSet<>(); measurements.add(observableMeasurement); Collections.addAll(measurements, additionalMeasurements); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java index 191223bfeac..c0deda9d068 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java @@ -131,6 +131,11 @@ public void recordDouble(double value, Attributes attributes, Context context) { } } + @Override + public boolean isEnabled() { + return true; + } + /** * Obtain the AggregatorHolder for recording measurements, re-reading the volatile * this.aggregatorHolder until we access one where recordsInProgress is even. Collect sets diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java index d076178d193..faaa7087c76 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java @@ -39,4 +39,9 @@ public void recordLong(long value, Attributes attributes, Context context) {} @Override public void recordDouble(double value, Attributes attributes, Context context) {} + + @Override + public boolean isEnabled() { + return false; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java index 64ecefd5385..30a3a838c45 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java @@ -11,11 +11,13 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -36,20 +38,25 @@ public class MeterSharedState { private final List callbackRegistrations = new ArrayList<>(); private final Map readerStorageRegistries; - private final InstrumentationScopeInfo instrumentationScopeInfo; + private final boolean meterEnabled; private MeterSharedState( - InstrumentationScopeInfo instrumentationScopeInfo, List registeredReaders) { + InstrumentationScopeInfo instrumentationScopeInfo, + List registeredReaders, + MeterConfig meterConfig) { this.instrumentationScopeInfo = instrumentationScopeInfo; this.readerStorageRegistries = registeredReaders.stream() .collect(toMap(Function.identity(), unused -> new MetricStorageRegistry())); + this.meterEnabled = meterConfig.isEnabled(); } public static MeterSharedState create( - InstrumentationScopeInfo instrumentationScopeInfo, List registeredReaders) { - return new MeterSharedState(instrumentationScopeInfo, registeredReaders); + InstrumentationScopeInfo instrumentationScopeInfo, + List registeredReaders, + MeterConfig meterConfig) { + return new MeterSharedState(instrumentationScopeInfo, registeredReaders, meterConfig); } /** @@ -81,11 +88,20 @@ public InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + /** Returns {@code true} if the {@link MeterConfig#enabled()} of the meter is {@code true}. */ + public boolean isMeterEnabled() { + return meterEnabled; + } + /** Collects all metrics. */ public List collectAll( RegisteredReader registeredReader, MeterProviderSharedState meterProviderSharedState, long epochNanos) { + // Short circuit collection process if meter is disabled + if (!meterEnabled) { + return Collections.emptyList(); + } List currentRegisteredCallbacks; synchronized (callbackLock) { currentRegisteredCallbacks = new ArrayList<>(callbackRegistrations); @@ -113,7 +129,7 @@ public List collectAll( result.add(current); } } - return result; + return Collections.unmodifiableList(result); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java index 59632a9cc4a..700fee4c3fb 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java @@ -29,4 +29,14 @@ public void recordDouble(double value, Attributes attributes, Context context) { storage.recordDouble(value, attributes, context); } } + + @Override + public boolean isEnabled() { + for (WriteableMetricStorage storage : storages) { + if (storage.isEnabled()) { + return true; + } + } + return false; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java index 77e2dd510b8..7191a63f1e0 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java @@ -22,4 +22,10 @@ public interface WriteableMetricStorage { /** Records a measurement. */ void recordDouble(double value, Attributes attributes, Context context); + + /** + * Returns {@code true} if the storage is actively recording measurements, and {@code false} + * otherwise (i.e. noop / empty metric storage is installed). + */ + boolean isEnabled(); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java index a351c95d0e6..c6ef1957428 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; @@ -24,7 +25,7 @@ class InstrumentBuilderTest { TestClock.create(), Resource.getDefault(), ExemplarFilter.alwaysOff(), 0); static final InstrumentationScopeInfo SCOPE = InstrumentationScopeInfo.create("scope-name"); public static final MeterSharedState METER_SHARED_STATE = - MeterSharedState.create(SCOPE, Collections.emptyList()); + MeterSharedState.create(SCOPE, Collections.emptyList(), MeterConfig.defaultConfig()); @Test void stringRepresentation() { diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java index 3b78f2abd0d..06d716bebc2 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -11,7 +11,16 @@ import static io.opentelemetry.sdk.metrics.internal.MeterConfig.disabled; import static io.opentelemetry.sdk.metrics.internal.MeterConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static java.util.stream.Collectors.groupingBy; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounter; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGauge; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogram; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleUpDownCounter; +import io.opentelemetry.api.incubator.metrics.ExtendedLongCounter; +import io.opentelemetry.api.incubator.metrics.ExtendedLongGauge; +import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogram; +import io.opentelemetry.api.incubator.metrics.ExtendedLongUpDownCounter; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ScopeConfigurator; @@ -20,7 +29,7 @@ import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -37,50 +46,135 @@ void disableScopes() { // Disable meterB. Since meters are enabled by default, meterA and meterC are enabled. .addMeterConfiguratorCondition(nameEquals("meterB"), disabled()) .registerMetricReader(reader) + // Register drop aggregation for all instruments of meterD. Instruments are disabled if + // their relevant MeterConfig is disabled, or if there are no resolved views which + // consume the measurements. + .registerView( + InstrumentSelector.builder().setMeterName("meterD").build(), + View.builder().setAggregation(Aggregation.drop()).build()) .build(); Meter meterA = meterProvider.get("meterA"); Meter meterB = meterProvider.get("meterB"); Meter meterC = meterProvider.get("meterC"); + Meter meterD = meterProvider.get("meterD"); + AtomicLong meterAInvocations = new AtomicLong(); + AtomicLong meterBInvocations = new AtomicLong(); + AtomicLong meterCInvocations = new AtomicLong(); + AtomicLong meterDInvocations = new AtomicLong(); - meterA.counterBuilder("counterA").build().add(1); - meterA.counterBuilder("asyncCounterA").buildWithCallback(observable -> observable.record(1)); - meterA.upDownCounterBuilder("upDownCounterA").build().add(1); - meterA - .upDownCounterBuilder("asyncUpDownCounterA") - .buildWithCallback(observable -> observable.record(1)); - meterA.histogramBuilder("histogramA").build().record(1.0); - meterA.gaugeBuilder("gaugeA").buildWithCallback(observable -> observable.record(1.0)); - - meterB.counterBuilder("counterB").build().add(1); - meterB.counterBuilder("asyncCounterB").buildWithCallback(observable -> observable.record(1)); - meterB.upDownCounterBuilder("upDownCounterB").build().add(1); - meterB - .upDownCounterBuilder("asyncUpDownCounterB") - .buildWithCallback(observable -> observable.record(1)); - meterB.histogramBuilder("histogramB").build().record(1.0); - meterB.gaugeBuilder("gaugeB").buildWithCallback(observable -> observable.record(1.0)); - - meterC.counterBuilder("counterC").build().add(1); - meterC.counterBuilder("asyncCounterC").buildWithCallback(observable -> observable.record(1)); - meterC.upDownCounterBuilder("upDownCounterC").build().add(1); - meterC - .upDownCounterBuilder("asyncUpDownCounterC") - .buildWithCallback(observable -> observable.record(1)); - meterC.histogramBuilder("histogramC").build().record(1.0); - meterC.gaugeBuilder("gaugeC").buildWithCallback(observable -> observable.record(1.0)); + // Record measurements to each instrument type + recordToMeterInstruments(meterA, meterAInvocations); + recordToMeterInstruments(meterB, meterBInvocations); + recordToMeterInstruments(meterC, meterCInvocations); + recordToMeterInstruments(meterD, meterDInvocations); // Only metrics from meterA and meterC should be seen assertThat(reader.collectAllMetrics()) .satisfies( metrics -> { Map> metricsByScope = - metrics.stream() - .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterA"))).hasSize(6); + metrics.stream().collect(groupingBy(MetricData::getInstrumentationScopeInfo)); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterA"))).hasSize(14); assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterB"))).isNull(); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterC"))).hasSize(6); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterC"))).hasSize(14); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterD"))).isNull(); + }); + // Only async callbacks from meterA and meterC should be invoked + assertThat(meterAInvocations.get()).isPositive(); + assertThat(meterBInvocations.get()).isZero(); + assertThat(meterCInvocations.get()).isPositive(); + assertThat(meterDInvocations.get()).isZero(); + // Instruments from meterA and meterC are enabled, meterC is not enabled + assertMeterInstrumentsEnabled(meterA, /* expectedEnabled= */ true); + assertMeterInstrumentsEnabled(meterB, /* expectedEnabled= */ false); + assertMeterInstrumentsEnabled(meterC, /* expectedEnabled= */ true); + assertMeterInstrumentsEnabled(meterD, /* expectedEnabled= */ false); + } + + private static void recordToMeterInstruments(Meter meter, AtomicLong asyncInvocationsCount) { + meter.counterBuilder("longCounter").build().add(1); + meter.counterBuilder("doubleCounter").ofDoubles().build().add(1); + meter + .counterBuilder("asyncLongCounter") + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + meter + .counterBuilder("asyncDoubleCounter") + .ofDoubles() + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); }); + meter.upDownCounterBuilder("longUpDownCounter").build().add(1); + meter.upDownCounterBuilder("doubleUpDownCounter").ofDoubles().build().add(1); + meter + .upDownCounterBuilder("asyncLongUpDownCounter") + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + meter + .upDownCounterBuilder("asyncDoubleUpDownCounter") + .ofDoubles() + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + meter.histogramBuilder("doubleHistogram").build().record(1.0); + meter.histogramBuilder("longHistogram").ofLongs().build().record(1); + meter.gaugeBuilder("doubleGauge").build().set(1); + meter.gaugeBuilder("longGauge").ofLongs().build().set(1); + meter + .gaugeBuilder("asyncDoubleGauge") + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1.0); + }); + meter + .gaugeBuilder("asyncLongGauge") + .ofLongs() + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + } + + private static void assertMeterInstrumentsEnabled(Meter meter, boolean expectedEnabled) { + assertThat( + ((ExtendedDoubleCounter) meter.counterBuilder("doubleCounter").ofDoubles().build()) + .enabled()) + .isEqualTo(expectedEnabled); + assertThat(((ExtendedLongCounter) meter.counterBuilder("longCounter").build()).enabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedDoubleUpDownCounter) + meter.upDownCounterBuilder("doubleUpDownCounter").ofDoubles().build()) + .enabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedLongUpDownCounter) meter.upDownCounterBuilder("longUpDownCounter").build()) + .enabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedDoubleHistogram) meter.histogramBuilder("doubleHistogram").build()).enabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedLongHistogram) meter.histogramBuilder("longHistogram").ofLongs().build()) + .enabled()) + .isEqualTo(expectedEnabled); + assertThat(((ExtendedDoubleGauge) meter.gaugeBuilder("doubleGauge").build()).enabled()) + .isEqualTo(expectedEnabled); + assertThat(((ExtendedLongGauge) meter.gaugeBuilder("longGauge").ofLongs().build()).enabled()) + .isEqualTo(expectedEnabled); } @ParameterizedTest diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java index a2b9e60a60f..03e52331dc7 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java @@ -13,6 +13,7 @@ import io.github.netmikey.logunit.api.LogCapturer; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.CallbackRegistration; @@ -36,7 +37,11 @@ class SdkObservableInstrumentTest { @BeforeEach void setup() { meterSharedState = - spy(MeterSharedState.create(InstrumentationScopeInfo.empty(), Collections.emptyList())); + spy( + MeterSharedState.create( + InstrumentationScopeInfo.empty(), + Collections.emptyList(), + MeterConfig.defaultConfig())); callbackRegistration = CallbackRegistration.create( Collections.singletonList( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java index 8b664ad5d3e..99a26106a78 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java @@ -114,5 +114,10 @@ public void recordLong(long value, Attributes attributes, Context context) {} @Override public void recordDouble(double value, Attributes attributes, Context context) {} + + @Override + public boolean isEnabled() { + return true; + } } } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java index a0b2704fc72..6c1df531568 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.trace; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.TracerProvider; @@ -12,13 +13,13 @@ import io.opentelemetry.sdk.trace.internal.TracerConfig; /** {@link SdkTracer} is SDK implementation of {@link Tracer}. */ -final class SdkTracer implements Tracer { +final class SdkTracer implements ExtendedTracer { static final String FALLBACK_SPAN_NAME = ""; private static final Tracer NOOP_TRACER = TracerProvider.noop().get("noop"); private final TracerSharedState sharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; - private final TracerConfig tracerConfig; + private final boolean tracerEnabled; SdkTracer( TracerSharedState sharedState, @@ -26,12 +27,12 @@ final class SdkTracer implements Tracer { TracerConfig tracerConfig) { this.sharedState = sharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; - this.tracerConfig = tracerConfig; + this.tracerEnabled = tracerConfig.isEnabled(); } @Override public SpanBuilder spanBuilder(String spanName) { - if (!tracerConfig.isEnabled()) { + if (!tracerEnabled) { return NOOP_TRACER.spanBuilder(spanName); } if (spanName == null || spanName.trim().isEmpty()) { @@ -49,4 +50,9 @@ public SpanBuilder spanBuilder(String spanName) { InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + + @Override + public boolean enabled() { + return tracerEnabled; + } } diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index 4df99b4c999..99e99ab541d 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -13,6 +13,7 @@ import static io.opentelemetry.sdk.trace.internal.TracerConfig.enabled; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanId; import io.opentelemetry.api.trace.Tracer; @@ -90,6 +91,10 @@ void disableScopes() throws InterruptedException { .hasSpanId(grandchild.getSpanContext().getSpanId()) .hasParentSpanId(parent.getSpanContext().getSpanId()) .hasAttributes(Attributes.builder().put("c", "1").build())); + // tracerA and tracerC are enabled, tracerB is disabled. + assertThat(((ExtendedTracer) tracerA).enabled()).isTrue(); + assertThat(((ExtendedTracer) tracerB).enabled()).isFalse(); + assertThat(((ExtendedTracer) tracerA).enabled()).isTrue(); } @ParameterizedTest From a0e1fee0f37ce76e178b0b013ec23d0286029dc1 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Mon, 24 Jun 2024 14:54:23 -0500 Subject: [PATCH 3/3] enabled => isEnabled --- .../api/incubator/logs/ExtendedLogger.java | 2 +- .../metrics/ExtendedDoubleCounter.java | 2 +- .../metrics/ExtendedDoubleGauge.java | 2 +- .../metrics/ExtendedDoubleHistogram.java | 2 +- .../metrics/ExtendedDoubleUpDownCounter.java | 2 +- .../metrics/ExtendedLongCounter.java | 2 +- .../incubator/metrics/ExtendedLongGauge.java | 2 +- .../metrics/ExtendedLongHistogram.java | 2 +- .../metrics/ExtendedLongUpDownCounter.java | 2 +- .../api/incubator/trace/ExtendedTracer.java | 2 +- .../logs/ExtendedLogsBridgeApiUsageTest.java | 8 ++++---- .../metrics/ExtendedMetricsApiUsageTest.java | 8 ++++---- .../trace/ExtendedTraceApiUsageTest.java | 8 ++++---- .../opentelemetry-exporter-otlp.txt | 19 +------------------ .../io/opentelemetry/sdk/logs/SdkLogger.java | 2 +- .../sdk/logs/LoggerConfigTest.java | 6 +++--- .../sdk/metrics/SdkDoubleCounter.java | 2 +- .../sdk/metrics/SdkDoubleGauge.java | 2 +- .../sdk/metrics/SdkDoubleHistogram.java | 2 +- .../sdk/metrics/SdkDoubleUpDownCounter.java | 2 +- .../sdk/metrics/SdkLongCounter.java | 2 +- .../sdk/metrics/SdkLongGauge.java | 2 +- .../sdk/metrics/SdkLongHistogram.java | 2 +- .../sdk/metrics/SdkLongUpDownCounter.java | 2 +- .../sdk/metrics/MeterConfigTest.java | 17 +++++++++-------- .../io/opentelemetry/sdk/trace/SdkTracer.java | 2 +- .../sdk/trace/TracerConfigTest.java | 6 +++--- 27 files changed, 48 insertions(+), 64 deletions(-) diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java index ea5dc49fac5..db5e2a3b029 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java @@ -17,7 +17,7 @@ public interface ExtendedLogger extends Logger { * the response is subject to change over the application, callers should call this before each * call to {@link #logRecordBuilder()}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java index fcd6e26771b..4345661ebe5 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java @@ -20,7 +20,7 @@ public interface ExtendedDoubleCounter extends DoubleCounter { * call to {@link #add(double)}, {@link #add(double, Attributes)}, or {@link #add(double, * Attributes, Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java index c149de023ff..d9a56f7a391 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java @@ -20,7 +20,7 @@ public interface ExtendedDoubleGauge extends DoubleGauge { * call to {@link #set(double)}, {@link #set(double, Attributes)}, or {@link #set(double, * Attributes, Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java index 62136270565..0a481afef2b 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java @@ -20,7 +20,7 @@ public interface ExtendedDoubleHistogram extends DoubleHistogram { * call to {@link #record(double)}, {@link #record(double, Attributes)}, or {@link #record(double, * Attributes, Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java index 7bed94da09e..6dbb91f1d6f 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java @@ -20,7 +20,7 @@ public interface ExtendedDoubleUpDownCounter extends DoubleUpDownCounter { * call to {@link #add(double)}, {@link #add(double, Attributes)}, or {@link #add(double, * Attributes, Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java index 2df247e5065..0ff67a38fb9 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java @@ -21,7 +21,7 @@ public interface ExtendedLongCounter extends LongCounter { * call to {@link #add(long)}, {@link #add(long, Attributes)}, or {@link #add(long, Attributes, * Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java index e8058179e27..7a660d0e007 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java @@ -20,7 +20,7 @@ public interface ExtendedLongGauge extends LongGauge { * call to {@link #set(long)}, {@link #set(long, Attributes)}, or {@link #set(long, Attributes, * Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java index 86aecd0e11f..d1cd303fb7d 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java @@ -20,7 +20,7 @@ public interface ExtendedLongHistogram extends LongHistogram { * call to {@link #record(long)}, {@link #record(long, Attributes)}, or {@link #record(long, * Attributes, Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java index 7b8d50fe623..7327ed43842 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java @@ -20,7 +20,7 @@ public interface ExtendedLongUpDownCounter extends LongUpDownCounter { * call to {@link #add(long)}, {@link #add(long, Attributes)}, or {@link #add(long, Attributes, * Context)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java index 66bdb31a21c..cb2cae27c24 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java @@ -17,7 +17,7 @@ public interface ExtendedTracer extends Tracer { * the response is subject to change over the application, callers should call this before each * call to {@link #spanBuilder(String)}. */ - default boolean enabled() { + default boolean isEnabled() { return true; } } diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java index 8c55abcef71..7a3d7c82e17 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java @@ -46,14 +46,14 @@ void loggerEnabled() { ExtendedLogger loggerB = (ExtendedLogger) loggerProvider.get("loggerB"); // Check if logger is enabled before emitting log and avoid unnecessary computation - if (loggerA.enabled()) { + if (loggerA.isEnabled()) { loggerA .logRecordBuilder() .setBody("hello world!") .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) .emit(); } - if (loggerB.enabled()) { + if (loggerB.isEnabled()) { loggerB .logRecordBuilder() .setBody("hello world!") @@ -62,8 +62,8 @@ void loggerEnabled() { } // loggerA is enabled, loggerB is disabled - assertThat(loggerA.enabled()).isTrue(); - assertThat(loggerB.enabled()).isFalse(); + assertThat(loggerA.isEnabled()).isTrue(); + assertThat(loggerB.isEnabled()).isFalse(); // Collected data only consists of logs from loggerA. Note, loggerB's logs would be // omitted from the results even if logs were emitted. The check if enabled simply avoids diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java index eb2d69ba302..09cda254e18 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java @@ -52,17 +52,17 @@ void meterEnabled() { (ExtendedDoubleHistogram) meterB.histogramBuilder("histogramB").build(); // Check if instrument is enabled before recording measurement and avoid unnecessary computation - if (histogramA.enabled()) { + if (histogramA.isEnabled()) { histogramA.record(1.0, Attributes.builder().put("result", flipCoin()).build()); } - if (histogramB.enabled()) { + if (histogramB.isEnabled()) { histogramA.record(1.0, Attributes.builder().put("result", flipCoin()).build()); } // histogramA is enabled since meterA is enabled, histogramB is disabled since meterB is // disabled - assertThat(histogramA.enabled()).isTrue(); - assertThat(histogramB.enabled()).isFalse(); + assertThat(histogramA.isEnabled()).isTrue(); + assertThat(histogramB.isEnabled()).isFalse(); // Collected data only consists of metrics from meterA. Note, meterB's histogramB would be // omitted from the results even if values were recorded. The check if enabled simply avoids diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java index cdefd2d84c3..98622ecfebc 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java @@ -57,14 +57,14 @@ void tracerEnabled() { ExtendedTracer tracerB = (ExtendedTracer) tracerProvider.get("tracerB"); // Check if tracer is enabled before recording span and avoid unnecessary computation - if (tracerA.enabled()) { + if (tracerA.isEnabled()) { tracerA .spanBuilder("span name") .startSpan() .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) .end(); } - if (tracerB.enabled()) { + if (tracerB.isEnabled()) { tracerB .spanBuilder("span name") .startSpan() @@ -73,8 +73,8 @@ void tracerEnabled() { } // tracerA is enabled, tracerB is disabled - assertThat(tracerA.enabled()).isTrue(); - assertThat(tracerB.enabled()).isFalse(); + assertThat(tracerA.isEnabled()).isTrue(); + assertThat(tracerB.isEnabled()).isFalse(); // Collected data only consists of spans from tracerA. Note, tracerB's spans would be // omitted from the results even if spans were recorded. The check if enabled simply avoids diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt b/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt index 35bb9f3e97e..df26146497b 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-exporter-otlp.txt @@ -1,19 +1,2 @@ Comparing source compatibility of against -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder setMemoryMode(io.opentelemetry.sdk.common.export.MemoryMode) -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder setMemoryMode(io.opentelemetry.sdk.common.export.MemoryMode) -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder setMemoryMode(io.opentelemetry.sdk.common.export.MemoryMode) -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder setMemoryMode(io.opentelemetry.sdk.common.export.MemoryMode) -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder setMemoryMode(io.opentelemetry.sdk.common.export.MemoryMode) -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder setMemoryMode(io.opentelemetry.sdk.common.export.MemoryMode) +No changes. \ No newline at end of file diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index 39c6592c3fd..72fb9f0b356 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -44,7 +44,7 @@ InstrumentationScopeInfo getInstrumentationScopeInfo() { } @Override - public boolean enabled() { + public boolean isEnabled() { return loggerEnabled; } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 3dabd823adf..f94b97388b4 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -61,9 +61,9 @@ void disableScopes() { assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerC"))).hasSize(1); }); // loggerA and loggerC are enabled, loggerB is disabled. - assertThat(((ExtendedLogger) loggerA).enabled()).isTrue(); - assertThat(((ExtendedLogger) loggerB).enabled()).isFalse(); - assertThat(((ExtendedLogger) loggerC).enabled()).isTrue(); + assertThat(((ExtendedLogger) loggerA).isEnabled()).isTrue(); + assertThat(((ExtendedLogger) loggerB).isEnabled()).isFalse(); + assertThat(((ExtendedLogger) loggerC).isEnabled()).isTrue(); } @ParameterizedTest diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java index 14a0aa18a1e..5e4eb4a7ef5 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java @@ -64,7 +64,7 @@ public void add(double increment) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java index a414d44269e..8cc9d468257 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java @@ -51,7 +51,7 @@ public void set(double increment) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java index ba39d892406..4861a631ab7 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java @@ -63,7 +63,7 @@ public void record(double value) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java index b391315f780..da6316d6b77 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java @@ -53,7 +53,7 @@ public void add(double increment) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java index 387a47d93cd..91b52fee7fd 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java @@ -65,7 +65,7 @@ public void add(long increment) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java index cc27bf8486e..62ab826df87 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java @@ -51,7 +51,7 @@ public void set(long increment) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java index 3a495324137..ef8ee31e707 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java @@ -64,7 +64,7 @@ public void record(long value) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java index fd0d417c541..a74ac786d1a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java @@ -52,7 +52,7 @@ public void add(long increment) { } @Override - public boolean enabled() { + public boolean isEnabled() { return meterSharedState.isMeterEnabled() && storage.isEnabled(); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java index 06d716bebc2..aaaeaf5f85d 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -151,29 +151,30 @@ private static void recordToMeterInstruments(Meter meter, AtomicLong asyncInvoca private static void assertMeterInstrumentsEnabled(Meter meter, boolean expectedEnabled) { assertThat( ((ExtendedDoubleCounter) meter.counterBuilder("doubleCounter").ofDoubles().build()) - .enabled()) + .isEnabled()) .isEqualTo(expectedEnabled); - assertThat(((ExtendedLongCounter) meter.counterBuilder("longCounter").build()).enabled()) + assertThat(((ExtendedLongCounter) meter.counterBuilder("longCounter").build()).isEnabled()) .isEqualTo(expectedEnabled); assertThat( ((ExtendedDoubleUpDownCounter) meter.upDownCounterBuilder("doubleUpDownCounter").ofDoubles().build()) - .enabled()) + .isEnabled()) .isEqualTo(expectedEnabled); assertThat( ((ExtendedLongUpDownCounter) meter.upDownCounterBuilder("longUpDownCounter").build()) - .enabled()) + .isEnabled()) .isEqualTo(expectedEnabled); assertThat( - ((ExtendedDoubleHistogram) meter.histogramBuilder("doubleHistogram").build()).enabled()) + ((ExtendedDoubleHistogram) meter.histogramBuilder("doubleHistogram").build()) + .isEnabled()) .isEqualTo(expectedEnabled); assertThat( ((ExtendedLongHistogram) meter.histogramBuilder("longHistogram").ofLongs().build()) - .enabled()) + .isEnabled()) .isEqualTo(expectedEnabled); - assertThat(((ExtendedDoubleGauge) meter.gaugeBuilder("doubleGauge").build()).enabled()) + assertThat(((ExtendedDoubleGauge) meter.gaugeBuilder("doubleGauge").build()).isEnabled()) .isEqualTo(expectedEnabled); - assertThat(((ExtendedLongGauge) meter.gaugeBuilder("longGauge").ofLongs().build()).enabled()) + assertThat(((ExtendedLongGauge) meter.gaugeBuilder("longGauge").ofLongs().build()).isEnabled()) .isEqualTo(expectedEnabled); } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java index 6c1df531568..cd8c7ca2471 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java @@ -52,7 +52,7 @@ InstrumentationScopeInfo getInstrumentationScopeInfo() { } @Override - public boolean enabled() { + public boolean isEnabled() { return tracerEnabled; } } diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index 99e99ab541d..4421185aeea 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -92,9 +92,9 @@ void disableScopes() throws InterruptedException { .hasParentSpanId(parent.getSpanContext().getSpanId()) .hasAttributes(Attributes.builder().put("c", "1").build())); // tracerA and tracerC are enabled, tracerB is disabled. - assertThat(((ExtendedTracer) tracerA).enabled()).isTrue(); - assertThat(((ExtendedTracer) tracerB).enabled()).isFalse(); - assertThat(((ExtendedTracer) tracerA).enabled()).isTrue(); + assertThat(((ExtendedTracer) tracerA).isEnabled()).isTrue(); + assertThat(((ExtendedTracer) tracerB).isEnabled()).isFalse(); + assertThat(((ExtendedTracer) tracerA).isEnabled()).isTrue(); } @ParameterizedTest