Skip to content

Add DeclarativeConfigContext #7293

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Base2ExponentialBucketHistogramAggregationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramAggregationModel;
import io.opentelemetry.sdk.metrics.Aggregation;
import java.io.Closeable;
import java.util.List;

final class AggregationFactory implements Factory<AggregationModel, Aggregation> {
Expand All @@ -25,8 +23,7 @@ static AggregationFactory getInstance() {
}

@Override
public Aggregation create(
AggregationModel model, SpiHelper spiHelper, List<Closeable> closeables) {
public Aggregation create(AggregationModel model, DeclarativeConfigContext context) {
if (model.getDrop() != null) {
return Aggregation.drop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

Expand All @@ -28,8 +26,7 @@ static AttributeListFactory getInstance() {
}

@Override
public Attributes create(
List<AttributeNameValueModel> model, SpiHelper spiHelper, List<Closeable> closeables) {
public Attributes create(List<AttributeNameValueModel> model, DeclarativeConfigContext context) {
AttributesBuilder builder = Attributes.builder();

for (AttributeNameValueModel nameValueModel : model) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel;
import io.opentelemetry.sdk.metrics.export.CardinalityLimitSelector;
import io.opentelemetry.sdk.metrics.internal.state.MetricStorage;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

final class CardinalityLimitsFactory
Expand All @@ -26,7 +23,7 @@ static CardinalityLimitsFactory getInstance() {

@Override
public CardinalityLimitSelector create(
CardinalityLimitsModel model, SpiHelper spiHelper, List<Closeable> closeables) {
CardinalityLimitsModel model, DeclarativeConfigContext context) {
int defaultLimit = getOrDefault(model.getDefault(), MetricStorage.DEFAULT_MAX_CARDINALITY);
int counterLimit = getOrDefault(model.getCounter(), defaultLimit);
int gaugeLimit = getOrDefault(model.getGauge(), defaultLimit);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/** Declarative configuration context and state carrier. */
class DeclarativeConfigContext {

private final SpiHelper spiHelper;
private final List<Closeable> closeables = new ArrayList<>();

DeclarativeConfigContext(SpiHelper spiHelper) {
this.spiHelper = spiHelper;
}

/**
* Add the {@code closeable} to the list of closeables to clean up if configuration fails
* exceptionally, and return it.
*/
<T extends Closeable> T addCloseable(T closeable) {
closeables.add(closeable);
return closeable;
}

List<Closeable> getCloseables() {
return Collections.unmodifiableList(closeables);
}

/**
* Find a registered {@link ComponentProvider} which {@link ComponentProvider#getType()} matching
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* Find a registered {@link ComponentProvider} which {@link ComponentProvider#getType()} matching
* Find a registered {@link ComponentProvider} with {@link ComponentProvider#getType()} matching

* {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link
* ComponentProvider#create(DeclarativeConfigProperties)} with the given {@code model}.
*
* @throws DeclarativeConfigException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(DeclarativeConfigProperties)} throws
*/
@SuppressWarnings({"unchecked", "rawtypes"})
<T> T loadComponent(Class<T> type, String name, Object model) {
DeclarativeConfigProperties config =
DeclarativeConfiguration.toConfigProperties(model, spiHelper.getComponentLoader());

// TODO(jack-berg): cache loaded component providers
List<ComponentProvider> componentProviders = spiHelper.load(ComponentProvider.class);
List<ComponentProvider<?>> matchedProviders =
componentProviders.stream()
.map(
(Function<ComponentProvider, ComponentProvider<?>>)
componentProvider -> componentProvider)
.filter(
componentProvider ->
componentProvider.getType() == type && name.equals(componentProvider.getName()))
.collect(Collectors.toList());
if (matchedProviders.isEmpty()) {
throw new DeclarativeConfigException(
"No component provider detected for " + type.getName() + " with name \"" + name + "\".");
}
if (matchedProviders.size() > 1) {
throw new DeclarativeConfigException(

Check warning on line 71 in sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java

View check run for this annotation

Codecov / codecov/patch

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java#L71

Added line #L71 was not covered by tests
"Component provider conflict. Multiple providers detected for "
+ type.getName()

Check warning on line 73 in sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java

View check run for this annotation

Codecov / codecov/patch

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java#L73

Added line #L73 was not covered by tests
+ " with name \""
+ name
+ "\": "
+ componentProviders.stream()
.map(provider -> provider.getClass().getName())
.collect(Collectors.joining(",", "[", "]")));

Check warning on line 79 in sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java

View check run for this annotation

Codecov / codecov/patch

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java#L77-L79

Added lines #L77 - L79 were not covered by tests
}
// Exactly one matching component provider
ComponentProvider<T> provider = (ComponentProvider<T>) matchedProviders.get(0);

try {
return provider.create(config);
} catch (Throwable throwable) {
throw new DeclarativeConfigException(
"Error configuring " + type.getName() + " with name \"" + name + "\"", throwable);

Check warning on line 88 in sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java

View check run for this annotation

Codecov / codecov/patch

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java#L86-L88

Added lines #L86 - L88 were not covered by tests
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -221,12 +220,12 @@ static <T> T convertToModel(
}

static <M, R> R createAndMaybeCleanup(Factory<M, R> factory, SpiHelper spiHelper, M model) {
List<Closeable> closeables = new ArrayList<>();
DeclarativeConfigContext context = new DeclarativeConfigContext(spiHelper);
try {
return factory.create(model, spiHelper, closeables);
return factory.create(model, context);
} catch (RuntimeException e) {
logger.info("Error encountered interpreting model. Closing partially configured components.");
for (Closeable closeable : closeables) {
for (Closeable closeable : context.getCloseables()) {
try {
logger.fine("Closing " + closeable.getClass().getName());
closeable.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,14 @@

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import java.io.Closeable;
import java.util.List;

interface Factory<ModelT, ResultT> {

/**
* Interpret the model and create {@link ResultT} with corresponding configuration.
*
* @param model the configuration model
* @param spiHelper the service loader helper
* @param closeables mutable list of closeables created
* @param context the configuration context
* @return the {@link ResultT}
*/
ResultT create(ModelT model, SpiHelper spiHelper, List<Closeable> closeables);
ResultT create(ModelT model, DeclarativeConfigContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,13 @@
import static java.util.stream.Collectors.joining;

import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import java.io.Closeable;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;

final class FileConfigUtil {

private FileConfigUtil() {}

/** Add the {@code closeable} to the {@code closeables} and return it. */
static <T> T addAndReturn(List<Closeable> closeables, T closeable) {
if (closeable instanceof Closeable) {
closeables.add((Closeable) closeable);
}
return closeable;
}

static <T> T assertNotNull(@Nullable T object, String description) {
if (object == null) {
throw new NullPointerException(description + " is null");
Expand All @@ -44,69 +29,6 @@ static <T> T requireNonNull(@Nullable T object, String description) {
return object;
}

/**
* Find a registered {@link ComponentProvider} which {@link ComponentProvider#getType()} matching
* {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link
* ComponentProvider#create(DeclarativeConfigProperties)} with the given {@code model}.
*
* @throws DeclarativeConfigException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(DeclarativeConfigProperties)} throws
*/
static <T> T loadComponent(SpiHelper spiHelper, Class<T> type, String name, Object model) {
// Map model to generic structured config properties
DeclarativeConfigProperties config =
DeclarativeConfiguration.toConfigProperties(model, spiHelper.getComponentLoader());
return loadComponentHelper(spiHelper, type, name, config);
}

/**
* Find a registered {@link ComponentProvider} with {@link ComponentProvider#getType()} matching
* {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link
* ComponentProvider#create(DeclarativeConfigProperties)} with the given {@code config}.
*
* @throws DeclarativeConfigException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(DeclarativeConfigProperties)} throws
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private static <T> T loadComponentHelper(
SpiHelper spiHelper, Class<T> type, String name, DeclarativeConfigProperties config) {
// TODO(jack-berg): cache loaded component providers
List<ComponentProvider> componentProviders = spiHelper.load(ComponentProvider.class);
List<ComponentProvider<?>> matchedProviders =
componentProviders.stream()
.map(
(Function<ComponentProvider, ComponentProvider<?>>)
componentProvider -> componentProvider)
.filter(
componentProvider ->
componentProvider.getType() == type && name.equals(componentProvider.getName()))
.collect(Collectors.toList());
if (matchedProviders.isEmpty()) {
throw new DeclarativeConfigException(
"No component provider detected for " + type.getName() + " with name \"" + name + "\".");
}
if (matchedProviders.size() > 1) {
throw new DeclarativeConfigException(
"Component provider conflict. Multiple providers detected for "
+ type.getName()
+ " with name \""
+ name
+ "\": "
+ componentProviders.stream()
.map(provider -> provider.getClass().getName())
.collect(Collectors.joining(",", "[", "]")));
}
// Exactly one matching component provider
ComponentProvider<T> provider = (ComponentProvider<T>) matchedProviders.get(0);

try {
return provider.create(config);
} catch (Throwable throwable) {
throw new DeclarativeConfigException(
"Error configuring " + type.getName() + " with name \"" + name + "\"", throwable);
}
}

static Map.Entry<String, Object> getSingletonMapEntry(
Map<String, Object> additionalProperties, String resourceName) {
if (additionalProperties.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.InstrumentSelectorBuilder;
import io.opentelemetry.sdk.metrics.InstrumentType;
import java.io.Closeable;
import java.util.List;

final class InstrumentSelectorFactory implements Factory<ViewSelectorModel, InstrumentSelector> {

Expand All @@ -25,8 +22,7 @@ static InstrumentSelectorFactory getInstance() {
}

@Override
public InstrumentSelector create(
ViewSelectorModel model, SpiHelper spiHelper, List<Closeable> closeables) {
public InstrumentSelector create(ViewSelectorModel model, DeclarativeConfigContext context) {
InstrumentSelectorBuilder builder = InstrumentSelector.builder();
if (model.getInstrumentName() != null) {
builder.setName(model.getInstrumentName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel;
import io.opentelemetry.sdk.logs.LogLimits;
import io.opentelemetry.sdk.logs.LogLimitsBuilder;
import java.io.Closeable;
import java.util.List;

final class LogLimitsFactory implements Factory<LogRecordLimitsAndAttributeLimits, LogLimits> {

Expand All @@ -25,7 +22,7 @@ static LogLimitsFactory getInstance() {

@Override
public LogLimits create(
LogRecordLimitsAndAttributeLimits model, SpiHelper spiHelper, List<Closeable> closeables) {
LogRecordLimitsAndAttributeLimits model, DeclarativeConfigContext context) {
LogLimitsBuilder builder = LogLimits.builder();

AttributeLimitsModel attributeLimitsModel = model.getAttributeLimits();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import java.io.Closeable;
import java.util.List;
import java.util.Map;

final class LogRecordExporterFactory implements Factory<LogRecordExporterModel, LogRecordExporter> {
Expand All @@ -23,8 +20,7 @@ static LogRecordExporterFactory getInstance() {
}

@Override
public LogRecordExporter create(
LogRecordExporterModel model, SpiHelper spiHelper, List<Closeable> closeables) {
public LogRecordExporter create(LogRecordExporterModel model, DeclarativeConfigContext context) {

model.getAdditionalProperties().compute("otlp_http", (k, v) -> model.getOtlpHttp());
model.getAdditionalProperties().compute("otlp_grpc", (k, v) -> model.getOtlpGrpc());
Expand All @@ -36,8 +32,7 @@ public LogRecordExporter create(
Map.Entry<String, Object> keyValue =
FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "log record exporter");
LogRecordExporter logRecordExporter =
FileConfigUtil.loadComponent(
spiHelper, LogRecordExporter.class, keyValue.getKey(), keyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, logRecordExporter);
context.loadComponent(LogRecordExporter.class, keyValue.getKey(), keyValue.getValue());
return context.addCloseable(logRecordExporter);
}
}
Loading
Loading