001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.kubernetes; 018 019import java.io.File; 020import java.io.IOException; 021import java.nio.file.Files; 022import java.nio.file.Path; 023import java.util.Objects; 024 025import org.apache.logging.log4j.Logger; 026import org.apache.logging.log4j.status.StatusLogger; 027 028/** 029 * Locate the current docker container. 030 */ 031public class ContainerUtil { 032 private static final Logger LOGGER = StatusLogger.getLogger(); 033 private static final int MAXLENGTH = 65; 034 035/** 036 * Returns the container id when running in a Docker container. 037 * 038 * This inspects /proc/self/cgroup looking for a Kubernetes Control Group. Once it finds one it attempts 039 * to isolate just the docker container id. There doesn't appear to be a standard way to do this, but 040 * it seems to be the only way to determine what the current container is in a multi-container pod. It would have 041 * been much nicer if Kubernetes would just put the container id in a standard environment variable. 042 * 043 * @see <a href="http://stackoverflow.com/a/25729598/12916">Stackoverflow</a> for a discussion on retrieving the containerId. 044 * @see <a href="https://github.com/jenkinsci/docker-workflow-plugin/blob/master/src/main/java/org/jenkinsci/plugins/docker/workflow/client/ControlGroup.java>ControlGroup</a> 045 * for the original version of this. Not much is actually left but it provided good inspiration. 046 */ 047 public static String getContainerId() { 048 try { 049 File file = new File("/proc/self/cgroup"); 050 if (file.exists()) { 051 Path path = file.toPath(); 052 String id = Files.lines(path).map(ContainerUtil::getContainerId).filter(Objects::nonNull) 053 .findFirst().orElse(null); 054 LOGGER.debug("Found container id {}", id); 055 return id; 056 } 057 LOGGER.warn("Unable to access container information"); 058 } catch (IOException ioe) { 059 LOGGER.warn("Error obtaining container id: {}", ioe.getMessage()); 060 } 061 return null; 062 } 063 064 private static String getContainerId(String line) { 065 // Every control group in Kubernetes will use 066 if (line.contains("/kubepods")) { 067 // Strip off everything up to the last slash. 068 int i = line.lastIndexOf('/'); 069 if (i < 0) { 070 return null; 071 } 072 // If the remainder has a period then take everything up to it. 073 line = line.substring(i + 1); 074 i = line.lastIndexOf('.'); 075 if (i > 0) { 076 line = line.substring(0, i); 077 } 078 // Everything ending with a '/' has already been stripped but the remainder might start with "docker-" 079 if (line.contains("docker-")) { 080 // 8:cpuset:/kubepods.slice/kubepods-pod9c26dfb6_b9c9_11e7_bfb9_02c6c1fc4861.slice/docker-3dd988081e7149463c043b5d9c57d7309e079c5e9290f91feba1cc45a04d6a5b.scope 081 i = line.lastIndexOf("docker-"); 082 line = line.substring(i + 7); 083 } 084 return line.length() <= MAXLENGTH ? line : line.substring(0, MAXLENGTH); 085 } 086 087 return null; 088 } 089}