Re-enable Agent Detection on Zos (#13730)

Co-authored-by: Jason Plumb <jplumb@splunk.com>
Co-authored-by: Lauri Tulmin <ltulmin@splunk.com>
This commit is contained in:
Benjamin Confino 2025-04-28 15:46:23 +01:00 committed by GitHub
parent b5492e8c5b
commit 7364927e51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 73 additions and 10 deletions

View File

@ -20,14 +20,21 @@ final class CgroupV1ContainerIdExtractor {
Logger.getLogger(CgroupV1ContainerIdExtractor.class.getName());
static final Path V1_CGROUP_PATH = Paths.get("/proc/self/cgroup");
private final ContainerResource.Filesystem filesystem;
private final Path inputFilePath;
CgroupV1ContainerIdExtractor() {
this(ContainerResource.FILESYSTEM_INSTANCE);
this(ContainerResource.FILESYSTEM_INSTANCE, V1_CGROUP_PATH);
}
// Exists for testing
CgroupV1ContainerIdExtractor(ContainerResource.Filesystem filesystem) {
this(filesystem, V1_CGROUP_PATH);
}
// Exists for testing
CgroupV1ContainerIdExtractor(ContainerResource.Filesystem filesystem, Path inputFilePath) {
this.filesystem = filesystem;
this.inputFilePath = inputFilePath;
}
/**
@ -38,10 +45,10 @@ final class CgroupV1ContainerIdExtractor {
* @return containerId
*/
Optional<String> extractContainerId() {
if (!filesystem.isReadable(V1_CGROUP_PATH)) {
if (!filesystem.isReadable(inputFilePath)) {
return Optional.empty();
}
try (Stream<String> lines = filesystem.lines(V1_CGROUP_PATH)) {
try (Stream<String> lines = filesystem.lines(inputFilePath)) {
return lines
.filter(line -> !line.isEmpty())
.map(CgroupV1ContainerIdExtractor::getIdFromLine)

View File

@ -10,10 +10,15 @@ import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -50,12 +55,6 @@ public final class ContainerResource {
// Visible for testing
Resource buildResource() {
// disable container id detection on z/os
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/12418
String osName = System.getProperty("os.name");
if (osName.equalsIgnoreCase("z/OS") || osName.equalsIgnoreCase("OS/390")) {
return Resource.empty();
}
return getContainerId()
.map(id -> Resource.create(Attributes.of(CONTAINER_ID, id)))
.orElseGet(Resource::empty);
@ -76,6 +75,17 @@ public final class ContainerResource {
// Exists for testing
static class Filesystem {
private static final Logger logger = Logger.getLogger(Filesystem.class.getName());
private final Supplier<String> osNameSupplier;
Filesystem() {
this(() -> System.getProperty("os.name"));
}
Filesystem(Supplier<String> osNameSupplier) {
this.osNameSupplier = osNameSupplier;
}
boolean isReadable(Path path) {
return Files.isReadable(path);
@ -83,7 +93,19 @@ public final class ContainerResource {
@MustBeClosed
Stream<String> lines(Path path) throws IOException {
return Files.lines(path);
String osName = osNameSupplier.get();
if (osName.equalsIgnoreCase("z/OS") || osName.equalsIgnoreCase("OS/390")) {
try {
// On z/OS the /proc tree is always encoded with IBM1047 (Canonical name: Cp1047).
return Files.lines(path, Charset.forName("Cp1047"));
} catch (UnsupportedCharsetException e) {
// What charsets are available depends on the instance of the JVM
logger.log(Level.WARNING, "Unable to find charset Cp1047", e);
return Stream.empty();
}
} else {
return Files.lines(path);
}
}
List<String> lineList(Path path) throws IOException {

View File

@ -11,6 +11,10 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import io.opentelemetry.sdk.resources.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -50,4 +54,34 @@ class ContainerResourceTest {
Resource resource = containerResource.buildResource();
assertThat(resource).isSameAs(Resource.empty());
}
@Test
void testAlternateEncoding() throws Exception {
String containerId = "ac679f8a8319c8cf7d38e1adf263bc08d231f2ff81abda3915f6e8ba4d64156a";
String line = "13:name=systemd:/podruntime/docker/kubepods/" + containerId + ".aaaa";
Charset ibmCharset = Charset.forName("Cp1047");
byte[] utf8 = line.getBytes(StandardCharsets.UTF_8);
byte[] ibm = line.getBytes(ibmCharset);
assertThat(ibm).isNotEqualTo(utf8);
String ibmAsString = new String(ibm, ibmCharset);
// Different bytes, different encoding, same semantic string value
assertThat(line).isEqualTo(ibmAsString);
// Make temp file that contains the IBM encoding
File tempFile = File.createTempFile("tmp", "mountinfo");
tempFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(tempFile)) {
out.write(ibm);
}
ContainerResource.Filesystem fs =
// pretend we are on z/OS to trigger the routine to detect an alternative encoding
new ContainerResource.Filesystem(() -> "z/OS");
CgroupV1ContainerIdExtractor extractor =
new CgroupV1ContainerIdExtractor(fs, tempFile.toPath());
ContainerResource testClass = new ContainerResource(extractor, null);
Resource resource = testClass.buildResource();
assertThat(resource.getAttribute(CONTAINER_ID)).isEqualTo(containerId);
}
}