Add file configuration ComponentProvider support for resources (#6625)
This commit is contained in:
parent
902c46e2a7
commit
05fe136cb3
|
@ -81,9 +81,9 @@ public final class SpiHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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(StructuredConfigProperties)} with the given {@code model}.
|
||||
* ComponentProvider#create(StructuredConfigProperties)} with the given {@code config}.
|
||||
*
|
||||
* @throws ConfigurationException if no matching providers are found, or if multiple are found
|
||||
* (i.e. conflict), or if {@link ComponentProvider#create(StructuredConfigProperties)} throws
|
||||
|
|
|
@ -6,14 +6,25 @@
|
|||
package io.opentelemetry.sdk.extension.incubator.fileconfig;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Attributes;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Resource;
|
||||
import io.opentelemetry.sdk.resources.ResourceBuilder;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.io.Closeable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
final class ResourceFactory implements Factory<Resource, io.opentelemetry.sdk.resources.Resource> {
|
||||
final class ResourceFactory
|
||||
implements Factory<
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Resource, Resource> {
|
||||
|
||||
private static final StructuredConfigProperties EMPTY_CONFIG =
|
||||
FileConfiguration.toConfigProperties(Collections.emptyMap());
|
||||
private static final ResourceFactory INSTANCE = new ResourceFactory();
|
||||
|
||||
private ResourceFactory() {}
|
||||
|
@ -23,16 +34,82 @@ final class ResourceFactory implements Factory<Resource, io.opentelemetry.sdk.re
|
|||
}
|
||||
|
||||
@Override
|
||||
public io.opentelemetry.sdk.resources.Resource create(
|
||||
Resource model, SpiHelper spiHelper, List<Closeable> closeables) {
|
||||
ResourceBuilder builder = io.opentelemetry.sdk.resources.Resource.getDefault().toBuilder();
|
||||
public Resource create(
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Resource model,
|
||||
SpiHelper spiHelper,
|
||||
List<Closeable> closeables) {
|
||||
Resource result = Resource.getDefault();
|
||||
|
||||
List<Resource> resourceDetectorResources = loadFromResourceDetectors(spiHelper);
|
||||
for (Resource resourceProviderResource : resourceDetectorResources) {
|
||||
result = result.merge(resourceProviderResource);
|
||||
}
|
||||
|
||||
Attributes attributesModel = model.getAttributes();
|
||||
if (attributesModel != null) {
|
||||
builder.putAll(
|
||||
AttributesFactory.getInstance().create(attributesModel, spiHelper, closeables));
|
||||
result =
|
||||
result.toBuilder()
|
||||
.putAll(
|
||||
AttributesFactory.getInstance().create(attributesModel, spiHelper, closeables))
|
||||
.build();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load resources from resource detectors, in order of lowest priority to highest priority.
|
||||
*
|
||||
* <p>In file configuration, a resource detector is a {@link ComponentProvider} with {@link
|
||||
* ComponentProvider#getType()} set to {@link Resource}. Unlike other {@link ComponentProvider}s,
|
||||
* the resource detector version does not use {@link ComponentProvider#getName()} (except for
|
||||
* debug messages), and {@link ComponentProvider#create(StructuredConfigProperties)} is called
|
||||
* with an empty instance. Additionally, the {@link Ordered#order()} value is respected for
|
||||
* resource detectors which implement {@link Ordered}.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<Resource> loadFromResourceDetectors(SpiHelper spiHelper) {
|
||||
List<ComponentProvider> componentProviders = spiHelper.load(ComponentProvider.class);
|
||||
List<ResourceAndOrder> resourceAndOrders = new ArrayList<>();
|
||||
for (ComponentProvider<?> componentProvider : componentProviders) {
|
||||
if (componentProvider.getType() != Resource.class) {
|
||||
continue;
|
||||
}
|
||||
Resource resource;
|
||||
try {
|
||||
resource = (Resource) componentProvider.create(EMPTY_CONFIG);
|
||||
} catch (Throwable throwable) {
|
||||
throw new ConfigurationException(
|
||||
"Error configuring "
|
||||
+ Resource.class.getName()
|
||||
+ " with name \""
|
||||
+ componentProvider.getName()
|
||||
+ "\"",
|
||||
throwable);
|
||||
}
|
||||
int order =
|
||||
(componentProvider instanceof Ordered) ? ((Ordered) componentProvider).order() : 0;
|
||||
resourceAndOrders.add(new ResourceAndOrder(resource, order));
|
||||
}
|
||||
resourceAndOrders.sort(Comparator.comparing(ResourceAndOrder::order));
|
||||
return resourceAndOrders.stream().map(ResourceAndOrder::resource).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static final class ResourceAndOrder {
|
||||
private final Resource resource;
|
||||
private final int order;
|
||||
|
||||
private ResourceAndOrder(Resource resource, int order) {
|
||||
this.resource = resource;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
private Resource resource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
private int order() {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,6 +140,10 @@ class OpenTelemetryConfigurationFactoryTest {
|
|||
io.opentelemetry.sdk.resources.Resource.getDefault().toBuilder()
|
||||
.put("service.name", "my-service")
|
||||
.put("key", "val")
|
||||
// resource attributes from resource ComponentProviders
|
||||
.put("color", "red")
|
||||
.put("shape", "square")
|
||||
.put("order", "second")
|
||||
.build();
|
||||
OpenTelemetrySdk expectedSdk =
|
||||
OpenTelemetrySdk.builder()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package io.opentelemetry.sdk.extension.incubator.fileconfig;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Attributes;
|
||||
|
@ -16,8 +16,11 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
class ResourceFactoryTest {
|
||||
|
||||
private SpiHelper spiHelper = SpiHelper.create(MetricExporterFactoryTest.class.getClassLoader());
|
||||
|
||||
@Test
|
||||
void create() {
|
||||
spiHelper = spy(spiHelper);
|
||||
assertThat(
|
||||
ResourceFactory.getInstance()
|
||||
.create(
|
||||
|
@ -26,13 +29,21 @@ class ResourceFactoryTest {
|
|||
.withAttributes(
|
||||
new Attributes()
|
||||
.withServiceName("my-service")
|
||||
.withAdditionalProperty("key", "val")),
|
||||
mock(SpiHelper.class),
|
||||
.withAdditionalProperty("key", "val")
|
||||
// Should override shape attribute from ResourceComponentProvider
|
||||
.withAdditionalProperty("shape", "circle")),
|
||||
spiHelper,
|
||||
Collections.emptyList()))
|
||||
.isEqualTo(
|
||||
Resource.getDefault().toBuilder()
|
||||
.put("service.name", "my-service")
|
||||
.put("key", "val")
|
||||
.put("shape", "circle")
|
||||
// From ResourceComponentProvider
|
||||
.put("color", "red")
|
||||
// From ResourceOrderedSecondComponentProvider, which takes priority over
|
||||
// ResourceOrderedFirstComponentProvider
|
||||
.put("order", "second")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
|
||||
public class ResourceComponentProvider implements ComponentProvider<Resource> {
|
||||
@Override
|
||||
public Class<Resource> getType() {
|
||||
return Resource.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "unused";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource create(StructuredConfigProperties config) {
|
||||
return Resource.builder().put("shape", "square").put("color", "red").build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
|
||||
public class ResourceOrderedFirstComponentProvider implements ComponentProvider<Resource>, Ordered {
|
||||
@Override
|
||||
public Class<Resource> getType() {
|
||||
return Resource.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "unused";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource create(StructuredConfigProperties config) {
|
||||
return Resource.builder().put("order", "first").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
|
||||
public class ResourceOrderedSecondComponentProvider
|
||||
implements ComponentProvider<Resource>, Ordered {
|
||||
@Override
|
||||
public Class<Resource> getType() {
|
||||
return Resource.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "unused";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource create(StructuredConfigProperties config) {
|
||||
return Resource.builder().put("order", "second").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceComponentProvider
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceOrderedFirstComponentProvider
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceOrderedSecondComponentProvider
|
||||
|
|
Loading…
Reference in New Issue