Add resource providers (#6574)

* Add resource providers

* Use autoservice annotation
This commit is contained in:
jack-berg 2022-09-14 17:45:24 -05:00 committed by GitHub
parent 0d1b954d9c
commit 6b607c1e18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1166 additions and 0 deletions

View File

@ -136,6 +136,7 @@ testing {
implementation("org.junit.jupiter:junit-jupiter-params")
runtimeOnly("org.junit.jupiter:junit-jupiter-engine")
runtimeOnly("org.junit.vintage:junit-vintage-engine")
implementation("org.junit-pioneer:junit-pioneer")
implementation("org.assertj:assertj-core")

View File

@ -106,6 +106,7 @@ val DEPENDENCIES = listOf(
"com.google.code.findbugs:jsr305:3.0.2",
"org.apache.groovy:groovy:${groovyVersion}",
"org.apache.groovy:groovy-json:${groovyVersion}",
"org.codehaus.mojo:animal-sniffer-annotations:1.22",
"org.junit-pioneer:junit-pioneer:1.7.1",
"org.objenesis:objenesis:3.2",
"org.spockframework:spock-core:2.2-groovy-4.0",

View File

@ -0,0 +1,62 @@
# OpenTelemetry Resource Providers
This package includes some standard `ResourceProvider`s for filling in attributes related to
common environments. Currently, the resources provide the following semantic conventions:
## Populated attributes
### Container
Provider: `io.opentelemetry.instrumentation.resources.ContainerResource`
Specification: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/container.md
Implemented attributes:
- `container.id`
### Host
Provider: `io.opentelemetry.instrumentation.resources.HostResource`
Specification: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/host.md
Implemented attributes:
- `host.name`
- `host.arch`
### Operating System
Provider: `io.opentelemetry.instrumentation.resources.OsResource`
Specification: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/resource/semantic_conventions/os.md
Implemented attributes:
- `os.type`
- `os.description`
### Process
Implementation: `io.opentelemetry.instrumentation.resources.ProcessResource`
Specification: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/resource/semantic_conventions/process.md#process
Implemented attributes:
- `process.pid`
- `process.executable.path` (note, we assume the `java` binary is located in the `bin` subfolder of `JAVA_HOME`)
- `process.command_line` (note this includes all system properties and arguments when running)
### Java Runtime
Implementation: `io.opentelemetry.instrumentation.resources.ProcessRuntimeResource`
Specification: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/resource/semantic_conventions/process.md#process-runtimes
Implemented attributes:
- `process.runtime.name`
- `process.runtime.version`
- `process.runtime.description`
## Platforms
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.

View File

@ -0,0 +1,64 @@
plugins {
id("otel.library-instrumentation")
id("otel.animalsniffer-conventions")
}
val mrJarVersions = listOf(11)
dependencies {
implementation("io.opentelemetry:opentelemetry-sdk-common")
implementation("io.opentelemetry:opentelemetry-semconv")
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
compileOnly("org.codehaus.mojo:animal-sniffer-annotations")
annotationProcessor("com.google.auto.service:auto-service")
compileOnly("com.google.auto.service:auto-service-annotations")
testImplementation("org.junit.jupiter:junit-jupiter-api")
}
for (version in mrJarVersions) {
sourceSets {
create("java$version") {
java {
setSrcDirs(listOf("src/main/java$version"))
}
}
}
tasks {
named<JavaCompile>("compileJava${version}Java") {
sourceCompatibility = "$version"
targetCompatibility = "$version"
options.release.set(version)
}
}
configurations {
named("java${version}Implementation") {
extendsFrom(configurations["implementation"])
}
named("java${version}CompileOnly") {
extendsFrom(configurations["compileOnly"])
}
}
dependencies {
// Common to reference classes in main sourceset from Java 9 one (e.g., to return a common interface)
add("java${version}Implementation", files(sourceSets.main.get().output.classesDirs))
}
}
tasks {
withType(Jar::class) {
for (version in mrJarVersions) {
into("META-INF/versions/$version") {
from(sourceSets["java$version"].output)
}
}
manifest.attributes(
"Multi-Release" to "true"
)
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.internal.OtelEncodingUtils;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
/** Factory for {@link Resource} retrieving Container ID information. */
public final class ContainerResource {
private static final Logger logger = Logger.getLogger(ContainerResource.class.getName());
private static final String UNIQUE_HOST_NAME_FILE_NAME = "/proc/self/cgroup";
private static final Resource INSTANCE = buildSingleton(UNIQUE_HOST_NAME_FILE_NAME);
@IgnoreJRERequirement
private static Resource buildSingleton(String uniqueHostNameFileName) {
// can't initialize this statically without running afoul of animalSniffer on paths
return buildResource(Paths.get(uniqueHostNameFileName));
}
// package private for testing
static Resource buildResource(Path path) {
String containerId = extractContainerId(path);
if (containerId == null || containerId.isEmpty()) {
return Resource.empty();
} else {
return Resource.create(Attributes.of(ResourceAttributes.CONTAINER_ID, containerId));
}
}
/** Returns resource with container information. */
public static Resource get() {
return INSTANCE;
}
/**
* Each line of cgroup file looks like "14:name=systemd:/docker/.../... A hex string is expected
* inside the last section separated by '/' Each segment of the '/' can contain metadata separated
* by either '.' (at beginning) or '-' (at end)
*
* @return containerId
*/
@IgnoreJRERequirement
@Nullable
private static String extractContainerId(Path cgroupFilePath) {
if (!Files.exists(cgroupFilePath) || !Files.isReadable(cgroupFilePath)) {
return null;
}
try (Stream<String> lines = Files.lines(cgroupFilePath)) {
Optional<String> value =
lines
.filter(line -> !line.isEmpty())
.map(ContainerResource::getIdFromLine)
.filter(Objects::nonNull)
.findFirst();
if (value.isPresent()) {
return value.get();
}
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to read file", e);
}
return null;
}
@Nullable
private static String getIdFromLine(String line) {
// This cgroup output line should have the container id in it
int lastSlashIdx = line.lastIndexOf('/');
if (lastSlashIdx < 0) {
return null;
}
String containerId;
String lastSection = line.substring(lastSlashIdx + 1);
int colonIdx = lastSection.lastIndexOf(':');
if (colonIdx != -1) {
// since containerd v1.5.0+, containerId is divided by the last colon when the cgroupDriver is
// systemd:
// https://github.com/containerd/containerd/blob/release/1.5/pkg/cri/server/helpers_linux.go#L64
containerId = lastSection.substring(colonIdx + 1);
} else {
int startIdx = lastSection.lastIndexOf('-');
int endIdx = lastSection.lastIndexOf('.');
startIdx = startIdx == -1 ? 0 : startIdx + 1;
if (endIdx == -1) {
endIdx = lastSection.length();
}
if (startIdx > endIdx) {
return null;
}
containerId = lastSection.substring(startIdx, endIdx);
}
if (OtelEncodingUtils.isValidBase16String(containerId) && !containerId.isEmpty()) {
return containerId;
} else {
return null;
}
}
private ContainerResource() {}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
/** {@link ResourceProvider} for automatically configuring {@link ResourceProvider}. */
@AutoService(ResourceProvider.class)
public class ContainerResourceProvider implements ResourceProvider {
@Override
public Resource createResource(ConfigProperties config) {
return ContainerResource.get();
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.net.InetAddress;
import java.net.UnknownHostException;
/** Factory for a {@link Resource} which provides information about the host info. */
public final class HostResource {
private static final Resource INSTANCE = buildResource();
/** Returns a {@link Resource} which provides information about host. */
public static Resource get() {
return INSTANCE;
}
// Visible for testing
static Resource buildResource() {
AttributesBuilder attributes = Attributes.builder();
try {
attributes.put(ResourceAttributes.HOST_NAME, InetAddress.getLocalHost().getHostName());
} catch (UnknownHostException e) {
// Ignore
}
String hostArch = null;
try {
hostArch = System.getProperty("os.arch");
} catch (SecurityException t) {
// Ignore
}
if (hostArch != null) {
attributes.put(ResourceAttributes.HOST_ARCH, hostArch);
}
return Resource.create(attributes.build(), ResourceAttributes.SCHEMA_URL);
}
private HostResource() {}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
/** {@link ResourceProvider} for automatically configuring {@link HostResource}. */
@AutoService(ResourceProvider.class)
public final class HostResourceProvider implements ResourceProvider {
@Override
public Resource createResource(ConfigProperties config) {
return HostResource.get();
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import javax.annotation.Nullable;
/** Factory of a {@link Resource} which provides information about the current operating system. */
public final class OsResource {
private static final Resource INSTANCE = buildResource();
/**
* Returns a factory for a {@link Resource} which provides information about the current operating
* system.
*/
public static Resource get() {
return INSTANCE;
}
// Visible for testing
static Resource buildResource() {
String os;
try {
os = System.getProperty("os.name");
} catch (SecurityException t) {
// Security manager enabled, can't provide much os information.
return Resource.empty();
}
if (os == null) {
return Resource.empty();
}
AttributesBuilder attributes = Attributes.builder();
String osName = getOs(os);
if (osName != null) {
attributes.put(ResourceAttributes.OS_TYPE, osName);
}
String version = null;
try {
version = System.getProperty("os.version");
} catch (SecurityException e) {
// Ignore
}
String osDescription = version != null ? os + ' ' + version : os;
attributes.put(ResourceAttributes.OS_DESCRIPTION, osDescription);
return Resource.create(attributes.build(), ResourceAttributes.SCHEMA_URL);
}
@Nullable
private static String getOs(String os) {
os = os.toLowerCase();
if (os.startsWith("windows")) {
return ResourceAttributes.OsTypeValues.WINDOWS;
} else if (os.startsWith("linux")) {
return ResourceAttributes.OsTypeValues.LINUX;
} else if (os.startsWith("mac")) {
return ResourceAttributes.OsTypeValues.DARWIN;
} else if (os.startsWith("freebsd")) {
return ResourceAttributes.OsTypeValues.FREEBSD;
} else if (os.startsWith("netbsd")) {
return ResourceAttributes.OsTypeValues.NETBSD;
} else if (os.startsWith("openbsd")) {
return ResourceAttributes.OsTypeValues.OPENBSD;
} else if (os.startsWith("dragonflybsd")) {
return ResourceAttributes.OsTypeValues.DRAGONFLYBSD;
} else if (os.startsWith("hp-ux")) {
return ResourceAttributes.OsTypeValues.HPUX;
} else if (os.startsWith("aix")) {
return ResourceAttributes.OsTypeValues.AIX;
} else if (os.startsWith("solaris")) {
return ResourceAttributes.OsTypeValues.SOLARIS;
} else if (os.startsWith("z/os")) {
return ResourceAttributes.OsTypeValues.Z_OS;
}
return null;
}
private OsResource() {}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
/** {@link ResourceProvider} for automatically configuring {@link OsResource}. */
@AutoService(ResourceProvider.class)
public final class OsResourceProvider implements ResourceProvider {
@Override
public Resource createResource(ConfigProperties config) {
return OsResource.get();
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import java.lang.management.ManagementFactory;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
final class ProcessPid {
private ProcessPid() {}
@IgnoreJRERequirement
static long getPid() {
// While this is not strictly defined, almost all commonly used JVMs format this as
// pid@hostname.
String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
int atIndex = runtimeName.indexOf('@');
if (atIndex >= 0) {
String pidString = runtimeName.substring(0, atIndex);
try {
return Long.parseLong(pidString);
} catch (NumberFormatException ignored) {
// Ignore parse failure.
}
}
return -1;
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
/** Factory of a {@link Resource} which provides information about the current running process. */
public final class ProcessResource {
private static final Resource INSTANCE = buildResource();
/**
* Returns a factory for a {@link Resource} which provides information about the current running
* process.
*/
public static Resource get() {
return INSTANCE;
}
// Visible for testing
static Resource buildResource() {
try {
return doBuildResource();
} catch (LinkageError t) {
// Will only happen on Android, where these attributes generally don't make much sense
// anyways.
return Resource.empty();
}
}
@IgnoreJRERequirement
private static Resource doBuildResource() {
AttributesBuilder attributes = Attributes.builder();
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
long pid = ProcessPid.getPid();
if (pid >= 0) {
attributes.put(ResourceAttributes.PROCESS_PID, pid);
}
String javaHome = null;
String osName = null;
try {
javaHome = System.getProperty("java.home");
osName = System.getProperty("os.name");
} catch (SecurityException e) {
// Ignore
}
if (javaHome != null) {
StringBuilder executablePath = new StringBuilder(javaHome);
executablePath
.append(File.pathSeparatorChar)
.append("bin")
.append(File.pathSeparatorChar)
.append("java");
if (osName != null && osName.toLowerCase().startsWith("windows")) {
executablePath.append(".exe");
}
attributes.put(ResourceAttributes.PROCESS_EXECUTABLE_PATH, executablePath.toString());
StringBuilder commandLine = new StringBuilder(executablePath);
for (String arg : runtime.getInputArguments()) {
commandLine.append(' ').append(arg);
}
attributes.put(ResourceAttributes.PROCESS_COMMAND_LINE, commandLine.toString());
}
return Resource.create(attributes.build(), ResourceAttributes.SCHEMA_URL);
}
private ProcessResource() {}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
/** {@link ResourceProvider} for automatically configuring {@link ProcessResource}. */
@AutoService(ResourceProvider.class)
public final class ProcessResourceProvider implements ResourceProvider {
@Override
public Resource createResource(ConfigProperties config) {
return ProcessResource.get();
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.PROCESS_RUNTIME_DESCRIPTION;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.PROCESS_RUNTIME_NAME;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.PROCESS_RUNTIME_VERSION;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
/** Factory of a {@link Resource} which provides information about the Java runtime. */
public final class ProcessRuntimeResource {
private static final Resource INSTANCE = buildResource();
/** Returns a factory for a {@link Resource} which provides information about the Java runtime. */
public static Resource get() {
return INSTANCE;
}
// Visible for testing
static Resource buildResource() {
try {
String name = System.getProperty("java.runtime.name");
String version = System.getProperty("java.runtime.version");
String description =
System.getProperty("java.vm.vendor")
+ " "
+ System.getProperty("java.vm.name")
+ " "
+ System.getProperty("java.vm.version");
return Resource.create(
Attributes.of(
PROCESS_RUNTIME_NAME,
name,
PROCESS_RUNTIME_VERSION,
version,
PROCESS_RUNTIME_DESCRIPTION,
description),
ResourceAttributes.SCHEMA_URL);
} catch (SecurityException ignored) {
return Resource.empty();
}
}
private ProcessRuntimeResource() {}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
/** {@link ResourceProvider} for automatically configuring {@link ProcessRuntimeResource}. */
@AutoService(ResourceProvider.class)
public final class ProcessRuntimeResourceProvider implements ResourceProvider {
@Override
public Resource createResource(ConfigProperties config) {
return ProcessRuntimeResource.get();
}
}

View File

@ -0,0 +1,13 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
/**
* {@link io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider} implementations for common
* resource information.
*/
@ParametersAreNonnullByDefault
package io.opentelemetry.instrumentation.resources;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@ -0,0 +1,19 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import java.lang.management.ManagementFactory;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
final class ProcessPid {
private ProcessPid() {}
@IgnoreJRERequirement
static long getPid() {
return ManagementFactory.getRuntimeMXBean().getPid();
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import static io.opentelemetry.instrumentation.resources.ContainerResource.buildResource;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
class ContainerResourceTest {
@Test
void buildResource_Invalid(@TempDir Path tempFolder) throws IOException {
// invalid containerId (non-hex)
Path cgroup =
createCgroup(
tempFolder.resolve("cgroup1"),
"13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23zzzz");
assertThat(buildResource(cgroup)).isEqualTo(Resource.empty());
// unrecognized format (last "-" is after last ".")
cgroup =
createCgroup(
tempFolder.resolve("cgroup1"),
"13:name=systemd:/podruntime/docker/kubepods/ac679f8.a8319c8cf7d38e1adf263bc08-d23zzzz");
assertThat(buildResource(cgroup)).isEqualTo(Resource.empty());
// test invalid file
cgroup = tempFolder.resolve("DoesNotExist");
assertThat(buildResource(cgroup)).isEqualTo(Resource.empty());
}
@Test
void buildResource_Valid(@TempDir Path tempFolder) throws IOException {
// with suffix
Path cgroup =
createCgroup(
tempFolder.resolve("cgroup1"),
"13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23.aaaa");
assertThat(getContainerId(buildResource(cgroup)))
.isEqualTo("ac679f8a8319c8cf7d38e1adf263bc08d23");
// with prefix and suffix
Path cgroup2 =
createCgroup(
tempFolder.resolve("cgroup2"),
"13:name=systemd:/podruntime/docker/kubepods/crio-dc679f8a8319c8cf7d38e1adf263bc08d23.stuff");
assertThat(getContainerId(buildResource(cgroup2)))
.isEqualTo("dc679f8a8319c8cf7d38e1adf263bc08d23");
// just container id
Path cgroup3 =
createCgroup(
tempFolder.resolve("cgroup3"),
"13:name=systemd:/pod/d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356");
assertThat(getContainerId(buildResource(cgroup3)))
.isEqualTo("d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356");
// with prefix
Path cgroup4 =
createCgroup(
tempFolder.resolve("cgroup4"),
"//\n"
+ "1:name=systemd:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23"
+ "2:name=systemd:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23"
+ "3:name=systemd:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23");
assertThat(getContainerId(buildResource(cgroup4)))
.isEqualTo("dc579f8a8319c8cf7d38e1adf263bc08d23");
// with two dashes in prefix
Path cgroup5 =
createCgroup(
tempFolder.resolve("cgroup5"),
"11:perf_event:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod4415fd05_2c0f_4533_909b_f2180dca8d7c.slice/cri-containerd-713a77a26fe2a38ebebd5709604a048c3d380db1eb16aa43aca0b2499e54733c.scope");
assertThat(getContainerId(buildResource(cgroup5)))
.isEqualTo("713a77a26fe2a38ebebd5709604a048c3d380db1eb16aa43aca0b2499e54733c");
// with colon, env: k8s v1.24.0, the cgroupDriver by systemd(default), and container is
// cri-containerd v1.6.8
Path cgroup6 =
createCgroup(
tempFolder.resolve("cgroup6"),
"11:devices:/system.slice/containerd.service/kubepods-pod87a18a64_b74a_454a_b10b_a4a36059d0a3.slice:cri-containerd:05c48c82caff3be3d7f1e896981dd410e81487538936914f32b624d168de9db0");
assertThat(getContainerId(buildResource(cgroup6)))
.isEqualTo("05c48c82caff3be3d7f1e896981dd410e81487538936914f32b624d168de9db0");
}
private static String getContainerId(Resource resource) {
return resource.getAttribute(ResourceAttributes.CONTAINER_ID);
}
private static Path createCgroup(Path path, String line) throws IOException {
return Files.write(path, line.getBytes(StandardCharsets.UTF_8));
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtendWith;
class HostResourceTest {
@Test
void shouldCreateRuntimeAttributes() {
// when
Resource resource = HostResource.buildResource();
Attributes attributes = resource.getAttributes();
// then
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes.get(ResourceAttributes.HOST_NAME)).isNotBlank();
assertThat(attributes.get(ResourceAttributes.HOST_ARCH)).isNotBlank();
}
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SecurityManagerExtension.class)
@EnabledOnJre(
value = {JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_16},
disabledReason = "Java 17 deprecates security manager for removal")
static class SecurityManagerEnabled {
@Test
void empty() {
Attributes attributes = HostResource.buildResource().getAttributes();
assertThat(attributes.asMap()).containsOnlyKeys(ResourceAttributes.HOST_NAME);
}
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junitpioneer.jupiter.SetSystemProperty;
class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Linux 4.11")
void linux() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.LINUX);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "MacOS X 11")
void macos() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.DARWIN);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "Windows 10")
void windows() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.WINDOWS);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "FreeBSD 10")
void freebsd() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.FREEBSD);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "NetBSD 10")
void netbsd() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.NETBSD);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "OpenBSD 10")
void openbsd() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.OPENBSD);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "DragonFlyBSD 10")
void dragonflybsd() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.DRAGONFLYBSD);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "HP-UX 10")
void hpux() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.HPUX);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "AIX 10")
void aix() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.AIX);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "Solaris 10")
void solaris() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.SOLARIS);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "Z/OS 10")
void zos() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.Z_OS);
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Test
@SetSystemProperty(key = "os.name", value = "RagOS 10")
void unknown() {
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(resource.getAttribute(ResourceAttributes.OS_TYPE)).isNull();
assertThat(resource.getAttribute(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SecurityManagerExtension.class)
@EnabledOnJre(
value = {JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_16},
disabledReason = "Java 17 deprecates security manager for removal")
static class SecurityManagerEnabled {
@Test
void empty() {
assertThat(OsResource.buildResource()).isEqualTo(Resource.empty());
}
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junitpioneer.jupiter.SetSystemProperty;
class ProcessResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Linux 4.12")
void notWindows() {
Resource resource = ProcessResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.PROCESS_PID)).isGreaterThan(1);
assertThat(attributes.get(ResourceAttributes.PROCESS_EXECUTABLE_PATH))
.contains("java")
.doesNotEndWith(".exe");
assertThat(attributes.get(ResourceAttributes.PROCESS_COMMAND_LINE))
.contains(attributes.get(ResourceAttributes.PROCESS_EXECUTABLE_PATH));
}
@Test
@SetSystemProperty(key = "os.name", value = "Windows 10")
void windows() {
Resource resource = ProcessResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.PROCESS_PID)).isGreaterThan(1);
assertThat(attributes.get(ResourceAttributes.PROCESS_EXECUTABLE_PATH))
.contains("java")
.endsWith(".exe");
assertThat(attributes.get(ResourceAttributes.PROCESS_COMMAND_LINE))
.contains(attributes.get(ResourceAttributes.PROCESS_EXECUTABLE_PATH));
}
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SecurityManagerExtension.class)
@EnabledOnJre(
value = {JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_16},
disabledReason = "Java 17 deprecates security manager for removal")
static class SecurityManagerEnabled {
@Test
void empty() {
Attributes attributes = ProcessResource.buildResource().getAttributes();
assertThat(attributes.asMap()).containsOnlyKeys(ResourceAttributes.PROCESS_PID);
}
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtendWith;
class ProcessRuntimeResourceTest {
@Test
void shouldCreateRuntimeAttributes() {
// when
Resource resource = ProcessRuntimeResource.buildResource();
Attributes attributes = resource.getAttributes();
// then
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes.get(ResourceAttributes.PROCESS_RUNTIME_NAME)).isNotBlank();
assertThat(attributes.get(ResourceAttributes.PROCESS_RUNTIME_VERSION)).isNotBlank();
assertThat(attributes.get(ResourceAttributes.PROCESS_RUNTIME_DESCRIPTION)).isNotBlank();
}
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SecurityManagerExtension.class)
@EnabledOnJre(
value = {JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_16},
disabledReason = "Java 17 deprecates security manager for removal")
static class SecurityManagerEnabled {
@Test
void empty() {
assertThat(ProcessRuntimeResource.buildResource()).isEqualTo(Resource.empty());
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.resources;
import java.security.Permission;
import java.util.HashSet;
import java.util.PropertyPermission;
import java.util.Set;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
final class SecurityManagerExtension implements BeforeEachCallback, AfterEachCallback {
private static final ExtensionContext.Namespace NAMESPACE =
ExtensionContext.Namespace.create(SecurityManagerExtension.class);
@Override
public void beforeEach(ExtensionContext context) {
context.getStore(NAMESPACE).put(SecurityManager.class, System.getSecurityManager());
System.setSecurityManager(BlockPropertiesAccess.INSTANCE);
}
@Override
public void afterEach(ExtensionContext context) {
System.setSecurityManager(
(SecurityManager) context.getStore(NAMESPACE).get(SecurityManager.class));
}
private static class BlockPropertiesAccess extends SecurityManager {
private static final BlockPropertiesAccess INSTANCE = new BlockPropertiesAccess();
private static final Set<String> BLOCKED_PROPERTIES = new HashSet<>();
static {
BLOCKED_PROPERTIES.add("java.home");
BLOCKED_PROPERTIES.add("java.runtime.home");
BLOCKED_PROPERTIES.add("java.runtime.version");
BLOCKED_PROPERTIES.add("java.vm.name");
BLOCKED_PROPERTIES.add("java.vm.vendor");
BLOCKED_PROPERTIES.add("java.vm.version");
BLOCKED_PROPERTIES.add("os.arch");
BLOCKED_PROPERTIES.add("os.name");
BLOCKED_PROPERTIES.add("os.version");
}
@Override
public void checkPermission(Permission perm) {
if (perm instanceof PropertyPermission) {
if (BLOCKED_PROPERTIES.contains(perm.getName())) {
throw new SecurityException("Property access not allowed.");
}
}
}
}
}

View File

@ -395,6 +395,7 @@ include(":instrumentation:redisson:redisson-3.0:javaagent")
include(":instrumentation:redisson:redisson-3.17:javaagent")
include(":instrumentation:redisson:redisson-common:javaagent")
include(":instrumentation:redisson:redisson-common:testing")
include(":instrumentation:resources:library")
include(":instrumentation:restlet:restlet-1.0:javaagent")
include(":instrumentation:restlet:restlet-1.0:library")
include(":instrumentation:restlet:restlet-1.0:testing")