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

Add experimental synchronous gauge #5506

Merged
merged 4 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.extension.incubator.metrics;

import io.opentelemetry.api.common.Attributes;
import javax.annotation.concurrent.ThreadSafe;

/** A gauge instrument that synchronously records {@code double} values. */
@ThreadSafe
public interface DoubleGauge {
/**
* Set the gauge value.
*
* @param value The current gauge value.
*/
void set(double value);

/**
* Records a value with a set of attributes.
*
* @param value The current gauge value.
* @param attributes A set of attributes to associate with the value.
*/
void set(double value, Attributes attributes);

// TODO(jack-berg): should we add overload with Context argument?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to open an issue for this and solve in a separate PR. The synchronous use cases I'm aware of require the instrumentation to subscribe to notifications about change in some value, rather than fetching the current value which caters to async gauge. Not clear when context would be available in one of these notification event streams. I'm open to it being a use case, but its not as clear cut as what's in this PR.

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
/** Extended {@link DoubleGaugeBuilder} with experimental APIs. */
public interface ExtendedDoubleGaugeBuilder extends DoubleGaugeBuilder {

/**
* Builds and returns a DoubleGauge instrument with the configuration.
*
* <p>NOTE: This produces a synchronous gauge which records gauge values as they occur. Most users
* will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe
* the value of the gauge when metrics are collected.
*
* @return The DoubleGauge instrument.
*/
DoubleGauge build();

/** Specify advice for gauge implementations. */
default DoubleGaugeBuilder setAdvice(Consumer<DoubleGaugeAdviceConfigurer> adviceConsumer) {
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
/** Extended {@link LongGaugeBuilder} with experimental APIs. */
public interface ExtendedLongGaugeBuilder extends LongGaugeBuilder {

/**
* Builds and returns a LongGauge instrument with the configuration.
*
* <p>NOTE: This produces a synchronous gauge which records gauge values as they occur. Most users
* will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe
* the value of the gauge when metrics are collected.
*
* @return The LongGauge instrument.
*/
LongGauge build();

/** Specify advice for gauge implementations. */
default LongGaugeBuilder setAdvice(Consumer<LongGaugeAdviceConfigurer> adviceConsumer) {
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.extension.incubator.metrics;

import io.opentelemetry.api.common.Attributes;
import javax.annotation.concurrent.ThreadSafe;

/** A gauge instrument that synchronously records {@code long} values. */
@ThreadSafe
public interface LongGauge {
/**
* Set the gauge value.
*
* @param value The current gauge value.
*/
void set(long value);

/**
* Records a value with a set of attributes.
*
* @param value The current gauge value.
* @param attributes A set of attributes to associate with the value.
*/
void set(long value, Attributes attributes);

// TODO(jack-berg): should we add overload with Context argument?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.metrics;

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;
import io.opentelemetry.context.Context;
import io.opentelemetry.extension.incubator.metrics.DoubleGauge;
import io.opentelemetry.extension.incubator.metrics.DoubleGaugeAdviceConfigurer;
import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleGaugeBuilder;
import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor;
import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState;
import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState;
import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage;
import java.util.List;
import java.util.function.Consumer;

final class SdkDoubleGauge extends AbstractInstrument implements DoubleGauge {

private final WriteableMetricStorage storage;

private SdkDoubleGauge(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
super(descriptor);
this.storage = storage;
}

@Override
public void set(double increment, Attributes attributes) {
storage.recordDouble(increment, attributes, Context.root());
}

@Override
public void set(double increment) {
set(increment, Attributes.empty());
}

static final class SdkDoubleGaugeBuilder extends AbstractInstrumentBuilder<SdkDoubleGaugeBuilder>
implements ExtendedDoubleGaugeBuilder, DoubleGaugeAdviceConfigurer {

SdkDoubleGaugeBuilder(
MeterProviderSharedState meterProviderSharedState,
MeterSharedState meterSharedState,
String name) {
super(
meterProviderSharedState,
meterSharedState,
// TODO: use InstrumentType.GAUGE when available
InstrumentType.OBSERVABLE_GAUGE,
InstrumentValueType.DOUBLE,
name,
"",
DEFAULT_UNIT);
}

@Override
protected SdkDoubleGaugeBuilder getThis() {
return this;
}

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

@Override
public DoubleGaugeBuilder setAdvice(Consumer<DoubleGaugeAdviceConfigurer> adviceConsumer) {
adviceConsumer.accept(this);
return this;
}

@Override
public DoubleGaugeAdviceConfigurer setAttributes(List<AttributeKey<?>> attributes) {
adviceBuilder.setAttributes(attributes);
return this;
}

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

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

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.metrics;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.LongGaugeBuilder;
import io.opentelemetry.api.metrics.ObservableLongGauge;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import io.opentelemetry.context.Context;
import io.opentelemetry.extension.incubator.metrics.ExtendedLongGaugeBuilder;
import io.opentelemetry.extension.incubator.metrics.LongGauge;
import io.opentelemetry.extension.incubator.metrics.LongGaugeAdviceConfigurer;
import io.opentelemetry.sdk.metrics.internal.descriptor.Advice;
import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor;
import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState;
import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState;
import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage;
import java.util.List;
import java.util.function.Consumer;

final class SdkLongGauge extends AbstractInstrument implements LongGauge {

private final WriteableMetricStorage storage;

private SdkLongGauge(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
super(descriptor);
this.storage = storage;
}

@Override
public void set(long increment, Attributes attributes) {
storage.recordLong(increment, attributes, Context.root());
}

@Override
public void set(long increment) {
set(increment, Attributes.empty());
}

static final class SdkLongGaugeBuilder extends AbstractInstrumentBuilder<SdkLongGaugeBuilder>
implements ExtendedLongGaugeBuilder, LongGaugeAdviceConfigurer {

SdkLongGaugeBuilder(
MeterProviderSharedState meterProviderSharedState,
MeterSharedState sharedState,
String name,
String description,
String unit,
Advice.AdviceBuilder adviceBuilder) {
super(
meterProviderSharedState,
sharedState,
// TODO: use InstrumentType.GAUGE when available
InstrumentType.OBSERVABLE_GAUGE,
InstrumentValueType.LONG,
name,
description,
unit,
adviceBuilder);
}

@Override
protected SdkLongGaugeBuilder getThis() {
return this;
}

@Override
public SdkLongGauge build() {
return buildSynchronousInstrument(SdkLongGauge::new);
}

@Override
public LongGaugeBuilder setAdvice(Consumer<LongGaugeAdviceConfigurer> adviceConsumer) {
adviceConsumer.accept(this);
return this;
}

@Override
public LongGaugeAdviceConfigurer setAttributes(List<AttributeKey<?>> attributes) {
adviceBuilder.setAttributes(attributes);
return this;
}

@Override
public ObservableLongGauge buildWithCallback(Consumer<ObservableLongMeasurement> callback) {
// TODO: use InstrumentType.GAUGE when available
return registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback);
}

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