Update to opentelemetry-configuration v0.3.0 (#6733)

This commit is contained in:
jack-berg 2024-09-30 14:12:25 -05:00 committed by GitHub
parent 697b4e0c70
commit 2dbb8de349
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 890 additions and 438 deletions

View File

@ -66,7 +66,7 @@ val DEPENDENCIES = listOf(
"eu.rekawek.toxiproxy:toxiproxy-java:2.1.7",
"io.github.netmikey.logunit:logunit-jul:2.0.0",
"io.jaegertracing:jaeger-client:1.8.1",
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.29.0-alpha",
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.39.0-alpha",
"io.opentelemetry.semconv:opentelemetry-semconv-incubating:1.27.0-alpha",
"io.opentelemetry.proto:opentelemetry-proto:1.3.2-alpha",
"io.opentracing:opentracing-api:0.33.0",

View File

@ -10,6 +10,7 @@ import static io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.RetryPolicy;
@ -27,6 +28,8 @@ import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.BiConsumer;
@ -97,21 +100,7 @@ public final class OtlpConfigUtil {
setEndpoint.accept(endpoint.toString());
}
Map<String, String> headers = config.getMap("otel.exporter.otlp." + dataType + ".headers");
if (headers.isEmpty()) {
headers = config.getMap("otel.exporter.otlp.headers");
}
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
try {
// headers are encoded as URL - see
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specifying-headers-via-environment-variables
addHeader.accept(key, URLDecoder.decode(value, StandardCharsets.UTF_8.displayName()));
} catch (Exception e) {
throw new ConfigurationException("Cannot decode header value: " + value, e);
}
}
configureOtlpHeaders(config, dataType, addHeader);
String compression = config.getString("otel.exporter.otlp." + dataType + ".compression");
if (compression == null) {
@ -190,29 +179,28 @@ public final class OtlpConfigUtil {
String protocol = getStructuredConfigOtlpProtocol(config);
boolean isHttpProtobuf = protocol.equals(PROTOCOL_HTTP_PROTOBUF);
URL endpoint = validateEndpoint(config.getString("endpoint"), isHttpProtobuf);
if (endpoint != null && isHttpProtobuf) {
String path = endpoint.getPath();
if (!path.endsWith("/")) {
path += "/";
}
path += signalPath(dataType);
endpoint = createUrl(endpoint, path);
}
if (endpoint != null) {
setEndpoint.accept(endpoint.toString());
}
StructuredConfigProperties headers = config.getStructured("headers");
String headerList = config.getString("headers_list");
if (headerList != null) {
ConfigProperties headersListConfig =
DefaultConfigProperties.createFromMap(
Collections.singletonMap("otel.exporter.otlp.headers", headerList));
configureOtlpHeaders(headersListConfig, dataType, addHeader);
}
List<StructuredConfigProperties> headers = config.getStructuredList("headers");
if (headers != null) {
headers
.getPropertyKeys()
.forEach(
header -> {
String value = headers.getString(header);
if (value != null) {
addHeader.accept(header, value);
}
});
headers.forEach(
header -> {
String name = header.getString("name");
String value = header.getString("value");
if (name != null && value != null) {
addHeader.accept(name, value);
}
});
}
String compression = config.getString("compression");
@ -249,6 +237,25 @@ public final class OtlpConfigUtil {
ExporterBuilderUtil.configureExporterMemoryMode(config, setMemoryMode);
}
private static void configureOtlpHeaders(
ConfigProperties config, String dataType, BiConsumer<String, String> addHeader) {
Map<String, String> headers = config.getMap("otel.exporter.otlp." + dataType + ".headers");
if (headers.isEmpty()) {
headers = config.getMap("otel.exporter.otlp.headers");
}
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
try {
// headers are encoded as URL - see
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specifying-headers-via-environment-variables
addHeader.accept(key, URLDecoder.decode(value, StandardCharsets.UTF_8.displayName()));
} catch (Exception e) {
throw new ConfigurationException("Cannot decode header value: " + value, e);
}
}
}
/**
* Invoke the {@code aggregationTemporalitySelectorConsumer} with the configured {@link
* AggregationTemporality}.

View File

@ -34,7 +34,8 @@ class FileConfigurationTest {
"file_format: \"0.1\"\n"
+ "resource:\n"
+ " attributes:\n"
+ " service.name: test\n"
+ " - name: service.name\n"
+ " value: test\n"
+ "tracer_provider:\n"
+ " processors:\n"
+ " - simple:\n"

View File

@ -58,7 +58,8 @@ class FileConfigurationTest {
"file_format: \"0.1\"\n"
+ "resource:\n"
+ " attributes:\n"
+ " service.name: test\n"
+ " - name: service.name\n"
+ " value: test\n"
+ "tracer_provider:\n"
+ " processors:\n"
+ " - simple:\n"
@ -162,7 +163,8 @@ class FileConfigurationTest {
"file_format: \"0.1\"\n"
+ "resource:\n"
+ " attributes:\n"
+ " service.name: test\n"
+ " - name: service.name\n"
+ " value: test\n"
+ "tracer_provider:\n"
+ " processors:\n"
+ " - simple:\n"

View File

@ -49,13 +49,14 @@ dependencies {
// The sequence of tasks is:
// 1. downloadConfigurationSchema - download configuration schema from open-telemetry/opentelemetry-configuration
// 2. unzipConfigurationSchema - unzip the configuration schema archive contents to $buildDir/configuration/
// 3. generateJsonSchema2Pojo - generate java POJOs from the configuration schema
// 4. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation
// 5. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation
// 6. deleteJs2pTmp - delete tmp directory
// 3. deleteTypeDescriptions - delete type_descriptions.yaml $buildDir/configuration/schema, which is not part of core schema and causes problems resolving type refs
// 4. generateJsonSchema2Pojo - generate java POJOs from the configuration schema
// 5. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation
// 6. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation
// 7. deleteJs2pTmp - delete tmp directory
// ... proceed with normal sourcesJar, compileJava, etc
val configurationTag = "0.1.0"
val configurationTag = "0.3.0"
val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit
val configurationRepoZip = "https://github.com/open-telemetry/opentelemetry-configuration/archive/$configurationRef.zip"
val buildDirectory = layout.buildDirectory.asFile.get()
@ -78,6 +79,11 @@ val unzipConfigurationSchema by tasks.registering(Copy::class) {
into("$buildDirectory/configuration/")
}
val deleteTypeDescriptions by tasks.registering(Delete::class) {
dependsOn(unzipConfigurationSchema)
delete("$buildDirectory/configuration/schema/type_descriptions.yaml")
}
jsonSchema2Pojo {
sourceFiles = setOf(file("$buildDirectory/configuration/schema"))
targetDirectory = file("$buildDirectory/generated/sources/js2p/java/main")
@ -106,7 +112,7 @@ jsonSchema2Pojo {
}
val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo")
generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema)
generateJsonSchema2Pojo.dependsOn(deleteTypeDescriptions)
val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) {
dependsOn(generateJsonSchema2Pojo)

View File

@ -0,0 +1,140 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.toList;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;
final class AttributeListFactory
implements Factory<List<AttributeNameValueModel>, io.opentelemetry.api.common.Attributes> {
private static final AttributeListFactory INSTANCE = new AttributeListFactory();
private AttributeListFactory() {}
static AttributeListFactory getInstance() {
return INSTANCE;
}
@Override
public io.opentelemetry.api.common.Attributes create(
List<AttributeNameValueModel> model, SpiHelper spiHelper, List<Closeable> closeables) {
AttributesBuilder builder = io.opentelemetry.api.common.Attributes.builder();
for (AttributeNameValueModel nameValueModel : model) {
addToBuilder(nameValueModel, builder);
}
return builder.build();
}
private static void addToBuilder(
AttributeNameValueModel nameValueModel, AttributesBuilder builder) {
String name = FileConfigUtil.requireNonNull(nameValueModel.getName(), "attribute name");
Object value = FileConfigUtil.requireNonNull(nameValueModel.getValue(), "attribute value");
AttributeNameValueModel.Type type = nameValueModel.getType();
if (type == null) {
type = AttributeNameValueModel.Type.STRING;
}
switch (type) {
case STRING:
if (value instanceof String) {
builder.put(name, (String) value);
return;
}
break;
case BOOL:
if (value instanceof Boolean) {
builder.put(name, (boolean) value);
return;
}
break;
case INT:
if ((value instanceof Integer) || (value instanceof Long)) {
builder.put(name, ((Number) value).longValue());
return;
}
break;
case DOUBLE:
if (value instanceof Number) {
builder.put(name, ((Number) value).doubleValue());
return;
}
break;
case STRING_ARRAY:
List<String> stringList = checkListOfType(value, String.class);
if (stringList != null) {
builder.put(AttributeKey.stringArrayKey(name), stringList);
return;
}
break;
case BOOL_ARRAY:
List<Boolean> boolList = checkListOfType(value, Boolean.class);
if (boolList != null) {
builder.put(AttributeKey.booleanArrayKey(name), boolList);
return;
}
break;
case INT_ARRAY:
List<Long> longList = checkListOfType(value, Long.class);
if (longList != null) {
builder.put(AttributeKey.longArrayKey(name), longList);
return;
}
List<Integer> intList = checkListOfType(value, Integer.class);
if (intList != null) {
builder.put(
AttributeKey.longArrayKey(name),
intList.stream().map(i -> (long) i).collect(toList()));
return;
}
break;
case DOUBLE_ARRAY:
List<Double> doubleList = checkListOfType(value, Double.class);
if (doubleList != null) {
builder.put(AttributeKey.doubleArrayKey(name), doubleList);
return;
}
List<Float> floatList = checkListOfType(value, Float.class);
if (floatList != null) {
builder.put(
AttributeKey.doubleArrayKey(name),
floatList.stream().map(i -> (double) i).collect(toList()));
return;
}
break;
}
throw new ConfigurationException(
"Error processing attribute with name \""
+ name
+ "\": value did not match type "
+ type.name());
}
@SuppressWarnings("unchecked")
@Nullable
private static <T> List<T> checkListOfType(Object value, Class<T> expectedType) {
if (!(value instanceof List)) {
return null;
}
List<?> list = (List<?>) value;
if (list.isEmpty()) {
return null;
}
if (!list.stream().allMatch(entry -> expectedType.isAssignableFrom(entry.getClass()))) {
return null;
}
return (List<T>) value;
}
}

View File

@ -1,152 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributesModel;
import java.io.Closeable;
import java.util.List;
final class AttributesFactory
implements Factory<AttributesModel, io.opentelemetry.api.common.Attributes> {
private static final AttributesFactory INSTANCE = new AttributesFactory();
private AttributesFactory() {}
static AttributesFactory getInstance() {
return INSTANCE;
}
@Override
public io.opentelemetry.api.common.Attributes create(
AttributesModel model, SpiHelper spiHelper, List<Closeable> closeables) {
AttributesBuilder builder = io.opentelemetry.api.common.Attributes.builder();
String serviceName = model.getServiceName();
if (serviceName != null) {
builder.put(stringKey("service.name"), serviceName);
}
model
.getAdditionalProperties()
.forEach(
(key, value) -> {
if (value == null) {
throw new ConfigurationException(
"Error processing attribute with key \"" + key + "\": unexpected null value");
}
if (value instanceof String) {
builder.put(key, (String) value);
return;
}
if (value instanceof Integer) {
builder.put(key, (int) value);
return;
}
if (value instanceof Long) {
builder.put(key, (long) value);
return;
}
if (value instanceof Double) {
builder.put(key, (double) value);
return;
}
if (value instanceof Float) {
builder.put(key, (float) value);
return;
}
if (value instanceof Boolean) {
builder.put(key, (boolean) value);
return;
}
if (value instanceof List) {
List<?> values = (List<?>) value;
if (values.isEmpty()) {
return;
}
Object first = values.get(0);
if (first instanceof String) {
checkAllEntriesOfType(key, values, String.class);
builder.put(
AttributeKey.stringArrayKey(key),
values.stream().map(obj -> (String) obj).toArray(String[]::new));
return;
}
if (first instanceof Long) {
checkAllEntriesOfType(key, values, Long.class);
builder.put(
AttributeKey.longArrayKey(key),
values.stream().map(obj -> (long) obj).toArray(Long[]::new));
return;
}
if (first instanceof Integer) {
checkAllEntriesOfType(key, values, Integer.class);
builder.put(
AttributeKey.longArrayKey(key),
values.stream().map(obj -> Long.valueOf((int) obj)).toArray(Long[]::new));
return;
}
if (first instanceof Double) {
checkAllEntriesOfType(key, values, Double.class);
builder.put(
AttributeKey.doubleArrayKey(key),
values.stream().map(obj -> (double) obj).toArray(Double[]::new));
return;
}
if (first instanceof Float) {
checkAllEntriesOfType(key, values, Float.class);
builder.put(
AttributeKey.doubleArrayKey(key),
values.stream()
.map(obj -> Double.valueOf((float) obj))
.toArray(Double[]::new));
return;
}
if (first instanceof Boolean) {
checkAllEntriesOfType(key, values, Boolean.class);
builder.put(
AttributeKey.booleanArrayKey(key),
values.stream().map(obj -> (Boolean) obj).toArray(Boolean[]::new));
return;
}
}
throw new ConfigurationException(
"Error processing attribute with key \""
+ key
+ "\": unrecognized value type "
+ value.getClass().getName());
});
return builder.build();
}
private static void checkAllEntriesOfType(String key, List<?> values, Class<?> expectedType) {
values.forEach(
value -> {
if (value == null) {
throw new ConfigurationException(
"Error processing attribute with key \""
+ key
+ "\": unexpected null element in value");
}
if (!expectedType.isAssignableFrom(value.getClass())) {
throw new ConfigurationException(
"Error processing attribute with key \""
+ key
+ "\": expected value entries to be of type "
+ expectedType
+ " but found entry with type "
+ value.getClass());
}
});
}
}

View File

@ -49,7 +49,7 @@ public final class FileConfiguration {
private static final Logger logger = Logger.getLogger(FileConfiguration.class.getName());
private static final Pattern ENV_VARIABLE_REFERENCE =
Pattern.compile("\\$\\{([a-zA-Z_][a-zA-Z0-9_]*)}");
Pattern.compile("\\$\\{([a-zA-Z_][a-zA-Z0-9_]*)(:-([^\n]*))?\\}");
private static final ComponentLoader DEFAULT_COMPONENT_LOADER =
SpiHelper.serviceComponentLoader(FileConfiguration.class.getClassLoader());
@ -313,7 +313,12 @@ public final class FileConfiguration {
ScalarStyle scalarStyle = ((ScalarNode) node).getScalarStyle();
do {
MatchResult matchResult = matcher.toMatchResult();
String replacement = environmentVariables.getOrDefault(matcher.group(1), "");
String envVarKey = matcher.group(1);
String defaultValue = matcher.group(3);
if (defaultValue == null) {
defaultValue = "";
}
String replacement = environmentVariables.getOrDefault(envVarKey, defaultValue);
newVal.append(val, offset, matchResult.start()).append(replacement);
offset = matchResult.end();
} while (matcher.find());

View File

@ -9,6 +9,7 @@ import static java.util.stream.Collectors.joining;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
@ -34,6 +35,11 @@ final class LogRecordExporterFactory implements Factory<LogRecordExporterModel,
model.getAdditionalProperties().put("otlp", otlpModel);
}
ConsoleModel consoleModel = model.getConsole();
if (consoleModel != null) {
model.getAdditionalProperties().put("console", consoleModel);
}
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {

View File

@ -9,14 +9,14 @@ import static java.util.stream.Collectors.joining;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import java.io.Closeable;
import java.util.List;
import java.util.Map;
final class MetricExporterFactory implements Factory<MetricExporterModel, MetricExporter> {
final class MetricExporterFactory implements Factory<PushMetricExporterModel, MetricExporter> {
private static final MetricExporterFactory INSTANCE = new MetricExporterFactory();
@ -28,7 +28,7 @@ final class MetricExporterFactory implements Factory<MetricExporterModel, Metric
@Override
public MetricExporter create(
MetricExporterModel model, SpiHelper spiHelper, List<Closeable> closeables) {
PushMetricExporterModel model, SpiHelper spiHelper, List<Closeable> closeables) {
OtlpMetricModel otlpModel = model.getOtlp();
if (otlpModel != null) {
model.getAdditionalProperties().put("otlp", otlpModel);
@ -38,10 +38,6 @@ final class MetricExporterFactory implements Factory<MetricExporterModel, Metric
model.getAdditionalProperties().put("console", model.getConsole());
}
if (model.getPrometheus() != null) {
throw new ConfigurationException("prometheus exporter not supported in this context");
}
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {

View File

@ -9,11 +9,12 @@ import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigUtil
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PrometheusModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReaderBuilder;
import java.io.Closeable;
@ -35,7 +36,7 @@ final class MetricReaderFactory implements Factory<MetricReaderModel, MetricRead
MetricReaderModel model, SpiHelper spiHelper, List<Closeable> closeables) {
PeriodicMetricReaderModel periodicModel = model.getPeriodic();
if (periodicModel != null) {
MetricExporterModel exporterModel =
PushMetricExporterModel exporterModel =
requireNonNull(periodicModel.getExporter(), "periodic metric reader exporter");
io.opentelemetry.sdk.metrics.export.MetricExporter metricExporter =
MetricExporterFactory.getInstance().create(exporterModel, spiHelper, closeables);
@ -50,7 +51,7 @@ final class MetricReaderFactory implements Factory<MetricReaderModel, MetricRead
PullMetricReaderModel pullModel = model.getPull();
if (pullModel != null) {
MetricExporterModel exporterModel =
PullMetricExporterModel exporterModel =
requireNonNull(pullModel.getExporter(), "pull metric reader exporter");
PrometheusModel prometheusModel = exporterModel.getPrometheus();
if (prometheusModel != null) {

View File

@ -5,19 +5,28 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.internal.GlobUtil.toGlobPatternPredicate;
import io.opentelemetry.sdk.autoconfigure.ResourceConfiguration;
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.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorAttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorsModel;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.resources.ResourceBuilder;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
final class ResourceFactory
implements Factory<
@ -41,23 +50,39 @@ final class ResourceFactory
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel model,
SpiHelper spiHelper,
List<Closeable> closeables) {
Resource result = Resource.getDefault();
ResourceBuilder builder = Resource.getDefault().toBuilder();
ResourceBuilder detectedResourceBuilder = Resource.builder();
List<Resource> resourceDetectorResources = loadFromResourceDetectors(spiHelper);
for (Resource resourceProviderResource : resourceDetectorResources) {
result = result.merge(resourceProviderResource);
detectedResourceBuilder.putAll(resourceProviderResource);
}
Predicate<String> detectorAttributeFilter = detectorAttributeFilter(model.getDetectors());
builder
.putAll(
detectedResourceBuilder.build().getAttributes().toBuilder()
.removeIf(attributeKey -> !detectorAttributeFilter.test(attributeKey.getKey()))
.build())
.build();
String attributeList = model.getAttributesList();
if (attributeList != null) {
builder.putAll(
ResourceConfiguration.createEnvironmentResource(
DefaultConfigProperties.createFromMap(
Collections.singletonMap("otel.resource.attributes", attributeList))));
}
AttributesModel attributesModel = model.getAttributes();
if (attributesModel != null) {
result =
result.toBuilder()
.putAll(
AttributesFactory.getInstance().create(attributesModel, spiHelper, closeables))
.build();
List<AttributeNameValueModel> attributeNameValueModel = model.getAttributes();
if (attributeNameValueModel != null) {
builder
.putAll(
AttributeListFactory.getInstance()
.create(attributeNameValueModel, spiHelper, closeables))
.build();
}
return result;
return builder.build();
}
/**
@ -115,4 +140,54 @@ final class ResourceFactory
return order;
}
}
private static boolean matchAll(String attributeKey) {
return true;
}
private static Predicate<String> detectorAttributeFilter(
@Nullable DetectorsModel detectorsModel) {
if (detectorsModel == null) {
return ResourceFactory::matchAll;
}
DetectorAttributesModel detectorAttributesModel = detectorsModel.getAttributes();
if (detectorAttributesModel == null) {
return ResourceFactory::matchAll;
}
List<String> included = detectorAttributesModel.getIncluded();
List<String> excluded = detectorAttributesModel.getExcluded();
if (included == null && excluded == null) {
return ResourceFactory::matchAll;
}
if (included == null) {
return excludedPredicate(excluded);
}
if (excluded == null) {
return includedPredicate(included);
}
return includedPredicate(included).and(excludedPredicate(excluded));
}
/**
* Returns a predicate which matches strings matching any of the {@code included} glob patterns.
*/
private static Predicate<String> includedPredicate(List<String> included) {
Predicate<String> result = attributeKey -> false;
for (String include : included) {
result = result.or(toGlobPatternPredicate(include));
}
return result;
}
/**
* Returns a predicate which matches strings NOT matching any of the {@code excluded} glob
* patterns.
*/
private static Predicate<String> excludedPredicate(List<String> excluded) {
Predicate<String> result = attributeKey -> true;
for (String exclude : excluded) {
result = result.and(toGlobPatternPredicate(exclude).negate());
}
return result;
}
}

View File

@ -6,12 +6,15 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.StreamModel;
import io.opentelemetry.sdk.metrics.View;
import io.opentelemetry.sdk.metrics.ViewBuilder;
import java.io.Closeable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
final class ViewFactory implements Factory<StreamModel, View> {
@ -32,8 +35,9 @@ final class ViewFactory implements Factory<StreamModel, View> {
if (model.getDescription() != null) {
builder.setDescription(model.getDescription());
}
if (model.getAttributeKeys() != null) {
builder.setAttributeFilter(new HashSet<>(model.getAttributeKeys()));
IncludeExcludeModel attributeKeys = model.getAttributeKeys();
if (attributeKeys != null) {
addAttributeKeyFilter(builder, attributeKeys.getIncluded(), attributeKeys.getExcluded());
}
if (model.getAggregation() != null) {
builder.setAggregation(
@ -41,4 +45,25 @@ final class ViewFactory implements Factory<StreamModel, View> {
}
return builder.build();
}
private static void addAttributeKeyFilter(
ViewBuilder builder, @Nullable List<String> included, @Nullable List<String> excluded) {
if (included == null && excluded == null) {
return;
}
if (included == null) {
Set<String> excludedKeys = new HashSet<>(excluded);
// TODO: set predicate with useful toString implementation
builder.setAttributeFilter(attributeKey -> !excludedKeys.contains(attributeKey));
return;
}
if (excluded == null) {
Set<String> includedKeys = new HashSet<>(included);
builder.setAttributeFilter(includedKeys);
return;
}
Set<String> includedKeys = new HashSet<>(included);
excluded.forEach(includedKeys::remove);
builder.setAttributeFilter(includedKeys);
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class AttributeListFactoryTest {
@ParameterizedTest
@MethodSource("invalidAttributes")
void create_InvalidAttributes(List<AttributeNameValueModel> model, String expectedMessage) {
assertThatThrownBy(
() ->
AttributeListFactory.getInstance()
.create(model, mock(SpiHelper.class), Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(expectedMessage);
}
private static Stream<Arguments> invalidAttributes() {
return Stream.of(
Arguments.of(
Collections.singletonList(new AttributeNameValueModel().withName("key")),
"attribute value is required but is null"),
Arguments.of(
Collections.singletonList(
new AttributeNameValueModel().withName("key").withValue(new Object())),
"Error processing attribute with name \"key\": value did not match type STRING"),
Arguments.of(
Collections.singletonList(
new AttributeNameValueModel()
.withName("key")
.withType(AttributeNameValueModel.Type.INT)
.withValue(Arrays.asList(1L, 1))),
"Error processing attribute with name \"key\": value did not match type INT"),
Arguments.of(
Collections.singletonList(
new AttributeNameValueModel()
.withName("key")
.withType(AttributeNameValueModel.Type.INT)
.withValue(true)),
"Error processing attribute with name \"key\": value did not match type INT"));
}
@Test
void create() {
Attributes expectedAttributes =
Attributes.builder()
.put("service.name", "my-service")
.put("strKey", "val")
.put("longKey", 1L)
.put("intKey", 2)
.put("doubleKey", 1.0d)
.put("floatKey", 2.0f)
.put("boolKey", true)
.put("strArrKey", "val1", "val2")
.put("longArrKey", 1L, 2L)
.put("intArrKey", 1, 2)
.put("doubleArrKey", 1.0d, 2.0d)
.put("floatArrKey", 1.0f, 2.0f)
.put("boolArrKey", true, false)
.build();
assertThat(
AttributeListFactory.getInstance()
.create(
Arrays.asList(
new AttributeNameValueModel()
.withName("service.name")
.withValue("my-service"),
new AttributeNameValueModel()
.withName("strKey")
.withValue("val")
.withType(AttributeNameValueModel.Type.STRING),
new AttributeNameValueModel()
.withName("longKey")
.withValue(1L)
.withType(AttributeNameValueModel.Type.INT),
new AttributeNameValueModel()
.withName("intKey")
.withValue(2)
.withType(AttributeNameValueModel.Type.INT),
new AttributeNameValueModel()
.withName("doubleKey")
.withValue(1.0d)
.withType(AttributeNameValueModel.Type.DOUBLE),
new AttributeNameValueModel()
.withName("floatKey")
.withValue(2.0f)
.withType(AttributeNameValueModel.Type.DOUBLE),
new AttributeNameValueModel()
.withName("boolKey")
.withValue(true)
.withType(AttributeNameValueModel.Type.BOOL),
new AttributeNameValueModel()
.withName("strArrKey")
.withValue(Arrays.asList("val1", "val2"))
.withType(AttributeNameValueModel.Type.STRING_ARRAY),
new AttributeNameValueModel()
.withName("longArrKey")
.withValue(Arrays.asList(1L, 2L))
.withType(AttributeNameValueModel.Type.INT_ARRAY),
new AttributeNameValueModel()
.withName("intArrKey")
.withValue(Arrays.asList(1, 2))
.withType(AttributeNameValueModel.Type.INT_ARRAY),
new AttributeNameValueModel()
.withName("doubleArrKey")
.withValue(Arrays.asList(1.0d, 2.0d))
.withType(AttributeNameValueModel.Type.DOUBLE_ARRAY),
new AttributeNameValueModel()
.withName("floatArrKey")
.withValue(Arrays.asList(1.0f, 2.0f))
.withType(AttributeNameValueModel.Type.DOUBLE_ARRAY),
new AttributeNameValueModel()
.withName("boolArrKey")
.withValue(Arrays.asList(true, false))
.withType(AttributeNameValueModel.Type.BOOL_ARRAY)),
mock(SpiHelper.class),
Collections.emptyList()))
.isEqualTo(expectedAttributes);
}
}

View File

@ -1,91 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributesModel;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class AttributesFactoryTest {
@ParameterizedTest
@MethodSource("invalidAttributes")
void create_InvalidAttributes(AttributesModel model, String expectedMessage) {
assertThatThrownBy(
() ->
AttributesFactory.getInstance()
.create(model, mock(SpiHelper.class), Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining(expectedMessage);
}
private static Stream<Arguments> invalidAttributes() {
return Stream.of(
Arguments.of(
new AttributesModel().withAdditionalProperty("key", null),
"Error processing attribute with key \"key\": unexpected null value"),
Arguments.of(
new AttributesModel().withAdditionalProperty("key", new Object()),
"Error processing attribute with key \"key\": unrecognized value type java.lang.Object"),
Arguments.of(
new AttributesModel().withAdditionalProperty("key", Arrays.asList(1L, 1)),
"Error processing attribute with key \"key\": expected value entries to be of type class java.lang.Long but found entry with type class java.lang.Integer"),
Arguments.of(
new AttributesModel().withAdditionalProperty("key", Arrays.asList(1L, null)),
"Error processing attribute with key \"key\": unexpected null element in value"));
}
@Test
void create() {
assertThat(
AttributesFactory.getInstance()
.create(
new AttributesModel()
.withServiceName("my-service")
.withAdditionalProperty("strKey", "val")
.withAdditionalProperty("longKey", 1L)
.withAdditionalProperty("intKey", 2)
.withAdditionalProperty("doubleKey", 1.0d)
.withAdditionalProperty("floatKey", 2.0f)
.withAdditionalProperty("boolKey", true)
.withAdditionalProperty("strArrKey", Arrays.asList("val1", "val2"))
.withAdditionalProperty("longArrKey", Arrays.asList(1L, 2L))
.withAdditionalProperty("intArrKey", Arrays.asList(1, 2))
.withAdditionalProperty("doubleArrKey", Arrays.asList(1.0d, 2.0d))
.withAdditionalProperty("floatArrKey", Arrays.asList(1.0f, 2.0f))
.withAdditionalProperty("boolArrKey", Arrays.asList(true, false))
.withAdditionalProperty("emptyArrKey", Collections.emptyList()),
mock(SpiHelper.class),
Collections.emptyList()))
.isEqualTo(
io.opentelemetry.api.common.Attributes.builder()
.put("service.name", "my-service")
.put("strKey", "val")
.put("longKey", 1L)
.put("intKey", 2)
.put("doubleKey", 1.0d)
.put("floatKey", 2.0f)
.put("boolKey", true)
.put("strArrKey", "val1", "val2")
.put("longArrKey", 1L, 2L)
.put("intArrKey", 1, 2)
.put("doubleArrKey", 1.0d, 2.0d)
.put("floatArrKey", 1.0f, 2.0f)
.put("boolArrKey", true, false)
.build());
}
}

View File

@ -86,10 +86,7 @@ class FileConfigurationCreateTest {
"client_key: .*\n", "client_key: " + clientKeyPath + System.lineSeparator())
.replaceAll(
"client_certificate: .*\n",
"client_certificate: " + clientCertificatePath + System.lineSeparator())
// TODO: remove once ComponentProvider SPI implemented in
// https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/aws-xray-propagator
.replaceAll("xray,", "");
"client_certificate: " + clientCertificatePath + System.lineSeparator());
InputStream is =
new ByteArrayInputStream(rewrittenExampleContent.getBytes(StandardCharsets.UTF_8));

View File

@ -13,30 +13,45 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Aggreg
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOffModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ClientModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorAttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorsModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HeadersModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GeneralInstrumentationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LanguageSpecificInstrumentationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricProducerModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpencensusModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ParentBasedModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeerModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PrometheusModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PropagatorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SelectorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ServerModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ServiceMappingModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel;
@ -83,7 +98,51 @@ class FileConfigurationParseTest {
// General config
ResourceModel resource =
new ResourceModel()
.withAttributes(new AttributesModel().withServiceName("unknown_service"));
.withAttributes(
Arrays.asList(
new AttributeNameValueModel()
.withName("service.name")
.withValue("unknown_service"),
new AttributeNameValueModel()
.withName("string_key")
.withValue("value")
.withType(AttributeNameValueModel.Type.STRING),
new AttributeNameValueModel()
.withName("bool_key")
.withValue(true)
.withType(AttributeNameValueModel.Type.BOOL),
new AttributeNameValueModel()
.withName("int_key")
.withValue(1)
.withType(AttributeNameValueModel.Type.INT),
new AttributeNameValueModel()
.withName("double_key")
.withValue(1.1)
.withType(AttributeNameValueModel.Type.DOUBLE),
new AttributeNameValueModel()
.withName("string_array_key")
.withValue(Arrays.asList("value1", "value2"))
.withType(AttributeNameValueModel.Type.STRING_ARRAY),
new AttributeNameValueModel()
.withName("bool_array_key")
.withValue(Arrays.asList(true, false))
.withType(AttributeNameValueModel.Type.BOOL_ARRAY),
new AttributeNameValueModel()
.withName("int_array_key")
.withValue(Arrays.asList(1, 2))
.withType(AttributeNameValueModel.Type.INT_ARRAY),
new AttributeNameValueModel()
.withName("double_array_key")
.withValue(Arrays.asList(1.1, 2.2))
.withType(AttributeNameValueModel.Type.DOUBLE_ARRAY)))
.withAttributesList("service.namespace=my-namespace,service.version=1.0.0")
.withDetectors(
new DetectorsModel()
.withAttributes(
new DetectorAttributesModel()
.withIncluded(Collections.singletonList("process.*"))
.withExcluded(Collections.singletonList("process.command_args"))))
.withSchemaUrl("https://opentelemetry.io/schemas/1.16.0");
expected.withResource(resource);
AttributeLimitsModel attributeLimits =
@ -138,15 +197,19 @@ class FileConfigurationParseTest {
.withOtlp(
new OtlpModel()
.withProtocol("http/protobuf")
.withEndpoint("http://localhost:4318")
.withEndpoint("http://localhost:4318/v1/traces")
.withCertificate("/app/cert.pem")
.withClientKey("/app/cert.pem")
.withClientCertificate("/app/cert.pem")
.withHeaders(
new HeadersModel()
.withAdditionalProperty("api-key", "1234"))
Collections.singletonList(
new NameStringValuePairModel()
.withName("api-key")
.withValue("1234")))
.withHeadersList("api-key=1234")
.withCompression("gzip")
.withTimeout(10_000))));
.withTimeout(10_000)
.withInsecure(false))));
SpanProcessorModel spanProcessor2 =
new SpanProcessorModel()
.withBatch(
@ -174,7 +237,7 @@ class FileConfigurationParseTest {
new LogRecordLimitsModel().withAttributeValueLengthLimit(4096).withAttributeCountLimit(128);
loggerProvider.withLimits(logRecordLimits);
LogRecordProcessorModel logRecordProcessor =
LogRecordProcessorModel logRecordProcessor1 =
new LogRecordProcessorModel()
.withBatch(
new BatchLogRecordProcessorModel()
@ -187,16 +250,25 @@ class FileConfigurationParseTest {
.withOtlp(
new OtlpModel()
.withProtocol("http/protobuf")
.withEndpoint("http://localhost:4318")
.withEndpoint("http://localhost:4318/v1/logs")
.withCertificate("/app/cert.pem")
.withClientKey("/app/cert.pem")
.withClientCertificate("/app/cert.pem")
.withHeaders(
new HeadersModel()
.withAdditionalProperty("api-key", "1234"))
Collections.singletonList(
new NameStringValuePairModel()
.withName("api-key")
.withValue("1234")))
.withHeadersList("api-key=1234")
.withCompression("gzip")
.withTimeout(10_000))));
loggerProvider.withProcessors(Collections.singletonList(logRecordProcessor));
.withTimeout(10_000)
.withInsecure(false))));
LogRecordProcessorModel logRecordProcessor2 =
new LogRecordProcessorModel()
.withSimple(
new SimpleLogRecordProcessorModel()
.withExporter(new LogRecordExporterModel().withConsole(new ConsoleModel())));
loggerProvider.withProcessors(Arrays.asList(logRecordProcessor1, logRecordProcessor2));
expected.withLoggerProvider(loggerProvider);
// end LoggerProvider config
@ -209,9 +281,22 @@ class FileConfigurationParseTest {
.withPull(
new PullMetricReaderModel()
.withExporter(
new MetricExporterModel()
new PullMetricExporterModel()
.withPrometheus(
new PrometheusModel().withHost("localhost").withPort(9464))));
new PrometheusModel()
.withHost("localhost")
.withPort(9464)
.withWithoutUnits(false)
.withWithoutTypeSuffix(false)
.withWithoutScopeInfo(false)
.withWithResourceConstantLabels(
new IncludeExcludeModel()
.withIncluded(Collections.singletonList("service*"))
.withExcluded(
Collections.singletonList("service.attr1"))))))
.withProducers(
Collections.singletonList(
new MetricProducerModel().withOpencensus(new OpencensusModel())));
MetricReaderModel metricReader2 =
new MetricReaderModel()
.withPeriodic(
@ -219,28 +304,36 @@ class FileConfigurationParseTest {
.withInterval(5_000)
.withTimeout(30_000)
.withExporter(
new MetricExporterModel()
new PushMetricExporterModel()
.withOtlp(
new OtlpMetricModel()
.withProtocol("http/protobuf")
.withEndpoint("http://localhost:4318")
.withEndpoint("http://localhost:4318/v1/metrics")
.withCertificate("/app/cert.pem")
.withClientKey("/app/cert.pem")
.withClientCertificate("/app/cert.pem")
.withHeaders(
new HeadersModel()
.withAdditionalProperty("api-key", "1234"))
Collections.singletonList(
new NameStringValuePairModel()
.withName("api-key")
.withValue("1234")))
.withHeadersList("api-key=1234")
.withCompression("gzip")
.withTimeout(10_000)
.withInsecure(false)
.withTemporalityPreference("delta")
.withDefaultHistogramAggregation(
OtlpMetricModel.DefaultHistogramAggregation
.BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM))));
.BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM))))
.withProducers(
Collections.singletonList(
new MetricProducerModel()
.withAdditionalProperty("prometheus", Collections.emptyMap())));
MetricReaderModel metricReader3 =
new MetricReaderModel()
.withPeriodic(
new PeriodicMetricReaderModel()
.withExporter(new MetricExporterModel().withConsole(new ConsoleModel())));
.withExporter(new PushMetricExporterModel().withConsole(new ConsoleModel())));
meterProvider.withReaders(Arrays.asList(metricReader1, metricReader2, metricReader3));
ViewModel view =
@ -266,12 +359,91 @@ class FileConfigurationParseTest {
0.0, 5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, 500.0,
750.0, 1000.0, 2500.0, 5000.0, 7500.0, 10000.0))
.withRecordMinMax(true)))
.withAttributeKeys(Arrays.asList("key1", "key2")));
.withAttributeKeys(
new IncludeExcludeModel()
.withIncluded(Arrays.asList("key1", "key2"))
.withExcluded(Collections.singletonList("key3"))));
meterProvider.withViews(Collections.singletonList(view));
expected.withMeterProvider(meterProvider);
// end MeterProvider config
// start instrumentation config
InstrumentationModel instrumentation =
new InstrumentationModel()
.withGeneral(
new GeneralInstrumentationModel()
.withPeer(
new PeerModel()
.withServiceMapping(
Arrays.asList(
new ServiceMappingModel()
.withPeer("1.2.3.4")
.withService("FooService"),
new ServiceMappingModel()
.withPeer("2.3.4.5")
.withService("BarService"))))
.withHttp(
new HttpModel()
.withClient(
new ClientModel()
.withRequestCapturedHeaders(
Arrays.asList("Content-Type", "Accept"))
.withResponseCapturedHeaders(
Arrays.asList("Content-Type", "Content-Encoding")))
.withServer(
new ServerModel()
.withRequestCapturedHeaders(
Arrays.asList("Content-Type", "Accept"))
.withResponseCapturedHeaders(
Arrays.asList("Content-Type", "Content-Encoding")))))
.withCpp(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withDotnet(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withErlang(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withGo(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withJava(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withJs(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withPhp(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withPython(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withRuby(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withRust(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")))
.withSwift(
new LanguageSpecificInstrumentationModel()
.withAdditionalProperty(
"example", Collections.singletonMap("property", "value")));
expected.withInstrumentation(instrumentation);
// end instrumentation config
try (FileInputStream configExampleFile =
new FileInputStream(System.getenv("CONFIG_EXAMPLE_DIR") + "/kitchen-sink.yaml")) {
OpenTelemetryConfigurationModel config = FileConfiguration.parse(configExampleFile);
@ -293,7 +465,7 @@ class FileConfigurationParseTest {
LoggerProviderModel configLoggerProvider = config.getLoggerProvider();
assertThat(configLoggerProvider.getLimits()).isEqualTo(logRecordLimits);
assertThat(configLoggerProvider.getProcessors())
.isEqualTo(Collections.singletonList(logRecordProcessor));
.isEqualTo(Arrays.asList(logRecordProcessor1, logRecordProcessor2));
// MeterProvider config
MeterProviderModel configMeterProvider = config.getMeterProvider();
@ -301,6 +473,10 @@ class FileConfigurationParseTest {
.isEqualTo(Arrays.asList(metricReader1, metricReader2, metricReader3));
assertThat(configMeterProvider.getViews()).isEqualTo(Collections.singletonList(view));
// Instrumentation config
InstrumentationModel configInstrumentation = config.getInstrumentation();
assertThat(configInstrumentation).isEqualTo(instrumentation);
// All configuration
assertThat(config).isEqualTo(expected);
}
@ -446,6 +622,15 @@ class FileConfigurationParseTest {
Arguments.of(
"key1: ${STR_1} value1\n" + "key2: value2\n",
mapOf(entry("key1", "value1 value1"), entry("key2", "value2"))),
// Default cases
Arguments.of("key1: ${NOT_SET:-value1}\n", mapOf(entry("key1", "value1"))),
Arguments.of("key1: ${NOT_SET:-true}\n", mapOf(entry("key1", true))),
Arguments.of("key1: ${NOT_SET:-1}\n", mapOf(entry("key1", 1))),
Arguments.of("key1: ${NOT_SET:-1.1}\n", mapOf(entry("key1", 1.1))),
Arguments.of("key1: ${NOT_SET:-0xdeadbeef}\n", mapOf(entry("key1", 3735928559L))),
Arguments.of(
"key1: ${NOT_SET:-value1} value2\n" + "key2: value2\n",
mapOf(entry("key1", "value1 value2"), entry("key2", "value2"))),
// Multiple environment variables referenced
Arguments.of("key1: ${STR_1}${STR_2}\n", mapOf(entry("key1", "value1value2"))),
Arguments.of("key1: ${STR_1} ${STR_2}\n", mapOf(entry("key1", "value1 value2"))),

View File

@ -13,7 +13,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
@ -22,8 +21,8 @@ import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HeadersModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import java.io.Closeable;
@ -32,6 +31,7 @@ import java.nio.file.Path;
import java.security.cert.CertificateEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -127,11 +127,15 @@ class LogRecordExporterFactoryTest {
.withOtlp(
new OtlpModel()
.withProtocol("http/protobuf")
.withEndpoint("http://example:4318")
.withEndpoint("http://example:4318/v1/logs")
.withHeaders(
new HeadersModel()
.withAdditionalProperty("key1", "value1")
.withAdditionalProperty("key2", "value2"))
Arrays.asList(
new NameStringValuePairModel()
.withName("key1")
.withValue("value1"),
new NameStringValuePairModel()
.withName("key2")
.withValue("value2")))
.withCompression("gzip")
.withTimeout(15_000)
.withCertificate(certificatePath)
@ -150,12 +154,19 @@ class LogRecordExporterFactoryTest {
.loadComponent(eq(LogRecordExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isEqualTo("http/protobuf");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318");
StructuredConfigProperties headers = configProperties.getStructured("headers");
assertThat(headers).isNotNull();
assertThat(headers.getPropertyKeys()).isEqualTo(ImmutableSet.of("key1", "key2"));
assertThat(headers.getString("key1")).isEqualTo("value1");
assertThat(headers.getString("key2")).isEqualTo("value2");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/logs");
List<StructuredConfigProperties> headers = configProperties.getStructuredList("headers");
assertThat(headers)
.isNotNull()
.satisfiesExactly(
header -> {
assertThat(header.getString("name")).isEqualTo("key1");
assertThat(header.getString("value")).isEqualTo("value1");
},
header -> {
assertThat(header.getString("name")).isEqualTo("key2");
assertThat(header.getString("value")).isEqualTo("value2");
});
assertThat(configProperties.getString("compression")).isEqualTo("gzip");
assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis());
assertThat(configProperties.getString("certificate")).isEqualTo(certificatePath);

View File

@ -11,10 +11,10 @@ import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SelectorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.StreamModel;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
@ -75,7 +75,7 @@ class MeterProviderFactoryTest {
.withPeriodic(
new PeriodicMetricReaderModel()
.withExporter(
new MetricExporterModel()
new PushMetricExporterModel()
.withOtlp(new OtlpMetricModel())))))
.withViews(
Collections.singletonList(

View File

@ -13,7 +13,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
@ -24,9 +23,8 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HeadersModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PrometheusModel;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
@ -38,6 +36,7 @@ import java.nio.file.Path;
import java.security.cert.CertificateEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -73,7 +72,7 @@ class MetricExporterFactoryTest {
MetricExporterFactory.getInstance()
.create(
new io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model
.MetricExporterModel()
.PushMetricExporterModel()
.withOtlp(new OtlpMetricModel()),
spiHelper,
closeables);
@ -131,15 +130,19 @@ class MetricExporterFactoryTest {
MetricExporterFactory.getInstance()
.create(
new io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model
.MetricExporterModel()
.PushMetricExporterModel()
.withOtlp(
new OtlpMetricModel()
.withProtocol("http/protobuf")
.withEndpoint("http://example:4318")
.withEndpoint("http://example:4318/v1/metrics")
.withHeaders(
new HeadersModel()
.withAdditionalProperty("key1", "value1")
.withAdditionalProperty("key2", "value2"))
Arrays.asList(
new NameStringValuePairModel()
.withName("key1")
.withValue("value1"),
new NameStringValuePairModel()
.withName("key2")
.withValue("value2")))
.withCompression("gzip")
.withTimeout(15_000)
.withCertificate(certificatePath)
@ -161,12 +164,19 @@ class MetricExporterFactoryTest {
verify(spiHelper).loadComponent(eq(MetricExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isEqualTo("http/protobuf");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318");
StructuredConfigProperties headers = configProperties.getStructured("headers");
assertThat(headers).isNotNull();
assertThat(headers.getPropertyKeys()).isEqualTo(ImmutableSet.of("key1", "key2"));
assertThat(headers.getString("key1")).isEqualTo("value1");
assertThat(headers.getString("key2")).isEqualTo("value2");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/metrics");
List<StructuredConfigProperties> headers = configProperties.getStructuredList("headers");
assertThat(headers)
.isNotNull()
.satisfiesExactly(
header -> {
assertThat(header.getString("name")).isEqualTo("key1");
assertThat(header.getString("value")).isEqualTo("value1");
},
header -> {
assertThat(header.getString("name")).isEqualTo("key2");
assertThat(header.getString("value")).isEqualTo("value2");
});
assertThat(configProperties.getString("compression")).isEqualTo("gzip");
assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis());
assertThat(configProperties.getString("certificate")).isEqualTo(certificatePath);
@ -188,7 +198,7 @@ class MetricExporterFactoryTest {
MetricExporterFactory.getInstance()
.create(
new io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model
.MetricExporterModel()
.PushMetricExporterModel()
.withConsole(new ConsoleModel()),
spiHelper,
closeables);
@ -198,24 +208,6 @@ class MetricExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
}
@Test
void create_PrometheusExporter() {
List<Closeable> closeables = new ArrayList<>();
assertThatThrownBy(
() ->
MetricExporterFactory.getInstance()
.create(
new io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model
.MetricExporterModel()
.withPrometheus(new PrometheusModel()),
spiHelper,
closeables))
.isInstanceOf(ConfigurationException.class)
.hasMessage("prometheus exporter not supported in this context");
cleanup.addCloseables(closeables);
}
@Test
void create_SpiExporter_Unknown() {
assertThatThrownBy(
@ -223,7 +215,7 @@ class MetricExporterFactoryTest {
MetricExporterFactory.getInstance()
.create(
new io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model
.MetricExporterModel()
.PushMetricExporterModel()
.withAdditionalProperty(
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
@ -239,7 +231,7 @@ class MetricExporterFactoryTest {
MetricExporterFactory.getInstance()
.create(
new io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model
.MetricExporterModel()
.PushMetricExporterModel()
.withAdditionalProperty("test", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>());

View File

@ -17,12 +17,13 @@ import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PrometheusModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import java.io.Closeable;
import java.io.IOException;
import java.net.ServerSocket;
@ -72,7 +73,7 @@ class MetricReaderFactoryTest {
.withPeriodic(
new PeriodicMetricReaderModel()
.withExporter(
new MetricExporterModel().withOtlp(new OtlpMetricModel()))),
new PushMetricExporterModel().withOtlp(new OtlpMetricModel()))),
spiHelper,
closeables);
cleanup.addCloseable(reader);
@ -97,7 +98,8 @@ class MetricReaderFactoryTest {
new MetricReaderModel()
.withPeriodic(
new PeriodicMetricReaderModel()
.withExporter(new MetricExporterModel().withOtlp(new OtlpMetricModel()))
.withExporter(
new PushMetricExporterModel().withOtlp(new OtlpMetricModel()))
.withInterval(1)),
spiHelper,
closeables);
@ -123,7 +125,7 @@ class MetricReaderFactoryTest {
.withPull(
new PullMetricReaderModel()
.withExporter(
new MetricExporterModel()
new PullMetricExporterModel()
.withPrometheus(new PrometheusModel().withPort(port)))),
spiHelper,
closeables);
@ -153,7 +155,7 @@ class MetricReaderFactoryTest {
.withPull(
new PullMetricReaderModel()
.withExporter(
new MetricExporterModel()
new PullMetricExporterModel()
.withPrometheus(
new PrometheusModel()
.withHost("localhost")
@ -187,21 +189,7 @@ class MetricReaderFactoryTest {
new MetricReaderModel()
.withPull(
new PullMetricReaderModel()
.withExporter(new MetricExporterModel())),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.hasMessage("prometheus is the only currently supported pull reader");
assertThatThrownBy(
() ->
MetricReaderFactory.getInstance()
.create(
new MetricReaderModel()
.withPull(
new PullMetricReaderModel()
.withExporter(
new MetricExporterModel().withOtlp(new OtlpMetricModel()))),
.withExporter(new PullMetricExporterModel())),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)

View File

@ -24,7 +24,7 @@ import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
@ -32,13 +32,13 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRec
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PropagatorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SelectorModel;
@ -222,9 +222,13 @@ class OpenTelemetryConfigurationFactoryTest {
.withResource(
new ResourceModel()
.withAttributes(
new AttributesModel()
.withServiceName("my-service")
.withAdditionalProperty("key", "val")))
Arrays.asList(
new AttributeNameValueModel()
.withName("service.name")
.withValue("my-service"),
new AttributeNameValueModel()
.withName("key")
.withValue("val"))))
.withLoggerProvider(
new LoggerProviderModel()
.withLimits(
@ -267,7 +271,7 @@ class OpenTelemetryConfigurationFactoryTest {
.withPeriodic(
new PeriodicMetricReaderModel()
.withExporter(
new MetricExporterModel()
new PushMetricExporterModel()
.withOtlp(new OtlpMetricModel())))))
.withViews(
Collections.singletonList(

View File

@ -9,11 +9,20 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.asser
import static org.mockito.Mockito.spy;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorAttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorsModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel;
import io.opentelemetry.sdk.resources.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class ResourceFactoryTest {
@ -27,11 +36,14 @@ class ResourceFactoryTest {
.create(
new ResourceModel()
.withAttributes(
new AttributesModel()
.withServiceName("my-service")
.withAdditionalProperty("key", "val")
// Should override shape attribute from ResourceComponentProvider
.withAdditionalProperty("shape", "circle")),
Arrays.asList(
new AttributeNameValueModel()
.withName("service.name")
.withValue("my-service"),
new AttributeNameValueModel().withName("key").withValue("val"),
new AttributeNameValueModel()
.withName("shape")
.withValue("circle"))),
spiHelper,
Collections.emptyList()))
.isEqualTo(
@ -46,4 +58,86 @@ class ResourceFactoryTest {
.put("order", "second")
.build());
}
@ParameterizedTest
@MethodSource("createWithDetectorsArgs")
void createWithDetectors(
@Nullable List<String> included, @Nullable List<String> excluded, Resource expectedResource) {
ResourceModel resourceModel =
new ResourceModel()
.withDetectors(
new DetectorsModel()
.withAttributes(
new DetectorAttributesModel()
.withIncluded(included)
.withExcluded(excluded)));
Resource resource =
ResourceFactory.getInstance().create(resourceModel, spiHelper, Collections.emptyList());
assertThat(resource).isEqualTo(expectedResource);
}
private static Stream<Arguments> createWithDetectorsArgs() {
return Stream.of(
Arguments.of(
null,
null,
Resource.getDefault().toBuilder()
.put("color", "red")
.put("shape", "square")
.put("order", "second")
.build()),
Arguments.of(
Collections.singletonList("color"),
null,
Resource.getDefault().toBuilder().put("color", "red").build()),
Arguments.of(
Arrays.asList("color", "shape"),
null,
Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build()),
Arguments.of(
null,
Collections.singletonList("color"),
Resource.getDefault().toBuilder()
.put("shape", "square")
.put("order", "second")
.build()),
Arguments.of(
null,
Arrays.asList("color", "shape"),
Resource.getDefault().toBuilder().put("order", "second").build()),
Arguments.of(
Collections.singletonList("color"),
Collections.singletonList("color"),
Resource.getDefault().toBuilder().build()),
Arguments.of(
Arrays.asList("color", "shape"),
Collections.singletonList("color"),
Resource.getDefault().toBuilder().put("shape", "square").build()),
Arguments.of(
Collections.singletonList("c*"),
null,
Resource.getDefault().toBuilder().put("color", "red").build()),
Arguments.of(
Collections.singletonList("c?lor"),
null,
Resource.getDefault().toBuilder().put("color", "red").build()),
Arguments.of(
null,
Collections.singletonList("c*"),
Resource.getDefault().toBuilder()
.put("shape", "square")
.put("order", "second")
.build()),
Arguments.of(
null,
Collections.singletonList("c?lor"),
Resource.getDefault().toBuilder()
.put("shape", "square")
.put("order", "second")
.build()),
Arguments.of(
Collections.singletonList("*o*"),
Collections.singletonList("order"),
Resource.getDefault().toBuilder().put("color", "red").build()));
}
}

View File

@ -13,7 +13,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
@ -25,7 +24,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HeadersModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ZipkinModel;
import io.opentelemetry.sdk.trace.export.SpanExporter;
@ -35,6 +34,7 @@ import java.nio.file.Path;
import java.security.cert.CertificateEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -126,11 +126,15 @@ class SpanExporterFactoryTest {
.withOtlp(
new OtlpModel()
.withProtocol("http/protobuf")
.withEndpoint("http://example:4318")
.withEndpoint("http://example:4318/v1/traces")
.withHeaders(
new HeadersModel()
.withAdditionalProperty("key1", "value1")
.withAdditionalProperty("key2", "value2"))
Arrays.asList(
new NameStringValuePairModel()
.withName("key1")
.withValue("value1"),
new NameStringValuePairModel()
.withName("key2")
.withValue("value2")))
.withCompression("gzip")
.withTimeout(15_000)
.withCertificate(certificatePath)
@ -148,12 +152,19 @@ class SpanExporterFactoryTest {
verify(spiHelper).loadComponent(eq(SpanExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isEqualTo("http/protobuf");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318");
StructuredConfigProperties headers = configProperties.getStructured("headers");
assertThat(headers).isNotNull();
assertThat(headers.getPropertyKeys()).isEqualTo(ImmutableSet.of("key1", "key2"));
assertThat(headers.getString("key1")).isEqualTo("value1");
assertThat(headers.getString("key2")).isEqualTo("value2");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/traces");
List<StructuredConfigProperties> headers = configProperties.getStructuredList("headers");
assertThat(headers)
.isNotNull()
.satisfiesExactly(
header -> {
assertThat(header.getString("name")).isEqualTo("key1");
assertThat(header.getString("value")).isEqualTo("value1");
},
header -> {
assertThat(header.getString("name")).isEqualTo("key2");
assertThat(header.getString("value")).isEqualTo("value2");
});
assertThat(configProperties.getString("compression")).isEqualTo("gzip");
assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis());
assertThat(configProperties.getString("certificate")).isEqualTo(certificatePath);

View File

@ -11,6 +11,7 @@ import static org.mockito.Mockito.mock;
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.ExplicitBucketHistogramModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.StreamModel;
import io.opentelemetry.sdk.metrics.View;
import java.util.Arrays;
@ -52,7 +53,8 @@ class ViewFactoryTest {
new StreamModel()
.withName("name")
.withDescription("description")
.withAttributeKeys(Arrays.asList("foo", "bar"))
.withAttributeKeys(
new IncludeExcludeModel().withIncluded(Arrays.asList("foo", "bar")))
.withAggregation(
new AggregationModel()
.withExplicitBucketHistogram(

View File

@ -26,7 +26,8 @@ class YamlStructuredConfigPropertiesTest {
+ "\n"
+ "resource:\n"
+ " attributes:\n"
+ " service.name: \"unknown_service\"\n"
+ " - name: service.name\n"
+ " value: \"unknown_service\"\n"
+ "\n"
+ "other:\n"
+ " str_key: str_value\n"
@ -70,9 +71,15 @@ class YamlStructuredConfigPropertiesTest {
assertThat(structuredConfigProps.getString("file_format")).isEqualTo("0.1");
StructuredConfigProperties resourceProps = structuredConfigProps.getStructured("resource");
assertThat(resourceProps).isNotNull();
StructuredConfigProperties resourceAttributesProps = resourceProps.getStructured("attributes");
assertThat(resourceAttributesProps).isNotNull();
assertThat(resourceAttributesProps.getString("service.name")).isEqualTo("unknown_service");
List<StructuredConfigProperties> resourceAttributesList =
resourceProps.getStructuredList("attributes");
assertThat(resourceAttributesList)
.isNotNull()
.satisfiesExactly(
attributeEntry -> {
assertThat(attributeEntry.getString("name")).isEqualTo("service.name");
assertThat(attributeEntry.getString("value")).isEqualTo("unknown_service");
});
}
@Test