-
Notifications
You must be signed in to change notification settings - Fork 107
Pass origin information to the forwarder #325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
257 changes: 257 additions & 0 deletions
257
dogstatsd-http/core/src/main/java/com/datadoghq/dogstatsd/http/CgroupReader.java
This file contains hidden or 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,257 @@ | ||
| package com.datadoghq.dogstatsd.http; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.Arrays; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| /** | ||
| * A reader class that retrieves the current container ID or the cgroup controller inode parsed from | ||
| * the cgroup file. | ||
| */ | ||
| class CgroupReader { | ||
| private static final Path CGROUP_PATH = Paths.get("/proc/self/cgroup"); | ||
| private static final String UUID_SOURCE = "[0-9a-f]{8}(?:[_-][0-9a-f]{4}){3}[_-][0-9a-f]{12}"; | ||
| private static final String CONTAINER_SOURCE = "[0-9a-f]{64}"; | ||
| private static final String TASK_SOURCE = "[0-9a-f]{32}-\\d+"; | ||
| private static final Pattern LINE_RE = | ||
| Pattern.compile("^\\d+:[^:]*:(.+)$", Pattern.MULTILINE | Pattern.UNIX_LINES); | ||
| private static final Pattern CONTAINER_RE = | ||
| Pattern.compile( | ||
| "(" | ||
| + UUID_SOURCE | ||
| + "|" | ||
| + CONTAINER_SOURCE | ||
| + "|" | ||
| + TASK_SOURCE | ||
| + ")(?:.scope)?$"); | ||
|
|
||
| /** DEFAULT_CGROUP_MOUNT_PATH is the default cgroup mount path. */ | ||
| private static final Path DEFAULT_CGROUP_MOUNT_PATH = Paths.get("/sys/fs/cgroup"); | ||
|
|
||
| /** CGROUP_NS_PATH is the path to the cgroup namespace file. */ | ||
| private static final Path CGROUP_NS_PATH = Paths.get("/proc/self/ns/cgroup"); | ||
|
|
||
| /** | ||
| * CGROUPV1_BASE_CONTROLLER is the controller used to identify the container-id in cgroup v1 | ||
| * (memory). | ||
| */ | ||
| private static final String CGROUPV1_BASE_CONTROLLER = "memory"; | ||
|
|
||
| /** | ||
| * CGROUPV2_BASE_CONTROLLER is the controller used to identify the container-id in cgroup v2. | ||
| */ | ||
| private static final String CGROUPV2_BASE_CONTROLLER = ""; | ||
|
|
||
| /** HOST_CGROUP_NAMESPACE_INODE is the inode of the host cgroup namespace. */ | ||
| private static final long HOST_CGROUP_NAMESPACE_INODE = 0xEFFFFFFBL; | ||
|
|
||
| private final Path MOUNTINFO_PATH = Paths.get("/proc/self/mountinfo"); | ||
|
|
||
| private final Pattern MOUNTINFO_RE = | ||
| Pattern.compile( | ||
| ".*/([^\\s/]+)/(([0-9a-f]{64})|([0-9a-f]{32}-\\d+)|([0-9a-f]{8}(-[0-9a-f]{4}){4})$)/[\\S]*hostname"); | ||
|
|
||
| interface Fs { | ||
| String getContents(Path path) throws IOException; | ||
|
|
||
| long getInode(Path path) throws IOException; | ||
| } | ||
|
|
||
| static class FilesFs implements Fs { | ||
| @Override | ||
| public String getContents(Path path) throws IOException { | ||
| return new String(Files.readAllBytes(path)); | ||
| } | ||
|
|
||
| @Override | ||
| public long getInode(Path path) throws IOException { | ||
| return (long) Files.getAttribute(path, "unix:ino"); | ||
| } | ||
| } | ||
|
|
||
| private final Fs fs; | ||
|
|
||
| CgroupReader() { | ||
| this(new FilesFs()); | ||
| } | ||
|
|
||
| CgroupReader(Fs fs) { | ||
| super(); | ||
| this.fs = fs; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the container ID if available or the cgroup controller inode. | ||
| * | ||
| * @throws IOException if /proc/self/cgroup is readable and still an I/O error occurs reading | ||
| * from the stream. | ||
| */ | ||
| public String getContainerID() { | ||
| String containerID = null; | ||
|
|
||
| String cgroupContent = null; | ||
| try { | ||
| cgroupContent = fs.getContents(CGROUP_PATH); | ||
| } catch (IOException ex) { | ||
| // ignored | ||
| } | ||
|
|
||
| if (!isEmpty(cgroupContent)) { | ||
| containerID = parseSelfCgroup(cgroupContent); | ||
| } | ||
|
|
||
| if (!isEmpty(containerID)) { | ||
| return containerID; | ||
| } | ||
|
|
||
| containerID = trySelfMountInfo(); | ||
| if (!isEmpty(containerID)) { | ||
| return containerID; | ||
| } | ||
|
|
||
| /* | ||
| * If the container ID is not available it means that the application is either | ||
| * not running in a container or running is private cgroup namespace, we | ||
| * fallback to the cgroup controller inode. The agent (7.51+) will use it to get | ||
| * the container ID. | ||
| * In Host cgroup namespace, the container ID should be found. If it is not | ||
| * found, it means that the application is running on a host/vm. | ||
| * | ||
| */ | ||
| if (!isEmpty(cgroupContent) && !isHostCgroupNamespace(CGROUP_NS_PATH)) { | ||
| containerID = getCgroupInode(DEFAULT_CGROUP_MOUNT_PATH, cgroupContent); | ||
| } | ||
| return containerID; | ||
| } | ||
|
|
||
| /** | ||
| * Parses a Cgroup file (=/proc/self/cgroup) content and returns the corresponding container ID. | ||
| * It can be found only if the container is running in host cgroup namespace. | ||
| * | ||
| * @param cgroupsContent Cgroup file content | ||
| */ | ||
| public static String parseSelfCgroup(final String cgroupsContent) { | ||
| final Matcher lines = LINE_RE.matcher(cgroupsContent); | ||
| while (lines.find()) { | ||
| final String path = lines.group(1); | ||
| final Matcher matcher = CONTAINER_RE.matcher(path); | ||
| if (matcher.find()) { | ||
| return matcher.group(1); | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the host cgroup namespace is used. It looks at the inode of | ||
| * `/proc/self/ns/cgroup` and compares it to HOST_CGROUP_NAMESPACE_INODE. | ||
| * | ||
| * @param path Path to the cgroup namespace file. | ||
| */ | ||
| private boolean isHostCgroupNamespace(final Path path) { | ||
| long hostCgroupInode = inodeForPath(path); | ||
| return hostCgroupInode == HOST_CGROUP_NAMESPACE_INODE; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the inode for the given path. | ||
| * | ||
| * @param path Path to the cgroup namespace file. | ||
| */ | ||
| private long inodeForPath(final Path path) { | ||
| try { | ||
| long inode = (long) fs.getInode(path); | ||
| return inode; | ||
| } catch (Exception e) { | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns the cgroup controller inode for the given cgroup mount path and procSelfCgroupPath. | ||
| * | ||
| * @param cgroupMountPath Path to the cgroup mount point. | ||
| * @param cgroupContent String content of the cgroup file. | ||
| */ | ||
| public String getCgroupInode(final Path cgroupMountPath, final String cgroupContent) { | ||
| Map<String, String> cgroupControllersPaths = parseCgroupNodePath(cgroupContent); | ||
| if (cgroupControllersPaths == null) { | ||
| return null; | ||
| } | ||
|
|
||
| // Retrieve the cgroup inode from /sys/fs/cgroup+controller+cgroupNodePath | ||
| List<String> controllers = | ||
| Arrays.asList(CGROUPV1_BASE_CONTROLLER, CGROUPV2_BASE_CONTROLLER); | ||
| for (String controller : controllers) { | ||
| String cgroupNodePath = cgroupControllersPaths.get(controller); | ||
| if (cgroupNodePath == null) { | ||
| continue; | ||
| } | ||
| Path path = Paths.get(cgroupMountPath.toString(), controller, cgroupNodePath); | ||
| long inode = inodeForPath(path); | ||
| /* | ||
| * Inode 0 is not a valid inode. Inode 1 is a bad block inode and inode 2 is the | ||
| * root of a filesystem. We can safely ignore them. | ||
| */ | ||
| if (inode > 2) { | ||
| return "in-" + inode; | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a map of cgroup controllers and their corresponding cgroup path. | ||
| * | ||
| * @param cgroupContent Cgroup file content. | ||
| */ | ||
| public Map<String, String> parseCgroupNodePath(final String cgroupContent) { | ||
| Map<String, String> res = new HashMap<>(); | ||
|
|
||
| for (String line : cgroupContent.split("\n")) { | ||
| String[] tokens = line.split(":"); | ||
| if (tokens.length != 3) { | ||
| continue; | ||
| } | ||
| if (CGROUPV1_BASE_CONTROLLER.equals(tokens[1]) | ||
| || CGROUPV2_BASE_CONTROLLER.equals(tokens[1])) { | ||
| res.put(tokens[1], tokens[2]); | ||
| } | ||
| } | ||
|
|
||
| return res; | ||
| } | ||
|
|
||
| private static boolean isEmpty(String str) { | ||
| return str == null || str.isEmpty(); | ||
| } | ||
|
|
||
| String trySelfMountInfo() { | ||
| String mountInfo; | ||
| try { | ||
| mountInfo = fs.getContents(MOUNTINFO_PATH); | ||
| } catch (IOException ex) { | ||
| return null; | ||
| } | ||
|
|
||
| for (String line : mountInfo.split("\n")) { | ||
| Matcher matcher = MOUNTINFO_RE.matcher(line); | ||
| if (matcher.find()) { | ||
| if (!"sandboxes".equals(matcher.group(1))) { | ||
| return matcher.group(2); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
| } |
19 changes: 19 additions & 0 deletions
19
dogstatsd-http/core/src/main/java/com/datadoghq/dogstatsd/http/EnvMap.java
This file contains hidden or 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,19 @@ | ||
| package com.datadoghq.dogstatsd.http; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| class EnvMap { | ||
| private final Map<String, String> env; | ||
|
|
||
| EnvMap() { | ||
| env = null; | ||
| } | ||
|
|
||
| EnvMap(Map<String, String> provided) { | ||
| env = provided; | ||
| } | ||
|
|
||
| String get(String name) { | ||
| return env != null ? env.get(name) : System.getenv(name); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.