diff --git a/sdk-extensions/metric-incubator/src/test/java/io/opentelemetry/sdk/viewconfig/ViewConfigTest.java b/sdk-extensions/metric-incubator/src/test/java/io/opentelemetry/sdk/viewconfig/ViewConfigTest.java index 3777623b73..9a56fe0727 100644 --- a/sdk-extensions/metric-incubator/src/test/java/io/opentelemetry/sdk/viewconfig/ViewConfigTest.java +++ b/sdk-extensions/metric-incubator/src/test/java/io/opentelemetry/sdk/viewconfig/ViewConfigTest.java @@ -16,6 +16,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.common.InstrumentType; +import io.opentelemetry.sdk.metrics.internal.view.ImmutableView; import io.opentelemetry.sdk.metrics.internal.view.ViewRegistryBuilder; import io.opentelemetry.sdk.metrics.view.Aggregation; import io.opentelemetry.sdk.metrics.view.InstrumentSelector; @@ -114,7 +115,7 @@ class ViewConfigTest { assertThat(view.getDescription()).isEqualTo("description"); assertThat(view.getAggregation()).isEqualTo(Aggregation.sum()); assertThat( - view.getAttributesProcessor() + ImmutableView.getAttributesProcessor(view) .process( Attributes.builder() .put("foo", "val") diff --git a/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/TestSourceInfo.java b/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java similarity index 92% rename from sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/TestSourceInfo.java rename to sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java index c6500ff3a7..01e3c7e87f 100644 --- a/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/TestSourceInfo.java +++ b/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java @@ -13,20 +13,21 @@ import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; import io.opentelemetry.sdk.metrics.internal.state.DebugUtils; +import io.opentelemetry.sdk.metrics.internal.view.ImmutableView; import io.opentelemetry.sdk.metrics.view.View; import org.junit.jupiter.api.Test; // Note: This class MUST be outside the io.opentelemetry.metrics package to work correctly. -class TestSourceInfo { +class SourceInfoTest { // Note: The line numbers for these statics are used as part of the test. private static final SourceInfo info = SourceInfo.fromCurrentStack(); @Test void sourceInfoFindsStackTrace() { - assertThat(info.shortDebugString()).isEqualTo("TestSourceInfo.java:22"); + assertThat(info.shortDebugString()).isEqualTo("SourceInfoTest.java:23"); assertThat(info.multiLineDebugString()) .startsWith( - "\tat io.opentelemetry.testing.TestSourceInfo.(TestSourceInfo.java:22)\n"); + "\tat io.opentelemetry.testing.SourceInfoTest.(SourceInfoTest.java:23)\n"); } @Test @@ -83,7 +84,7 @@ class TestSourceInfo { .contains(simple.getSourceInstrument().getSourceInfo().multiLineDebugString()) .contains("- Description [description2] does not match [description]") .contains("Conflicting view registered") - .contains(problemView.getSourceInfo().multiLineDebugString()) + .contains(ImmutableView.getSourceInfo(problemView).multiLineDebugString()) .contains("FROM instrument name") .contains( simpleWithNewDescription.getSourceInstrument().getSourceInfo().multiLineDebugString()); @@ -113,7 +114,7 @@ class TestSourceInfo { assertThat(DebugUtils.duplicateMetricErrorMessage(simple, simpleWithNewDescription)) .contains("Found duplicate metric definition: name") .contains("VIEW defined") - .contains(problemView.getSourceInfo().multiLineDebugString()) + .contains(ImmutableView.getSourceInfo(problemView).multiLineDebugString()) .contains("FROM instrument name2") .contains(simple.getSourceInstrument().getSourceInfo().multiLineDebugString()) .contains("- Unit [unit] does not match [unit2]") diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java index 9bdd2daf11..5b6a3ce7c7 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java @@ -23,6 +23,7 @@ import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; import io.opentelemetry.sdk.metrics.internal.export.CollectionInfo; import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; +import io.opentelemetry.sdk.metrics.internal.view.ImmutableView; import io.opentelemetry.sdk.metrics.view.View; import io.opentelemetry.sdk.resources.Resource; import java.util.HashMap; @@ -74,7 +75,7 @@ public class AsynchronousMetricStorage implements MetricStorage { AsyncAccumulator accumulator = new AsyncAccumulator<>(instrument); ObservableDoubleMeasurement measurement = new ObservableDoubleMeasurementImpl<>( - aggregator, accumulator, view.getAttributesProcessor()); + aggregator, accumulator, ImmutableView.getAttributesProcessor(view)); return new AsynchronousMetricStorage<>(metricDescriptor, aggregator, accumulator, measurement); } @@ -88,7 +89,8 @@ public class AsynchronousMetricStorage implements MetricStorage { .createAggregator(instrument, ExemplarFilter.neverSample()); AsyncAccumulator accumulator = new AsyncAccumulator<>(instrument); ObservableLongMeasurement measurement = - new ObservableLongMeasurementImpl<>(aggregator, accumulator, view.getAttributesProcessor()); + new ObservableLongMeasurementImpl<>( + aggregator, accumulator, ImmutableView.getAttributesProcessor(view)); return new AsynchronousMetricStorage<>(metricDescriptor, aggregator, accumulator, measurement); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DebugUtils.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DebugUtils.java index 4d548d6d3b..627b4194c1 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DebugUtils.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DebugUtils.java @@ -6,6 +6,7 @@ package io.opentelemetry.sdk.metrics.internal.state; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; +import io.opentelemetry.sdk.metrics.internal.view.ImmutableView; /** * Utilities for logging metric diagnostic issues. @@ -45,7 +46,7 @@ public final class DebugUtils { result.append("\tVIEW defined\n"); conflict .getSourceView() - .ifPresent(v -> result.append(v.getSourceInfo().multiLineDebugString())); + .ifPresent(v -> result.append(ImmutableView.getSourceInfo(v).multiLineDebugString())); result .append("\tFROM instrument ") .append(conflict.getSourceInstrument().getName()) @@ -109,7 +110,8 @@ public final class DebugUtils { result.append("Conflicting view registered.\n"); existing .getSourceView() - .ifPresent(view -> result.append(view.getSourceInfo().multiLineDebugString())); + .ifPresent( + view -> result.append(ImmutableView.getSourceInfo(view).multiLineDebugString())); result .append("FROM instrument ") .append(existing.getSourceInstrument().getName()) diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java index 46e571bf4b..58a61936b8 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java @@ -11,6 +11,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; +import io.opentelemetry.sdk.metrics.internal.view.ImmutableView; import io.opentelemetry.sdk.metrics.view.View; /** @@ -43,6 +44,6 @@ public interface SynchronousMetricStorage extends MetricStorage, WriteableMetric return empty(); } return new DefaultSynchronousMetricStorage<>( - metricDescriptor, aggregator, view.getAttributesProcessor()); + metricDescriptor, aggregator, ImmutableView.getAttributesProcessor(view)); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ImmutableView.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ImmutableView.java new file mode 100644 index 0000000000..77b4a211d1 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ImmutableView.java @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.view; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; +import io.opentelemetry.sdk.metrics.view.Aggregation; +import io.opentelemetry.sdk.metrics.view.View; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * A configuration for a metric stream transformation. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@AutoValue +@Immutable +public abstract class ImmutableView implements View { + + /** Returns the {@link AttributesProcessor} for the {@link View}. */ + public static AttributesProcessor getAttributesProcessor(View view) { + if (view instanceof ImmutableView) { + return ((ImmutableView) view).getAttributesProcessor(); + } + return AttributesProcessor.NOOP; + } + + /** Processor of attributes before performing aggregation. */ + abstract AttributesProcessor getAttributesProcessor(); + + /** Returns the {@link SourceInfo} for the {@link View}. */ + public static SourceInfo getSourceInfo(View view) { + if (view instanceof ImmutableView) { + return ((ImmutableView) view).getSourceInfo(); + } + return SourceInfo.noSourceInfo(); + } + + /** Information about where the View was defined. */ + abstract SourceInfo getSourceInfo(); + + static ImmutableView create( + @Nullable String name, + @Nullable String description, + Aggregation aggregation, + AttributesProcessor attributesProcessor) { + // TODO - Add the ability to track when a View was registered via a config file. + return new AutoValue_ImmutableView( + name, description, aggregation, attributesProcessor, SourceInfo.fromCurrentStack()); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewBuilderImpl.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewBuilderImpl.java new file mode 100644 index 0000000000..7e2bb707a3 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewBuilderImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.view; + +import io.opentelemetry.sdk.metrics.view.Aggregation; +import io.opentelemetry.sdk.metrics.view.View; +import io.opentelemetry.sdk.metrics.view.ViewBuilder; +import java.util.function.Predicate; +import javax.annotation.Nullable; + +/** + * Builder of metric {@link View}s. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ViewBuilderImpl implements ViewBuilder { + @Nullable private String name = null; + @Nullable private String description = null; + private Aggregation aggregation = Aggregation.defaultAggregation(); + private AttributesProcessor processor = AttributesProcessor.noop(); + + public ViewBuilderImpl() {} + + @Override + public ViewBuilder setName(String name) { + this.name = name; + return this; + } + + @Override + public ViewBuilder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public ViewBuilder setAggregation(Aggregation aggregation) { + this.aggregation = aggregation; + return this; + } + + @Override + public ViewBuilder setAttributeFilter(Predicate keyFilter) { + this.processor = this.processor.then(AttributesProcessor.filterByKeyName(keyFilter)); + return this; + } + + /** + * Appends key-values from baggage to all measurements. + * + *

Note: This runs after all other attribute processing added so far. + * + * @param keyFilter Only baggage key values pairs where the key matches this predicate will be + * appended. + * @return this Builder. + */ + public ViewBuilder appendFilteredBaggageAttributes(Predicate keyFilter) { + this.processor = this.processor.then(AttributesProcessor.appendBaggageByKeyName(keyFilter)); + return this; + } + + /** + * Appends all key-values from baggage to all measurements. + * + *

Note: This runs after all other attribute processing added so far. + * + * @return this Builder. + */ + public ViewBuilder appendAllBaggageAttributes() { + return appendFilteredBaggageAttributes(StringPredicates.ALL); + } + + @Override + public View build() { + return ImmutableView.create(this.name, this.description, this.aggregation, this.processor); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/View.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/View.java index 21e4e8c1e5..7fbb39a6ec 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/View.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/View.java @@ -5,49 +5,28 @@ package io.opentelemetry.sdk.metrics.view; -import com.google.auto.value.AutoValue; -import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; -import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; +import io.opentelemetry.sdk.metrics.internal.view.ViewBuilderImpl; import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -/** TODO: javadoc. */ -@AutoValue -@Immutable -public abstract class View { +/** A configuration for a metric stream transformation. */ +public interface View { + /** Returns a {@linkplain ViewBuilder builder} for a {@link View}. */ + static ViewBuilder builder() { + return new ViewBuilderImpl(); + } /** * The name of the resulting metric to generate, or {@code null} if the same as the instrument. */ @Nullable - public abstract String getName(); + String getName(); /** * The name of the resulting metric to generate, or {@code null} if the same as the instrument. */ @Nullable - public abstract String getDescription(); + String getDescription(); /** The aggregation used for this view. */ - public abstract Aggregation getAggregation(); - - /** Processor of attributes before performing aggregation. */ - public abstract AttributesProcessor getAttributesProcessor(); - - /** Information about where the View was defined. */ - public abstract SourceInfo getSourceInfo(); - - public static ViewBuilder builder() { - return new ViewBuilder(); - } - - static View create( - @Nullable String name, - @Nullable String description, - Aggregation aggregation, - AttributesProcessor attributesProcessor) { - // TODO - Add the ability to track when a View was registered via a config file. - return new AutoValue_View( - name, description, aggregation, attributesProcessor, SourceInfo.fromCurrentStack()); - } + Aggregation getAggregation(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/ViewBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/ViewBuilder.java index a27a7a0d59..a5f8fb51b3 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/ViewBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/view/ViewBuilder.java @@ -5,19 +5,10 @@ package io.opentelemetry.sdk.metrics.view; -import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; -import io.opentelemetry.sdk.metrics.internal.view.StringPredicates; import java.util.function.Predicate; -import javax.annotation.Nullable; -/** Builder of metric {@link View}s. */ -public final class ViewBuilder { - @Nullable private String name = null; - @Nullable private String description = null; - private Aggregation aggregation = Aggregation.defaultAggregation(); - private AttributesProcessor processor = AttributesProcessor.noop(); - - ViewBuilder() {} +/** A builder for {@link View}. */ +public interface ViewBuilder { /** * sets the name of the resulting metric. @@ -25,10 +16,7 @@ public final class ViewBuilder { * @param name metric name or {@code null} if the underlying instrument name should be used. * @return this Builder. */ - public ViewBuilder setName(String name) { - this.name = name; - return this; - } + ViewBuilder setName(String name); /** * sets the name of the resulting metric. @@ -37,10 +25,7 @@ public final class ViewBuilder { * should be used. * @return this Builder. */ - public ViewBuilder setDescription(String description) { - this.description = description; - return this; - } + ViewBuilder setDescription(String description); /** * sets {@link Aggregation}. @@ -48,10 +33,7 @@ public final class ViewBuilder { * @param aggregation aggregation to use. * @return this Builder. */ - public ViewBuilder setAggregation(Aggregation aggregation) { - this.aggregation = aggregation; - return this; - } + ViewBuilder setAggregation(Aggregation aggregation); /** * Sets a filter for attributes, where only attribute names that pass the supplied {@link @@ -62,38 +44,8 @@ public final class ViewBuilder { * @param keyFilter filter for key names to include. * @return this Builder. */ - public ViewBuilder setAttributeFilter(Predicate keyFilter) { - this.processor = this.processor.then(AttributesProcessor.filterByKeyName(keyFilter)); - return this; - } + ViewBuilder setAttributeFilter(Predicate keyFilter); - /** - * Appends key-values from baggage to all measurements. - * - *

Note: This runs after all other attribute processing added so far. - * - * @param keyFilter Only baggage key values pairs where the key matches this predicate will be - * appended. - * @return this Builder. - */ - public ViewBuilder appendFilteredBaggageAttributes(Predicate keyFilter) { - this.processor = this.processor.then(AttributesProcessor.appendBaggageByKeyName(keyFilter)); - return this; - } - - /** - * Appends all key-values from baggage to all measurements. - * - *

Note: This runs after all other attribute processing added so far. - * - * @return this Builder. - */ - public ViewBuilder appendAllBaggageAttributes() { - return appendFilteredBaggageAttributes(StringPredicates.ALL); - } - - /** Returns the resulting {@link View}. */ - public View build() { - return View.create(this.name, this.description, this.aggregation, this.processor); - } + /** Returns a {@link View} with the configuration of this builder. */ + View build(); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java index 522aaeff88..c405fbdd98 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java @@ -29,6 +29,7 @@ import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.data.LongPointData; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.MetricReader; +import io.opentelemetry.sdk.metrics.internal.view.ViewBuilderImpl; import io.opentelemetry.sdk.metrics.view.Aggregation; import io.opentelemetry.sdk.metrics.view.InstrumentSelector; import io.opentelemetry.sdk.metrics.view.View; @@ -691,8 +692,7 @@ class SdkMeterProviderTest { .registerMetricReader(reader) .registerView( selector, - View.builder() - .setAggregation(Aggregation.sum()) + ((ViewBuilderImpl) View.builder().setAggregation(Aggregation.sum())) .appendAllBaggageAttributes() .build()) .build();