-
Notifications
You must be signed in to change notification settings - Fork 878
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This resolves #6694. We've been tracking the update to cgroup version support and want to get ahead of the widespread usage. The surface of the existing `ContainerResource` has not changed, but its internals have been factored out to two "extractor" utilities -- one that understands cgroup v1 and another for v2. v1 is attempted and, if successful, the result is used. If v1 fails, then the `ContainerResource` will fall back to v2. As mentioned in #6694, the approach taken in this PR is borrowed from [this SO post](https://stackoverflow.com/questions/68816329/how-to-get-docker-container-id-from-within-the-container-with-cgroup-v2) combined with local experimentation on docker desktop on a Mac, which already uses cgroup2 v2.
- Loading branch information
1 parent
33b0b58
commit b09fb67
Showing
6 changed files
with
395 additions
and
148 deletions.
There are no files selected for viewing
95 changes: 95 additions & 0 deletions
95
...rc/main/java/io/opentelemetry/instrumentation/resources/CgroupV1ContainerIdExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.resources; | ||
|
||
import io.opentelemetry.api.internal.OtelEncodingUtils; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Optional; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import java.util.stream.Stream; | ||
|
||
/** Utility for extracting the container ID from runtimes inside cgroup v1 containers. */ | ||
final class CgroupV1ContainerIdExtractor { | ||
|
||
private static final Logger logger = | ||
Logger.getLogger(CgroupV1ContainerIdExtractor.class.getName()); | ||
static final Path V1_CGROUP_PATH = Paths.get("/proc/self/cgroup"); | ||
private final ContainerResource.Filesystem filesystem; | ||
|
||
CgroupV1ContainerIdExtractor() { | ||
this(ContainerResource.FILESYSTEM_INSTANCE); | ||
} | ||
|
||
// Exists for testing | ||
CgroupV1ContainerIdExtractor(ContainerResource.Filesystem filesystem) { | ||
this.filesystem = filesystem; | ||
} | ||
|
||
/** | ||
* 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 | ||
*/ | ||
Optional<String> extractContainerId() { | ||
if (!filesystem.isReadable(V1_CGROUP_PATH)) { | ||
return Optional.empty(); | ||
} | ||
try (Stream<String> lines = filesystem.lines(V1_CGROUP_PATH)) { | ||
return lines | ||
.filter(line -> !line.isEmpty()) | ||
.map(CgroupV1ContainerIdExtractor::getIdFromLine) | ||
.filter(Optional::isPresent) | ||
.findFirst() | ||
.orElse(Optional.empty()); | ||
} catch (Exception e) { | ||
logger.log(Level.WARNING, "Unable to read file", e); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
private static Optional<String> getIdFromLine(String line) { | ||
// This cgroup output line should have the container id in it | ||
int lastSlashIdx = line.lastIndexOf('/'); | ||
if (lastSlashIdx < 0) { | ||
return Optional.empty(); | ||
} | ||
|
||
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 Optional.empty(); | ||
} | ||
|
||
containerId = lastSection.substring(startIdx, endIdx); | ||
} | ||
|
||
if (OtelEncodingUtils.isValidBase16String(containerId) && !containerId.isEmpty()) { | ||
return Optional.of(containerId); | ||
} else { | ||
return Optional.empty(); | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...rc/main/java/io/opentelemetry/instrumentation/resources/CgroupV2ContainerIdExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.instrumentation.resources; | ||
|
||
import static java.util.Optional.empty; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Optional; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
/** Utility for extracting the container ID from runtimes inside cgroup v2 containers. */ | ||
class CgroupV2ContainerIdExtractor { | ||
|
||
private static final Logger logger = | ||
Logger.getLogger(CgroupV2ContainerIdExtractor.class.getName()); | ||
|
||
static final Path V2_CGROUP_PATH = Paths.get("/proc/self/mountinfo"); | ||
private static final Pattern CONTAINER_RE = | ||
Pattern.compile(".*/docker/containers/([0-9a-f]{64})/.*"); | ||
|
||
private final ContainerResource.Filesystem filesystem; | ||
|
||
CgroupV2ContainerIdExtractor() { | ||
this(ContainerResource.FILESYSTEM_INSTANCE); | ||
} | ||
|
||
// Exists for testing | ||
CgroupV2ContainerIdExtractor(ContainerResource.Filesystem filesystem) { | ||
this.filesystem = filesystem; | ||
} | ||
|
||
Optional<String> extractContainerId() { | ||
if (!filesystem.isReadable(V2_CGROUP_PATH)) { | ||
return empty(); | ||
} | ||
try { | ||
return filesystem | ||
.lines(V2_CGROUP_PATH) | ||
.map(CONTAINER_RE::matcher) | ||
.filter(Matcher::matches) | ||
.findFirst() | ||
.map(matcher -> matcher.group(1)); | ||
} catch (IOException e) { | ||
logger.log(Level.WARNING, "Unable to read v2 cgroup path", e); | ||
} | ||
return empty(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.