Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dismantle AbstractInstrumentBuilder inheritance hierarchy #5820

Merged
merged 11 commits into from
Oct 13, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.sdk.metrics;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import io.opentelemetry.sdk.metrics.internal.descriptor.Advice;
Expand All @@ -15,95 +16,72 @@
import io.opentelemetry.sdk.metrics.internal.state.SdkObservableMeasurement;
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;
import javax.annotation.Nullable;

/** Helper to make implementing builders easier. */
abstract class AbstractInstrumentBuilder<BuilderT extends AbstractInstrumentBuilder<?>> {

static final String DEFAULT_UNIT = "";
final class InstrumentBuilder {

private final String name;
private final MeterProviderSharedState meterProviderSharedState;
private final InstrumentType type;
private final InstrumentValueType valueType;
private String description;
private String unit;

protected final MeterSharedState meterSharedState;
protected final String instrumentName;
protected final Advice.AdviceBuilder adviceBuilder;

AbstractInstrumentBuilder(
MeterProviderSharedState meterProviderSharedState,
MeterSharedState meterSharedState,
InstrumentType type,
InstrumentValueType valueType,
private final MeterSharedState meterSharedState;
@Nullable private InstrumentType type = null;
@Nullable private InstrumentValueType valueType;
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved
private Advice.AdviceBuilder adviceBuilder = Advice.builder();
private String description = "";
private String unit = "";

InstrumentBuilder(
String name,
String description,
String unit) {
this(
meterProviderSharedState,
meterSharedState,
type,
valueType,
name,
description,
unit,
Advice.builder());
}

AbstractInstrumentBuilder(
MeterProviderSharedState meterProviderSharedState,
MeterSharedState meterSharedState,
InstrumentType type,
InstrumentValueType valueType,
String name,
String description,
String unit,
Advice.AdviceBuilder adviceBuilder) {
this.type = type;
this.valueType = valueType;
this.instrumentName = name;
this.description = description;
this.unit = unit;
MeterSharedState meterSharedState) {
this.name = name;
this.meterProviderSharedState = meterProviderSharedState;
this.meterSharedState = meterSharedState;
this.adviceBuilder = adviceBuilder;
}

protected abstract BuilderT getThis();

public BuilderT setUnit(String unit) {
public InstrumentBuilder setUnit(String unit) {
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved
this.unit = unit;
return getThis();
return this;
}

public InstrumentBuilder setType(InstrumentType type) {
this.type = type;
return this;
}

public BuilderT setDescription(String description) {
public InstrumentBuilder setValueType(InstrumentValueType valueType) {
this.valueType = valueType;
return this;
}

public InstrumentBuilder setAdviceBuilder(Advice.AdviceBuilder adviceBuilder) {
this.adviceBuilder = adviceBuilder;
return this;
}

public InstrumentBuilder setDescription(String description) {
this.description = description;
return getThis();
return this;
}

protected <T> T swapBuilder(SwapBuilder<T> swapper) {
<T> T swapBuilder(SwapBuilder<T> swapper) {
return swapper.newBuilder(
meterProviderSharedState,
meterSharedState,
instrumentName,
description,
unit,
adviceBuilder);
meterProviderSharedState, meterSharedState, name, description, unit, adviceBuilder);
}

final <I extends AbstractInstrument> I buildSynchronousInstrument(
<I extends AbstractInstrument> I buildSynchronousInstrument(
BiFunction<InstrumentDescriptor, WriteableMetricStorage, I> instrumentFactory) {
InstrumentDescriptor descriptor =
InstrumentDescriptor.create(
instrumentName, description, unit, type, valueType, adviceBuilder.build());
validateType();
InstrumentDescriptor descriptor = newDescriptor();
WriteableMetricStorage storage =
meterSharedState.registerSynchronousMetricStorage(descriptor, meterProviderSharedState);
return instrumentFactory.apply(descriptor, storage);
}

final SdkObservableInstrument registerDoubleAsynchronousInstrument(
SdkObservableInstrument buildDoubleAsynchronousInstrument(
InstrumentType type, Consumer<ObservableDoubleMeasurement> updater) {
SdkObservableMeasurement sdkObservableMeasurement = buildObservableMeasurement(type);
Runnable runnable = () -> updater.accept(sdkObservableMeasurement);
Expand All @@ -113,7 +91,7 @@
return new SdkObservableInstrument(meterSharedState, callbackRegistration);
}

final SdkObservableInstrument registerLongAsynchronousInstrument(
SdkObservableInstrument buildLongAsynchronousInstrument(
InstrumentType type, Consumer<ObservableLongMeasurement> updater) {
SdkObservableMeasurement sdkObservableMeasurement = buildObservableMeasurement(type);
Runnable runnable = () -> updater.accept(sdkObservableMeasurement);
Expand All @@ -123,20 +101,36 @@
return new SdkObservableInstrument(meterSharedState, callbackRegistration);
}

final SdkObservableMeasurement buildObservableMeasurement(InstrumentType type) {
InstrumentDescriptor descriptor =
InstrumentDescriptor.create(
instrumentName, description, unit, type, valueType, adviceBuilder.build());
SdkObservableMeasurement buildObservableMeasurement(InstrumentType type) {
this.type = type;
validateType();
InstrumentDescriptor descriptor = newDescriptor();
return meterSharedState.registerObservableMeasurement(descriptor);
}

@SuppressWarnings("NullAway")
private InstrumentDescriptor newDescriptor() {
validateType();
return InstrumentDescriptor.create(
name, description, unit, type, valueType, adviceBuilder.build());
}

private void validateType() {
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved
if (type == null) {
throw new IllegalStateException("The instrument type must be configured before build().");

Check warning on line 120 in sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java

View check run for this annotation

Codecov / codecov/patch

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java#L120

Added line #L120 was not covered by tests
}
if (valueType == null) {
throw new IllegalStateException("The valueType must be configured before build().");

Check warning on line 123 in sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java

View check run for this annotation

Codecov / codecov/patch

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java#L123

Added line #L123 was not covered by tests
}
}

@Override
public String toString() {
return this.getClass().getSimpleName()
+ "{descriptor="
+ InstrumentDescriptor.create(
instrumentName, description, unit, type, valueType, adviceBuilder.build())
+ "}";
return toStringHelper(getClass().getSimpleName());
}

String toStringHelper(String className) {
return className + "{descriptor=" + newDescriptor() + "}";
}

@FunctionalInterface
Expand All @@ -149,4 +143,12 @@
String unit,
Advice.AdviceBuilder adviceBuilder);
}

void setAdviceAttributes(List<AttributeKey<?>> attributes) {
adviceBuilder.setAttributes(attributes);
}

void setExplicitBucketBoundaries(List<Double> bucketBoundaries) {
adviceBuilder.setExplicitBucketBoundaries(bucketBoundaries);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.DoubleCounterBuilder;
import io.opentelemetry.api.metrics.ObservableDoubleCounter;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import io.opentelemetry.context.Context;
Expand Down Expand Up @@ -57,9 +58,9 @@
add(increment, Attributes.empty());
}

static final class SdkDoubleCounterBuilder
extends AbstractInstrumentBuilder<SdkDoubleCounterBuilder>
implements ExtendedDoubleCounterBuilder {
static final class SdkDoubleCounterBuilder implements ExtendedDoubleCounterBuilder {

private final InstrumentBuilder builder;

SdkDoubleCounterBuilder(
MeterProviderSharedState meterProviderSharedState,
Expand All @@ -68,42 +69,52 @@
String description,
String unit,
Advice.AdviceBuilder adviceBuilder) {
super(
meterProviderSharedState,
sharedState,
InstrumentType.COUNTER,
InstrumentValueType.DOUBLE,
name,
description,
unit,
adviceBuilder);
this.builder =
new InstrumentBuilder(name, meterProviderSharedState, sharedState)
.setType(InstrumentType.COUNTER)
.setValueType(InstrumentValueType.DOUBLE)
.setUnit(unit)
.setDescription(description)
.setAdviceBuilder(adviceBuilder);
}

@Override
public SdkDoubleCounter build() {
return builder.buildSynchronousInstrument(SdkDoubleCounter::new);
}

@Override
protected SdkDoubleCounterBuilder getThis() {
public DoubleCounterBuilder setDescription(String description) {
builder.setDescription(description);
return this;
}

@Override
public SdkDoubleCounter build() {
return buildSynchronousInstrument(SdkDoubleCounter::new);
public DoubleCounterBuilder setUnit(String unit) {
builder.setUnit(unit);
return this;
}

@Override
public ObservableDoubleCounter buildWithCallback(
Consumer<ObservableDoubleMeasurement> callback) {
return registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_COUNTER, callback);
return builder.buildDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_COUNTER, callback);
}

@Override
public ObservableDoubleMeasurement buildObserver() {
return buildObservableMeasurement(InstrumentType.OBSERVABLE_COUNTER);
return builder.buildObservableMeasurement(InstrumentType.OBSERVABLE_COUNTER);
}

@Override
public ExtendedDoubleCounterBuilder setAttributesAdvice(List<AttributeKey<?>> attributes) {
adviceBuilder.setAttributes(attributes);
builder.setAdviceAttributes(attributes);
return this;
}

@Override
public String toString() {
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved
return builder.toStringHelper(getClass().getSimpleName());

Check warning on line 117 in sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java

View check run for this annotation

Codecov / codecov/patch

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java#L117

Added line #L117 was not covered by tests
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleGaugeBuilder;
import io.opentelemetry.api.metrics.LongGaugeBuilder;
import io.opentelemetry.api.metrics.ObservableDoubleGauge;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
Expand Down Expand Up @@ -39,55 +40,64 @@
set(increment, Attributes.empty());
}

static final class SdkDoubleGaugeBuilder extends AbstractInstrumentBuilder<SdkDoubleGaugeBuilder>
implements ExtendedDoubleGaugeBuilder {
static final class SdkDoubleGaugeBuilder implements ExtendedDoubleGaugeBuilder {
private final InstrumentBuilder builder;

SdkDoubleGaugeBuilder(
MeterProviderSharedState meterProviderSharedState,
MeterSharedState meterSharedState,
String name) {
super(
meterProviderSharedState,
meterSharedState,
// TODO: use InstrumentType.GAUGE when available
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved
InstrumentType.OBSERVABLE_GAUGE,
InstrumentValueType.DOUBLE,
name,
"",
DEFAULT_UNIT);

builder =
new InstrumentBuilder(name, meterProviderSharedState, meterSharedState)
// TODO: use InstrumentType.GAUGE when available
.setType(InstrumentType.OBSERVABLE_GAUGE)
.setValueType(InstrumentValueType.DOUBLE);
}

@Override
public DoubleGaugeBuilder setDescription(String description) {
builder.setDescription(description);
return this;
}

@Override
protected SdkDoubleGaugeBuilder getThis() {
public DoubleGaugeBuilder setUnit(String unit) {
builder.setUnit(unit);
return this;
}

@Override
public SdkDoubleGauge build() {
return buildSynchronousInstrument(SdkDoubleGauge::new);
return builder.buildSynchronousInstrument(SdkDoubleGauge::new);
}

@Override
public ExtendedDoubleGaugeBuilder setAttributesAdvice(List<AttributeKey<?>> attributes) {
adviceBuilder.setAttributes(attributes);
builder.setAdviceAttributes(attributes);
return this;
}

@Override
public LongGaugeBuilder ofLongs() {
return swapBuilder(SdkLongGauge.SdkLongGaugeBuilder::new);
return builder.swapBuilder(SdkLongGauge.SdkLongGaugeBuilder::new);
}

@Override
public ObservableDoubleGauge buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {
// TODO: use InstrumentType.GAUGE when available
return registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback);
return builder.buildDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback);
}

@Override
public ObservableDoubleMeasurement buildObserver() {
// TODO: use InstrumentType.GAUGE when available
return buildObservableMeasurement(InstrumentType.OBSERVABLE_GAUGE);
return builder.buildObservableMeasurement(InstrumentType.OBSERVABLE_GAUGE);
}

@Override
public String toString() {
return builder.toStringHelper(getClass().getSimpleName());

Check warning on line 100 in sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java

View check run for this annotation

Codecov / codecov/patch

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java#L100

Added line #L100 was not covered by tests
}
}
}
Loading