diff --git a/instrumentation/resources/library/README.md b/instrumentation/resources/library/README.md index ca7a790ec2cc..883f40ce0626 100644 --- a/instrumentation/resources/library/README.md +++ b/instrumentation/resources/library/README.md @@ -11,6 +11,8 @@ Provider: `io.opentelemetry.instrumentation.resources.ContainerResource` Specification: +Included in [declarative config]. + Implemented attributes: - `container.id` @@ -21,6 +23,8 @@ Provider: `io.opentelemetry.instrumentation.resources.HostResource` Specification: +Included in [declarative config]. + Implemented attributes: - `host.name` @@ -30,6 +34,8 @@ Provider: `io.opentelemetry.instrumentation.resources.HostIdResourceProvider` Specification: +Included in [declarative config]. + Implemented attributes: - `host.id` @@ -40,6 +46,8 @@ Provider: `io.opentelemetry.instrumentation.resources.OsResource` Specification: +Included in [declarative config]. + Implemented attributes: - `os.type` @@ -51,6 +59,8 @@ Implementation: `io.opentelemetry.instrumentation.resources.ProcessResource` Specification: +Included in [declarative config]. + Implemented attributes: - `process.pid` @@ -63,6 +73,8 @@ Implementation: `io.opentelemetry.instrumentation.resources.ProcessRuntimeResour Specification: +Included in [declarative config]. + Implemented attributes: - `process.runtime.name` @@ -73,3 +85,5 @@ Implemented attributes: This package currently does not run on Android. It has been verified on OpenJDK and should work on other server JVM distributions but if you find any issues please let us know. + +[declarative config]: https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/configuration#declarative-configuration diff --git a/instrumentation/resources/library/build.gradle.kts b/instrumentation/resources/library/build.gradle.kts index cf3969d90d12..2c2ba58a3901 100644 --- a/instrumentation/resources/library/build.gradle.kts +++ b/instrumentation/resources/library/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") testCompileOnly("com.google.auto.service:auto-service-annotations") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("org.junit.jupiter:junit-jupiter-api") } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResource.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResource.java new file mode 100644 index 000000000000..5414166599b6 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResource.java @@ -0,0 +1,172 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +import io.opentelemetry.sdk.resources.Resource; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.logging.Logger; + +/** + * {@link ResourceProvider} for automatically configuring host.id according to the + * semantic conventions + */ +public final class HostIdResource { + + private static final Logger logger = Logger.getLogger(HostIdResource.class.getName()); + + // copied from HostIncubatingAttributes + static final AttributeKey HOST_ID = AttributeKey.stringKey("host.id"); + + public static final String REGISTRY_QUERY = + "reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid"; + + private static final HostIdResource INSTANCE = + new HostIdResource( + HostIdResource::getOsTypeSystemProperty, + HostIdResource::readMachineIdFile, + HostIdResource::queryWindowsRegistry); + + private final Supplier getOsType; + private final Function> machineIdReader; + private final Supplier> queryWindowsRegistry; + + // Visible for testing + HostIdResource( + Supplier getOsType, + Function> machineIdReader, + Supplier> queryWindowsRegistry) { + this.getOsType = getOsType; + this.machineIdReader = machineIdReader; + this.queryWindowsRegistry = queryWindowsRegistry; + } + + /** Returns a {@link Resource} containing the {@code host.id} resource attribute. */ + public static Resource get() { + return INSTANCE.createResource(); + } + + /** Returns a {@link Resource} containing the {@code host.id} resource attribute. */ + Resource createResource() { + if (runningWindows()) { + return readWindowsGuid(); + } + if (runningLinux()) { + return readLinuxMachineId(); + } + logger.log(FINE, "Unsupported OS type: {0}", getOsType.get()); + return Resource.empty(); + } + + private boolean runningLinux() { + return getOsType.get().toLowerCase(Locale.ROOT).equals("linux"); + } + + private boolean runningWindows() { + return getOsType.get().startsWith("Windows"); + } + + // see + // https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/SystemUtils.java + // for values + private static String getOsTypeSystemProperty() { + return System.getProperty("os.name", ""); + } + + private Resource readLinuxMachineId() { + Path path = FileSystems.getDefault().getPath("/etc/machine-id"); + List lines = machineIdReader.apply(path); + if (lines.isEmpty()) { + return Resource.empty(); + } + return Resource.create(Attributes.of(HOST_ID, lines.get(0))); + } + + private static List readMachineIdFile(Path path) { + try { + List lines = Files.readAllLines(path); + if (lines.isEmpty()) { + logger.fine("Failed to read /etc/machine-id: empty file"); + } + return lines; + } catch (IOException e) { + logger.log(FINE, "Failed to read /etc/machine-id", e); + return Collections.emptyList(); + } + } + + private Resource readWindowsGuid() { + List lines = queryWindowsRegistry.get(); + + for (String line : lines) { + if (line.contains("MachineGuid")) { + String[] parts = line.trim().split("\\s+"); + if (parts.length == 3) { + return Resource.create(Attributes.of(HOST_ID, parts[2])); + } + } + } + logger.fine("Failed to read Windows registry: No MachineGuid found in output: " + lines); + return Resource.empty(); + } + + private static List queryWindowsRegistry() { + try { + ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/c", REGISTRY_QUERY); + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + + List output = getProcessOutput(process); + int exitedValue = process.waitFor(); + if (exitedValue != 0) { + logger.fine( + "Failed to read Windows registry. Exit code: " + + exitedValue + + " Output: " + + String.join("\n", output)); + + return Collections.emptyList(); + } + + return output; + } catch (IOException | InterruptedException e) { + logger.log(FINE, "Failed to read Windows registry", e); + return Collections.emptyList(); + } + } + + private static List getProcessOutput(Process process) throws IOException { + List result = new ArrayList<>(); + + try (BufferedReader processOutputReader = + new BufferedReader( + new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { + String readLine; + + while ((readLine = processOutputReader.readLine()) != null) { + result.add(readLine); + } + } + return result; + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResourceProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResourceProvider.java index 04766d899835..f19cb5185f00 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResourceProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/HostIdResourceProvider.java @@ -5,28 +5,12 @@ package io.opentelemetry.instrumentation.resources; -import static java.util.logging.Level.FINE; +import static io.opentelemetry.instrumentation.resources.HostIdResource.HOST_ID; -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.ConditionalResourceProvider; import io.opentelemetry.sdk.resources.Resource; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.logging.Logger; /** * {@link ResourceProvider} for automatically configuring host.id according to HOST_ID = AttributeKey.stringKey("host.id"); - - public static final String REGISTRY_QUERY = - "reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid"; - - private final Supplier getOsType; - - private final Function> machineIdReader; - - private final Supplier> queryWindowsRegistry; - - public HostIdResourceProvider() { - this( - HostIdResourceProvider::getOsTypeSystemProperty, - HostIdResourceProvider::readMachineIdFile, - HostIdResourceProvider::queryWindowsRegistry); - } - - // Visible for testing - - HostIdResourceProvider( - Supplier getOsType, - Function> machineIdReader, - Supplier> queryWindowsRegistry) { - this.getOsType = getOsType; - this.machineIdReader = machineIdReader; - this.queryWindowsRegistry = queryWindowsRegistry; - } - @Override public Resource createResource(ConfigProperties config) { - if (runningWindows()) { - return readWindowsGuid(); - } - if (runningLinux()) { - return readLinuxMachineId(); - } - logger.log(FINE, "Unsupported OS type: {0}", getOsType.get()); - return Resource.empty(); - } - - private boolean runningLinux() { - return getOsType.get().toLowerCase(Locale.ROOT).equals("linux"); - } - - private boolean runningWindows() { - return getOsType.get().startsWith("Windows"); - } - - // see - // https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/SystemUtils.java - // for values - private static String getOsTypeSystemProperty() { - return System.getProperty("os.name", ""); - } - - private Resource readLinuxMachineId() { - Path path = FileSystems.getDefault().getPath("/etc/machine-id"); - List lines = machineIdReader.apply(path); - if (lines.isEmpty()) { - return Resource.empty(); - } - return Resource.create(Attributes.of(HOST_ID, lines.get(0))); - } - - private static List readMachineIdFile(Path path) { - try { - List lines = Files.readAllLines(path); - if (lines.isEmpty()) { - logger.fine("Failed to read /etc/machine-id: empty file"); - } - return lines; - } catch (IOException e) { - logger.log(FINE, "Failed to read /etc/machine-id", e); - return Collections.emptyList(); - } - } - - private Resource readWindowsGuid() { - List lines = queryWindowsRegistry.get(); - - for (String line : lines) { - if (line.contains("MachineGuid")) { - String[] parts = line.trim().split("\\s+"); - if (parts.length == 3) { - return Resource.create(Attributes.of(HOST_ID, parts[2])); - } - } - } - logger.fine("Failed to read Windows registry: No MachineGuid found in output: " + lines); - return Resource.empty(); - } - - private static List queryWindowsRegistry() { - try { - ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/c", REGISTRY_QUERY); - processBuilder.redirectErrorStream(true); - Process process = processBuilder.start(); - - List output = getProcessOutput(process); - int exitedValue = process.waitFor(); - if (exitedValue != 0) { - logger.fine( - "Failed to read Windows registry. Exit code: " - + exitedValue - + " Output: " - + String.join("\n", output)); - - return Collections.emptyList(); - } - - return output; - } catch (IOException | InterruptedException e) { - logger.log(FINE, "Failed to read Windows registry", e); - return Collections.emptyList(); - } - } - - public static List getProcessOutput(Process process) throws IOException { - List result = new ArrayList<>(); - - try (BufferedReader processOutputReader = - new BufferedReader( - new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { - String readLine; - - while ((readLine = processOutputReader.readLine()) != null) { - result.add(readLine); - } - } - return result; + return HostResource.get(); } @Override diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java new file mode 100644 index 000000000000..00b3ffb06686 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.ContainerResource; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config container resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class ContainerResourceComponentProvider extends ResourceComponentProvider { + public ContainerResourceComponentProvider() { + super(ContainerResource::get); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostIdResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostIdResourceComponentProvider.java new file mode 100644 index 000000000000..9432f52fac37 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostIdResourceComponentProvider.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.HostIdResource; +import io.opentelemetry.sdk.autoconfigure.spi.Ordered; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config host id resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class HostIdResourceComponentProvider extends ResourceComponentProvider implements Ordered { + public HostIdResourceComponentProvider() { + super(HostIdResource::get); + } + + @Override + public int order() { + // Run after cloud provider resource providers + return Integer.MAX_VALUE - 1; + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java new file mode 100644 index 000000000000..806ac10a7c52 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.HostResource; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config host resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class HostResourceComponentProvider extends ResourceComponentProvider { + public HostResourceComponentProvider() { + super(HostResource::get); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/OsResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/OsResourceComponentProvider.java new file mode 100644 index 000000000000..de7b78d656a8 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/OsResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.OsResource; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config os resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class OsResourceComponentProvider extends ResourceComponentProvider { + public OsResourceComponentProvider() { + super(OsResource::get); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java new file mode 100644 index 000000000000..273b4397e5f3 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.ProcessResource; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config process resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class ProcessResourceComponentProvider extends ResourceComponentProvider { + public ProcessResourceComponentProvider() { + super(ProcessResource::get); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessRuntimeResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessRuntimeResourceComponentProvider.java new file mode 100644 index 000000000000..8254ddeab359 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessRuntimeResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.ProcessRuntimeResource; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config process runtime resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class ProcessRuntimeResourceComponentProvider extends ResourceComponentProvider { + public ProcessRuntimeResourceComponentProvider() { + super(ProcessRuntimeResource::get); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java new file mode 100644 index 000000000000..677f4792a3f2 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; +import io.opentelemetry.sdk.resources.Resource; +import java.util.function.Supplier; + +/** Abstract class to simply {@link Resource} {@link ComponentProvider} implementations. */ +abstract class ResourceComponentProvider implements ComponentProvider { + + private final Supplier supplier; + + ResourceComponentProvider(Supplier supplier) { + this.supplier = supplier; + } + + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + // getName() is unused for Resource ComponentProviders + return "unused"; + } + + @Override + public Resource create(StructuredConfigProperties structuredConfigProperties) { + return supplier.get(); + } +} diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/HostIdResourceProviderTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/HostIdResourceTest.java similarity index 87% rename from instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/HostIdResourceProviderTest.java rename to instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/HostIdResourceTest.java index 2b88957b7b32..61f4f737834b 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/HostIdResourceProviderTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/HostIdResourceTest.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; -class HostIdResourceProviderTest { +class HostIdResourceTest { private static class LinuxTestCase { private final String name; @@ -63,10 +63,10 @@ Collection createResourceLinux() { DynamicTest.dynamicTest( testCase.name, () -> { - HostIdResourceProvider provider = - new HostIdResourceProvider(() -> "linux", testCase.pathReader, null); + HostIdResource hostIdResource = + new HostIdResource(() -> "linux", testCase.pathReader, null); - assertHostId(testCase.expectedValue, provider); + assertHostId(testCase.expectedValue, hostIdResource); })) .collect(Collectors.toList()); } @@ -87,18 +87,18 @@ Collection createResourceWindows() { DynamicTest.dynamicTest( testCase.name, () -> { - HostIdResourceProvider provider = - new HostIdResourceProvider( + HostIdResource hostIdResource = + new HostIdResource( () -> "Windows 95", null, testCase.queryWindowsRegistry); - assertHostId(testCase.expectedValue, provider); + assertHostId(testCase.expectedValue, hostIdResource); })) .collect(Collectors.toList()); } - private static void assertHostId(String expectedValue, HostIdResourceProvider provider) { + private static void assertHostId(String expectedValue, HostIdResource hostIdResource) { MapAssert, Object> that = - assertThat(provider.createResource(null).getAttributes().asMap()); + assertThat(hostIdResource.createResource().getAttributes().asMap()); if (expectedValue == null) { that.isEmpty(); diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/DeclarativeConfigTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/DeclarativeConfigTest.java new file mode 100644 index 000000000000..14b8aacc2aa1 --- /dev/null +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/DeclarativeConfigTest.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import static org.assertj.core.api.Assertions.as; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfiguration; +import io.opentelemetry.sdk.resources.Resource; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.stream.Collectors; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +class DeclarativeConfigTest { + + @Test + void endToEnd() { + String yaml = + "file_format: 0.1\n" + + "resource:\n" + + " attributes:\n" + + " service.name: my-service\n" + + "tracer_provider:\n"; + + OpenTelemetrySdk openTelemetrySdk = + FileConfiguration.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + assertThat(openTelemetrySdk.getSdkTracerProvider()) + .extracting("sharedState.resource", as(InstanceOfAssertFactories.type(Resource.class))) + .satisfies( + resource -> { + // From .resource.attributes + assertThat(resource.getAttribute(AttributeKey.stringKey("service.name"))) + .isEqualTo("my-service"); + + // From ComponentProvider SPI + Set attributeKeys = + resource.getAttributes().asMap().keySet().stream() + .map(AttributeKey::getKey) + .collect(Collectors.toSet()); + // ContainerResourceComponentProvider - no container attributes reliably provided + // HostIdResourceComponentProvider - host.id attribute not reliably provided + // HostResourceComponentProvider + assertThat(attributeKeys).contains("host.arch"); + assertThat(attributeKeys).contains("host.name"); + // OsResourceComponentProvider + assertThat(attributeKeys).contains("os.description"); + assertThat(attributeKeys).contains("os.type"); + // ProcessResourceComponentProvider + assertThat(attributeKeys).contains("process.command_line"); + assertThat(attributeKeys).contains("process.executable.path"); + assertThat(attributeKeys).contains("process.pid"); + // ProcessRuntimeResourceComponentProvider + assertThat(attributeKeys).contains("process.runtime.description"); + assertThat(attributeKeys).contains("process.runtime.name"); + assertThat(attributeKeys).contains("process.runtime.version"); + }); + } +}