Extract View configuration interface so it only exposes public API. (#4239)

* Extract View configuration interface so it only exposes public API.

* scare
This commit is contained in:
Anuraag Agrawal 2022-03-09 14:36:56 +09:00 committed by GitHub
parent 048a0c8d14
commit 9ac622170e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 175 additions and 100 deletions

View File

@ -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")

View File

@ -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.<clinit>(TestSourceInfo.java:22)\n");
"\tat io.opentelemetry.testing.SourceInfoTest.<clinit>(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]")

View File

@ -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<T, O> implements MetricStorage {
AsyncAccumulator<T> 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<T, O> implements MetricStorage {
.createAggregator(instrument, ExemplarFilter.neverSample());
AsyncAccumulator<T> 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);
}

View File

@ -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())

View File

@ -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));
}
}

View File

@ -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.
*
* <p>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());
}
}

View File

@ -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.
*
* <p>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<String> keyFilter) {
this.processor = this.processor.then(AttributesProcessor.filterByKeyName(keyFilter));
return this;
}
/**
* Appends key-values from baggage to all measurements.
*
* <p>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<String> keyFilter) {
this.processor = this.processor.then(AttributesProcessor.appendBaggageByKeyName(keyFilter));
return this;
}
/**
* Appends all key-values from baggage to all measurements.
*
* <p>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);
}
}

View File

@ -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();
}

View File

@ -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<String> keyFilter) {
this.processor = this.processor.then(AttributesProcessor.filterByKeyName(keyFilter));
return this;
}
ViewBuilder setAttributeFilter(Predicate<String> keyFilter);
/**
* Appends key-values from baggage to all measurements.
*
* <p>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<String> keyFilter) {
this.processor = this.processor.then(AttributesProcessor.appendBaggageByKeyName(keyFilter));
return this;
}
/**
* Appends all key-values from baggage to all measurements.
*
* <p>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();
}

View File

@ -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();