You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2020/06/21 06:47:26 UTC
[logging-log4j2] branch release-2.x updated: LOG4J2-2877 -
Determine the container id to obtain container and image information
This is an automated email from the ASF dual-hosted git repository.
rgoers pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/release-2.x by this push:
new dff745e LOG4J2-2877 - Determine the container id to obtain container and image information
dff745e is described below
commit dff745ec0c98dd87342bd718712d6cace1f3c78e
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sat Jun 20 23:47:02 2020 -0700
LOG4J2-2877 - Determine the container id to obtain container and image information
---
.../log4j/core/config/ConfigurationScheduler.java | 26 +--
.../apache/logging/log4j/docker/DockerLookup.java | 2 +
.../logging/log4j/kubernetes/ContainerUtil.java | 90 +++++++++++
.../log4j/kubernetes/KubernetesClientBuilder.java | 12 +-
.../logging/log4j/kubernetes/KubernetesLookup.java | 137 ++++++++++++----
.../log4j/kubernetes/KubernetesLookupTest.java | 98 ++++++++++++
.../src/test/resources/clusterPod.json | 177 +++++++++++++++++++++
log4j-kubernetes/src/test/resources/localPod.json | 141 ++++++++++++++++
.../docker/app-compose.yml | 2 +-
.../docker/combined-compose.yml | 86 ++++++++++
.../docker/restartApp.sh | 2 +-
.../k8s/sampleapp-deployment.yaml | 33 ++--
.../config/sample/controller/K8SController.java | 71 +++++++++
.../src/main/resources/application.yml | 2 +-
14 files changed, 817 insertions(+), 62 deletions(-)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
index dd7525c..e393d4c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
@@ -39,7 +39,7 @@ public class ConfigurationScheduler extends AbstractLifeCycle {
private static final String SIMPLE_NAME = "Log4j2 " + ConfigurationScheduler.class.getSimpleName();
private static final int MAX_SCHEDULED_ITEMS = 5;
- private ScheduledExecutorService executorService;
+ private volatile ScheduledExecutorService executorService;
private int scheduledItems = 0;
private final String name;
@@ -193,17 +193,21 @@ public class ConfigurationScheduler extends AbstractLifeCycle {
private ScheduledExecutorService getExecutorService() {
if (executorService == null) {
- if (scheduledItems > 0) {
- LOGGER.debug("{} starting {} threads", name, scheduledItems);
- scheduledItems = Math.min(scheduledItems, MAX_SCHEDULED_ITEMS);
- final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(scheduledItems,
- Log4jThreadFactory.createDaemonThreadFactory("Scheduled"));
- executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
- executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
- this.executorService = executor;
+ synchronized (this) {
+ if (executorService == null) {
+ if (scheduledItems > 0) {
+ LOGGER.debug("{} starting {} threads", name, scheduledItems);
+ scheduledItems = Math.min(scheduledItems, MAX_SCHEDULED_ITEMS);
+ final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(scheduledItems,
+ Log4jThreadFactory.createDaemonThreadFactory("Scheduled"));
+ executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+ executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ this.executorService = executor;
- } else {
- LOGGER.debug("{}: No scheduled items", name);
+ } else {
+ LOGGER.debug("{}: No scheduled items", name);
+ }
+ }
}
}
return executorService;
diff --git a/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java b/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java
index c7bd4d5..f09df6e 100644
--- a/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java
+++ b/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java
@@ -53,6 +53,8 @@ public class DockerLookup extends AbstractLookup {
}
if (baseUri == null) {
LOGGER.warn("No Docker URI provided. Docker information is unavailable");
+ container = null;
+ return;
}
Container current = null;
try {
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java
new file mode 100644
index 0000000..e414045
--- /dev/null
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/ContainerUtil.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kubernetes;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Locate the current docker container.
+ */
+public class ContainerUtil {
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private static final int MAXLENGTH = 65;
+
+/**
+ * Returns the container id when running in a Docker container.
+ *
+ * This inspects /proc/self/cgroup looking for a Kubernetes Control Group. Once it finds one it attempts
+ * to isolate just the docker container id. There doesn't appear to be a standard way to do this, but
+ * it seems to be the only way to determine what the current container is in a multi-container pod. It would have
+ * been much nicer if Kubernetes would just put the container id in a standard environment variable.
+ *
+ * @see <a href="http://stackoverflow.com/a/25729598/12916">Stackoverflow</a> for a discussion on retrieving the containerId.
+ * @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>
+ * for the original version of this. Not much is actually left but it provided good inspiration.
+ */
+ public static String getContainerId() {
+ try {
+ File file = new File("/proc/self/cgroup");
+ if (file.exists()) {
+ Path path = file.toPath();
+ String id = Files.lines(path).map(ContainerUtil::getContainerId).filter(Objects::nonNull)
+ .findFirst().orElse(null);
+ LOGGER.debug("Found container id {}", id);
+ return id;
+ } else {
+ LOGGER.warn("Unable to access container information");
+ }
+ } catch (IOException ioe) {
+ LOGGER.warn("Error obtaining container id: {}", ioe.getMessage());
+ }
+ return null;
+ }
+
+ private static String getContainerId(String line) {
+ // Every control group in Kubernetes will use
+ if (line.contains("/kubepods")) {
+ // Strip off everything up to the last slash.
+ int i = line.lastIndexOf('/');
+ if (i < 0) {
+ return null;
+ }
+ // If the remainder has a period then take everything up to it.
+ line = line.substring(i + 1);
+ i = line.lastIndexOf('.');
+ if (i > 0) {
+ line = line.substring(0, i);
+ }
+ // Everything ending with a '/' has already been stripped but the remainder might start with "docker-"
+ if (line.contains("docker-")) {
+ // 8:cpuset:/kubepods.slice/kubepods-pod9c26dfb6_b9c9_11e7_bfb9_02c6c1fc4861.slice/docker-3dd988081e7149463c043b5d9c57d7309e079c5e9290f91feba1cc45a04d6a5b.scope
+ i = line.lastIndexOf("docker-");
+ line = line.substring(i + 7);
+ }
+ return line.length() <= MAXLENGTH ? line : line.substring(0, MAXLENGTH);
+ }
+
+ return null;
+ }
+}
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java
index 414f9e7..79c942d 100644
--- a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java
@@ -32,11 +32,19 @@ public class KubernetesClientBuilder {
private static final Logger LOGGER = StatusLogger.getLogger();
public KubernetesClient createClient() {
- return new DefaultKubernetesClient(kubernetesClientConfig());
+ Config config = kubernetesClientConfig();
+ return config != null ? new DefaultKubernetesClient(config) : null;
}
private Config kubernetesClientConfig() {
- Config base = Config.autoConfigure(null);
+ Config base = null;
+ try {
+ base = Config.autoConfigure(null);
+ } catch (Exception ex) {
+ if (ex instanceof NullPointerException) {
+ return null;
+ }
+ }
KubernetesClientProperties props = new KubernetesClientProperties(base);
Config properties = new ConfigBuilder(base)
.withApiVersion(props.getApiVersion())
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java
index 44aa834..cc07b7d 100644
--- a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.kubernetes;
import java.net.URL;
import java.nio.file.Paths;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -57,50 +58,99 @@ public class KubernetesLookup extends AbstractLookup {
private static Lock initLock = new ReentrantLock();
private static boolean isSpringIncluded =
LoaderUtil.isClassAvailable("org.apache.logging.log4j.spring.cloud.config.client.SpringEnvironmentHolder");
+ private Pod pod;
+ private Namespace namespace;
+ private URL masterUrl;
+ public KubernetesLookup() {
+ this.pod = null;
+ this.namespace = null;
+ this.masterUrl = null;
+ initialize();
+ }
+
+ KubernetesLookup(Pod pod, Namespace namespace, URL masterUrl) {
+ this.pod = pod;
+ this.namespace = namespace;
+ this.masterUrl = masterUrl;
+ initialize();
+ }
private boolean initialize() {
if (kubernetesInfo == null || (isSpringIncluded && !kubernetesInfo.isSpringActive)) {
initLock.lock();
boolean isSpringActive = isSpringActive();
if (kubernetesInfo == null || (!kubernetesInfo.isSpringActive && isSpringActive)) {
try {
- KubernetesClient client = new KubernetesClientBuilder().createClient();
- if (client != null) {
- KubernetesInfo info = new KubernetesInfo();
- info.isSpringActive = isSpringActive;
- info.hostName = getHostname();
- Pod pod = getCurrentPod(info.hostName, client);
- if (pod != null) {
- info.app = pod.getMetadata().getLabels().get("app");
- final String app = info.app != null ? info.app : "";
- info.podTemplateHash = pod.getMetadata().getLabels().get("pod-template-hash");
- info.accountName = pod.getSpec().getServiceAccountName();
- info.clusterName = pod.getMetadata().getClusterName();
- info.hostIp = pod.getStatus().getHostIP();
- info.labels = pod.getMetadata().getLabels();
- info.podId = pod.getMetadata().getUid();
- info.podIp = pod.getStatus().getPodIP();
- info.podName = pod.getMetadata().getName();
- Container container = pod.getSpec().getContainers().stream()
- .filter(c -> c.getName().equals(app)).findFirst().orElse(null);
- if (container != null) {
- info.containerName = container.getName();
- info.imageName = container.getImage();
- }
+ KubernetesInfo info = new KubernetesInfo();
+ KubernetesClient client = null;
+ info.isSpringActive = isSpringActive;
+ if (pod == null) {
+ client = new KubernetesClientBuilder().createClient();
+ if (client != null) {
+ pod = getCurrentPod(System.getenv(HOSTNAME), client);
info.masterUrl = client.getMasterUrl();
- info.namespace = pod.getMetadata().getNamespace();
- Namespace namespace = client.namespaces().withName(info.namespace).get();
- if (namespace != null) {
- info.namespaceId = namespace.getMetadata().getUid();
+ if (pod != null) {
+ info.namespace = pod.getMetadata().getNamespace();
+ namespace = namespace = client.namespaces().withName(info.namespace).get();
}
- ContainerStatus containerStatus = pod.getStatus().getContainerStatuses().stream()
- .filter(cs -> cs.getName().equals(app)).findFirst().orElse(null);
- if (containerStatus != null) {
- info.containerId = containerStatus.getContainerID();
- info.imageId = containerStatus.getImageID();
+ } else {
+ LOGGER.warn("Kubernetes is not available for access");
+ }
+ } else {
+ info.masterUrl = masterUrl;
+ }
+ if (pod != null) {
+ if (namespace != null) {
+ info.namespaceId = namespace.getMetadata().getUid();
+ info.namespaceAnnotations = namespace.getMetadata().getAnnotations();
+ info.namespaceLabels = namespace.getMetadata().getLabels();
+ }
+ info.app = pod.getMetadata().getLabels().get("app");
+ info.hostName = pod.getSpec().getNodeName();
+ info.annotations = pod.getMetadata().getAnnotations();
+ final String app = info.app != null ? info.app : "";
+ info.podTemplateHash = pod.getMetadata().getLabels().get("pod-template-hash");
+ info.accountName = pod.getSpec().getServiceAccountName();
+ info.clusterName = pod.getMetadata().getClusterName();
+ info.hostIp = pod.getStatus().getHostIP();
+ info.labels = pod.getMetadata().getLabels();
+ info.podId = pod.getMetadata().getUid();
+ info.podIp = pod.getStatus().getPodIP();
+ info.podName = pod.getMetadata().getName();
+ ContainerStatus containerStatus = null;
+ List<ContainerStatus> statuses = pod.getStatus().getContainerStatuses();
+ if (statuses.size() == 1) {
+ containerStatus = statuses.get(0);
+ } else if (statuses.size() > 1) {
+ String containerId = ContainerUtil.getContainerId();
+ if (containerId != null) {
+ containerStatus = statuses.stream()
+ .filter(cs -> cs.getContainerID().contains(containerId))
+ .findFirst().orElse(null);
}
- kubernetesInfo = info;
}
+ final String containerName;
+ if (containerStatus != null) {
+ info.containerId = containerStatus.getContainerID();
+ info.imageId = containerStatus.getImageID();
+ containerName = containerStatus.getName();
+ } else {
+ containerName = null;
+ }
+ Container container = null;
+ List<Container> containers = pod.getSpec().getContainers();
+ if (containers.size() == 1) {
+ container = containers.get(0);
+ } else if (containers.size() > 1 && containerName != null) {
+ container = containers.stream().filter(c -> c.getName().equals(containerName))
+ .findFirst().orElse(null);
+ }
+ if (container != null) {
+ info.containerName = container.getName();
+ info.imageName = container.getImage();
+ }
+
+ kubernetesInfo = info;
}
} finally {
initLock.unlock();
@@ -112,13 +162,16 @@ public class KubernetesLookup extends AbstractLookup {
@Override
public String lookup(LogEvent event, String key) {
- if (!initialize()) {
+ if (kubernetesInfo == null) {
return null;
}
switch (key) {
case "accountName": {
return kubernetesInfo.accountName;
}
+ case "annotations": {
+ return kubernetesInfo.annotations.toString();
+ }
case "containerId": {
return kubernetesInfo.containerId;
}
@@ -146,9 +199,15 @@ public class KubernetesLookup extends AbstractLookup {
case "masterUrl": {
return kubernetesInfo.masterUrl.toString();
}
+ case "namespaceAnnotations": {
+ return kubernetesInfo.namespaceAnnotations.toString();
+ }
case "namespaceId": {
return kubernetesInfo.namespaceId;
}
+ case "namespaceLabels": {
+ return kubernetesInfo.namespaceLabels.toString();
+ }
case "namespaceName": {
return kubernetesInfo.namespace;
}
@@ -172,6 +231,13 @@ public class KubernetesLookup extends AbstractLookup {
}
}
+ /**
+ * For unit testing only.
+ */
+ void clearInfo() {
+ kubernetesInfo = null;
+ }
+
private String getHostname() {
return System.getenv(HOSTNAME);
}
@@ -201,6 +267,7 @@ public class KubernetesLookup extends AbstractLookup {
private static class KubernetesInfo {
boolean isSpringActive;
String accountName;
+ Map<String, String> annotations;
String app;
String clusterName;
String containerId;
@@ -212,7 +279,9 @@ public class KubernetesLookup extends AbstractLookup {
Map<String, String> labels;
URL masterUrl;
String namespace;
+ Map<String, String> namespaceAnnotations;
String namespaceId;
+ Map<String, String> namespaceLabels;
String podId;
String podIp;
String podName;
diff --git a/log4j-kubernetes/src/test/java/org/apache/logging/log4j/kubernetes/KubernetesLookupTest.java b/log4j-kubernetes/src/test/java/org/apache/logging/log4j/kubernetes/KubernetesLookupTest.java
new file mode 100644
index 0000000..7174596
--- /dev/null
+++ b/log4j-kubernetes/src/test/java/org/apache/logging/log4j/kubernetes/KubernetesLookupTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kubernetes;
+
+import java.io.File;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.ObjectMeta;
+import io.fabric8.kubernetes.api.model.Pod;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Validate the Kubernetes Lookup.
+ */
+public class KubernetesLookupTest {
+
+ private static final String localJson = "target/test-classes/localPod.json";
+ private static final String clusterJson = "target/test-classes/clusterPod.json";
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+ public static URL masterUrl;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ masterUrl = new URL("http://localhost:443/");
+ }
+
+ @Test
+ public void testLocal() throws Exception {
+ Pod pod = objectMapper.readValue(new File(localJson), Pod.class);
+ Namespace namespace = createNamespace();
+ KubernetesLookup lookup = new KubernetesLookup(pod, namespace, masterUrl);
+ try {
+ assertEquals("Incorrect container name", "sampleapp", lookup.lookup("containerName"));
+ assertEquals("Incorrect container id",
+ "docker://818b0098946c67e6ac56cb7c0934b7c2a9f50feb7244b422b2a7f566f7e5d0df",
+ lookup.lookup("containerId"));
+ assertEquals("Incorrect host name", "docker-desktop", lookup.lookup("host"));
+ assertEquals("Incorrect pod name", "sampleapp-584f99476d-mnrp4", lookup.lookup("podName"));
+ } finally {
+ lookup.clearInfo();;
+ }
+ }
+
+ @Test
+ public void testCluster() throws Exception {
+ Pod pod = objectMapper.readValue(new File(clusterJson), Pod.class);
+ Namespace namespace = createNamespace();
+ KubernetesLookup lookup = new KubernetesLookup(pod, namespace, masterUrl);
+ try {
+ assertEquals("Incorrect container name", "platform-forms-service", lookup.lookup("containerName"));
+ assertEquals("Incorrect container id",
+ "docker://2b7c2a93dfb48334aa549e29fdd38039ddd256eec43ba64c145fa4b75a1542f0",
+ lookup.lookup("containerId"));
+ assertEquals("Incorrect host name", "k8s-tmpcrm-worker-s03-04", lookup.lookup("host"));
+ assertEquals("Incorrect pod name", "platform-forms-service-primary-5ddfc4f9b8-kfpzv", lookup.lookup("podName"));
+ } finally {
+ lookup.clearInfo();
+ }
+ }
+
+ private Namespace createNamespace() {
+ Namespace namespace = new Namespace();
+ ObjectMeta meta = new ObjectMeta();
+ Map<String, String> annotations = new HashMap<>();
+ annotations.put("test", "name");
+ meta.setAnnotations(annotations);
+ Map<String, String> labels = new HashMap<>();
+ labels.put("ns", "my-namespace");
+ meta.setLabels(labels);
+ meta.setUid(UUID.randomUUID().toString());
+ namespace.setMetadata(meta);
+ return namespace;
+ }
+}
diff --git a/log4j-kubernetes/src/test/resources/clusterPod.json b/log4j-kubernetes/src/test/resources/clusterPod.json
new file mode 100644
index 0000000..7bae9c3
--- /dev/null
+++ b/log4j-kubernetes/src/test/resources/clusterPod.json
@@ -0,0 +1,177 @@
+{
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "annotations": {
+ "cni.projectcalico.org/podIP": "172.16.55.101/32",
+ "cni.projectcalico.org/podIPs": "172.16.55.101/32",
+ "flagger-id": "94d53b7b-cc06-41b3-bbac-a2d14a16d95d",
+ "prometheus.io/port": "9797",
+ "prometheus.io/scrape": "true"
+ },
+ "creationTimestamp": "2020-06-15T15:44:16Z",
+ "generateName": "platform-forms-service-primary-5ddfc4f9b8-",
+ "labels": {
+ "app": "platform-forms-service-primary",
+ "pod-template-hash": "5ddfc4f9b8"
+ },
+ "name": "platform-forms-service-primary-5ddfc4f9b8-kfpzv",
+ "namespace": "default",
+ "ownerReferences": [
+ {
+ "apiVersion": "apps/v1",
+ "kind": "ReplicaSet",
+ "blockOwnerDeletion": true,
+ "controller": true,
+ "name": "platform-forms-service-primary-5ddfc4f9b8",
+ "uid": "d2e89c56-7623-439e-a9ee-4a67e2f3a81a"
+ }],
+ "resourceVersion": "37382150",
+ "selfLink": "/api/v1/namespaces/default/pods/platform-forms-service-primary-5ddfc4f9b8-kfpzv",
+ "uid": "df8cbac1-129c-4cd3-b5bc-65d72d8ba5f0"
+ },
+ "spec": {
+ "containers": [
+ {
+ "env": [
+ {
+ "name": "APACHE_ENV",
+ "value": "tmpcrm"
+ },
+ {
+ "name": "SPRING_PROFILES_ACTIVE",
+ "value": "tmpcrm"
+ },
+ {
+ "name": "JAVA_OPTS",
+ "value": "-Dlogging.label=crm"
+ }],
+ "image": "docker.apache.xyz/platform-forms-service:0.15.0",
+ "imagePullPolicy": "Always",
+ "livenessProbe": {
+ "failureThreshold": 3,
+ "httpGet": {
+ "path": "/info",
+ "port": "http",
+ "scheme": "HTTP"
+ },
+ "periodSeconds": 10,
+ "successThreshold": 1,
+ "timeoutSeconds": 1
+ },
+ "name": "platform-forms-service",
+ "ports": [
+ {
+ "containerPort": 8080,
+ "name": "http",
+ "protocol": "TCP"
+ }],
+ "readinessProbe": {
+ "failureThreshold": 3,
+ "httpGet": {
+ "path": "/health",
+ "port": "http",
+ "scheme": "HTTP"
+ },
+ "periodSeconds": 10,
+ "successThreshold": 1,
+ "timeoutSeconds": 1
+ },
+ "resources": {
+ },
+ "securityContext": {
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "terminationMessagePolicy": "File",
+ "volumeMounts": [
+ {
+ "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
+ "name": "default-token-2nqlw",
+ "readOnly": true
+ }]
+ }],
+ "dnsPolicy": "ClusterFirst",
+ "enableServiceLinks": true,
+ "nodeName": "k8s-tmpcrm-worker-s03-04",
+ "priority": 0,
+ "restartPolicy": "Always",
+ "schedulerName": "default-scheduler",
+ "securityContext": {
+ },
+ "serviceAccount": "default",
+ "serviceAccountName": "default",
+ "terminationGracePeriodSeconds": 30,
+ "tolerations": [
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/not-ready",
+ "operator": "Exists",
+ "tolerationSeconds": 300
+ },
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/unreachable",
+ "operator": "Exists",
+ "tolerationSeconds": 300
+ }],
+ "volumes": [
+ {
+ "name": "default-token-2nqlw",
+ "secret": {
+ "defaultMode": 420,
+ "secretName": "default-token-2nqlw"
+ }
+ }]
+ },
+ "status": {
+ "conditions": [
+ {
+ "lastTransitionTime": "2020-06-15T15:44:16Z",
+ "status": "True",
+ "type": "Initialized"
+ },
+ {
+ "lastTransitionTime": "2020-06-15T15:44:46Z",
+ "status": "True",
+ "type": "Ready"
+ },
+ {
+ "lastTransitionTime": "2020-06-15T15:44:46Z",
+ "status": "True",
+ "type": "ContainersReady"
+ },
+ {
+ "lastTransitionTime": "2020-06-15T15:44:16Z",
+ "status": "True",
+ "type": "PodScheduled"
+ }],
+ "containerStatuses": [
+ {
+ "containerID": "docker://2b7c2a93dfb48334aa549e29fdd38039ddd256eec43ba64c145fa4b75a1542f0",
+ "image": "docker.apache.xyz/platform-forms-service:0.15.0",
+ "imageID":
+ "docker-pullable://docker.apache.xyz/platform-forms-service@sha256:45fd19ccd99e218a7685c4cee5bc5b16aeae1cdb8e8773f9c066d4cfb22ee195",
+ "lastState": {
+ },
+ "name": "platform-forms-service",
+ "ready": true,
+ "restartCount": 0,
+ "state": {
+ "running": {
+ "startedAt": "2020-06-15T15:44:21Z"
+ }
+ },
+ "started": true
+ }],
+ "hostIP": "10.103.220.170",
+ "phase": "Running",
+ "podIP": "172.16.55.101",
+ "qosClass": "BestEffort",
+ "startTime": "2020-06-15T15:44:16Z",
+ "podIPs": [
+ {
+ "ip": "172.16.55.101"
+ }]
+ }
+}
+
diff --git a/log4j-kubernetes/src/test/resources/localPod.json b/log4j-kubernetes/src/test/resources/localPod.json
new file mode 100644
index 0000000..3aeef46
--- /dev/null
+++ b/log4j-kubernetes/src/test/resources/localPod.json
@@ -0,0 +1,141 @@
+{
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "creationTimestamp": "2020-06-14T21:50:09Z",
+ "generateName": "sampleapp-584f99476d-",
+ "labels": {
+ "app": "sampleapp",
+ "pod-template-hash": "584f99476d"
+ },
+ "name": "sampleapp-584f99476d-mnrp4",
+ "namespace": "default",
+ "ownerReferences": [
+ {
+ "apiVersion": "apps/v1",
+ "kind": "ReplicaSet",
+ "blockOwnerDeletion": true,
+ "controller": true,
+ "name": "sampleapp-584f99476d",
+ "uid": "d68146d1-17c4-486e-aa8d-07d7d5d38b94"
+ }],
+ "resourceVersion": "1200430",
+ "selfLink": "/api/v1/namespaces/default/pods/sampleapp-584f99476d-mnrp4",
+ "uid": "9213879a-479c-42ce-856b-7e2666d21829"
+ },
+ "spec": {
+ "containers": [
+ {
+ "env": [
+ {
+ "name": "JAVA_OPTS",
+ "value": "-Delastic.search.host=host.docker.internal"
+ }],
+ "image": "localhost:5000/sampleapp:latest",
+ "imagePullPolicy": "Always",
+ "name": "sampleapp",
+ "ports": [
+ {
+ "containerPort": 8080,
+ "protocol": "TCP"
+ },
+ {
+ "containerPort": 5005,
+ "protocol": "TCP"
+ }],
+ "resources": {
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "terminationMessagePolicy": "File",
+ "volumeMounts": [
+ {
+ "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
+ "name": "default-token-jzq7d",
+ "readOnly": true
+ }]
+ }],
+ "dnsPolicy": "ClusterFirst",
+ "nodeName": "docker-desktop",
+ "priority": 0,
+ "restartPolicy": "Always",
+ "schedulerName": "default-scheduler",
+ "securityContext": {
+ },
+ "serviceAccount": "default",
+ "serviceAccountName": "default",
+ "terminationGracePeriodSeconds": 30,
+ "tolerations": [
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/not-ready",
+ "operator": "Exists",
+ "tolerationSeconds": 300
+ },
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/unreachable",
+ "operator": "Exists",
+ "tolerationSeconds": 300
+ }],
+ "volumes": [
+ {
+ "name": "default-token-jzq7d",
+ "secret": {
+ "defaultMode": 420,
+ "secretName": "default-token-jzq7d"
+ }
+ }],
+ "enableServiceLinks": true
+ },
+ "status": {
+ "conditions": [
+ {
+ "lastTransitionTime": "2020-06-14T21:50:09Z",
+ "status": "True",
+ "type": "Initialized"
+ },
+ {
+ "lastTransitionTime": "2020-06-14T21:50:10Z",
+ "status": "True",
+ "type": "Ready"
+ },
+ {
+ "lastTransitionTime": "2020-06-14T21:50:10Z",
+ "status": "True",
+ "type": "ContainersReady"
+ },
+ {
+ "lastTransitionTime": "2020-06-14T21:50:09Z",
+ "status": "True",
+ "type": "PodScheduled"
+ }],
+ "containerStatuses": [
+ {
+ "containerID": "docker://818b0098946c67e6ac56cb7c0934b7c2a9f50feb7244b422b2a7f566f7e5d0df",
+ "image": "sampleapp:latest",
+ "imageID":
+ "docker-pullable://localhost:5000/sampleapp@sha256:3cefb2db514db73c69854fee8abd072f27240519432d08aad177a57ee34b7d39",
+ "lastState": {
+ },
+ "name": "sampleapp",
+ "ready": true,
+ "restartCount": 0,
+ "state": {
+ "running": {
+ "startedAt": "2020-06-14T21:50:10Z"
+ }
+ },
+ "started": true
+ }],
+ "hostIP": "192.168.65.3",
+ "phase": "Running",
+ "podIP": "10.1.0.47",
+ "qosClass": "BestEffort",
+ "startTime": "2020-06-14T21:50:09Z",
+ "podIPs": [
+ {
+ "ip": "10.1.0.47"
+ }]
+ }
+}
+
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/app-compose.yml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/app-compose.yml
index 01cb293..9864e8e 100755
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/app-compose.yml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/app-compose.yml
@@ -8,7 +8,7 @@ services:
SERVICE_PARAMS: --spring.config.location=classpath:/,classpath:/application-local-docker.yml
ports:
- "5005:5005"
- - "8080:4567"
+ - "8080:8080"
networks:
sample_network:
aliases:
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/combined-compose.yml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/combined-compose.yml
new file mode 100755
index 0000000..b2f5abb
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/combined-compose.yml
@@ -0,0 +1,86 @@
+version: "3"
+services:
+ socat:
+ container_name: socat
+ image: bobrik/socat
+ command: TCP-LISTEN:1234,fork UNIX-CONNECT:/var/run/docker.sock
+ expose:
+ - "1234"
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ networks:
+ sample_network:
+ aliases:
+ - socat
+
+ rabbitmq:
+ container_name: rabbit
+ image: rabbitmq:3-management-alpine
+ expose:
+ - "5672"
+ - "15672"
+ ports:
+ - "5672:5672"
+ - "15672:15672"
+ volumes:
+ - ./init/rabbit/rabbitmq.config:/etc/rabbitmq/rabbitmq.config:ro
+ - ./init/rabbit/definitions.json:/etc/rabbitmq/definitions.json:ro
+ networks:
+ sample_network:
+ aliases:
+ - rabbitmq
+
+ fluent-bit:
+ container_name: fluent-bit
+ image: fluent/fluent-bit:latest
+ expose:
+ - "2020"
+ - "24221"
+ - "24224"
+ ports:
+ - "24224:24224"
+ volumes:
+ - ./init/fluent-bit/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
+ - ./target/logs:/var/logs
+ networks:
+ sample_network:
+ aliases:
+ - fluent-bit
+
+ flume:
+ container_name: flume
+ image: probablyfine/flume:latest
+ expose:
+ - "5050"
+ environment:
+ FLUME_AGENT_NAME: forwarder
+ FLUME_JAVA_OPTS: -Dlog4j.configuration=file:///opt/flume-config/log4j.properties
+ volumes:
+ - ./init/flume/start-flume.sh:/opt/flume/bin/start-flume
+ - ./init/flume/flume.conf:/opt/flume-config/flume.conf
+ - ./init/flume/flume-env.sh:/opt/flume-config/flume-env.sh
+ - ./init/flume/log4j.properties:/opt/flume-config/log4j.properties
+ - ~/flume-logs:/var/log/flume
+ networks:
+ sample_network:
+ aliases:
+ - flume
+
+ sampleapp:
+ container_name: sampleapp
+ image: sampleapp
+ environment:
+ DOCKER_URI: http://socat:1234
+ SERVICE_PARAMS: --spring.config.location=classpath:/,classpath:/application-local-docker.yml
+ ports:
+ - "5005:5005"
+ - "8080:8080"
+ networks:
+ sample_network:
+ aliases:
+ - sampleapp
+networks:
+ sample_network:
+
+volumes:
+ pgdata:
\ No newline at end of file
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/restartApp.sh b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/restartApp.sh
index 397d5a3..6bb6fac 100755
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/restartApp.sh
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/docker/restartApp.sh
@@ -23,7 +23,7 @@ containerName=app-container
networkName=docker_sample_network
debug_port=5005
#debug_expose="-p $debug_port:$debug_port"
-exposed_ports="-p 8080:4567 $debug_expose"
+exposed_ports="-p 8080:8080 $debug_expose"
mvn clean package -DskipTests=true
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml
index fe5d2b7..ffd2851 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml
@@ -15,30 +15,39 @@ spec:
app: sampleapp
spec:
containers:
- - name: sampleapp
- image: localhost:5000/sampleapp:latest
- imagePullPolicy: Always
- ports:
- - containerPort: 8080
- - containerPort: 5005
- env:
- - name: JAVA_OPTS
- value: "-Delastic.search.host=host.docker.internal"
+ - name: sampleapp
+ image: localhost:5000/sampleapp:latest
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 8080
+ - containerPort: 5005
+ env:
+ - name: JAVA_OPTS
+ value: "-Delastic.search.host=host.docker.internal"
+ - name: key-value-store
+ image: redis
+ ports:
+ - containerPort: 6379
+
+
---
apiVersion: v1
kind: Service
metadata:
name: sampleapp
spec:
- type: NodePort
selector:
app: sampleapp
ports:
- protocol: TCP
port: 8080
- nodePort: 30011
+ targetPort: 8080
name: http
- protocol: TCP
+ port: 6379
+ targetPort: 6379
+ name: redis
+ - protocol: TCP
port: 5005
- nodePort: 30012
+ targetPort: 5005
name: debug
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/java/org/apache/logging/log4j/spring/cloud/config/sample/controller/K8SController.java b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/java/org/apache/logging/log4j/spring/cloud/config/sample/controller/K8SController.java
new file mode 100644
index 0000000..5059a49
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/java/org/apache/logging/log4j/spring/cloud/config/sample/controller/K8SController.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Nextiva, Inc. to Present.
+ * All rights reserved.
+ */
+
+package org.apache.logging.log4j.spring.cloud.config.sample.controller;
+
+import java.nio.file.Paths;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.kubernetes.KubernetesClientBuilder;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+/**
+ * Test class
+ */
+@RestController
+public class K8SController {
+
+ private static final Logger LOGGER = LogManager.getLogger(K8SController.class);
+ private static final String HOSTNAME = "HOSTNAME";
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @GetMapping("/k8s/pod")
+ public ResponseEntity<Pod> getPod() {
+ try {
+ KubernetesClient client = new KubernetesClientBuilder().createClient();
+ if (client != null) {
+ Pod pod = getCurrentPod(client);
+ if (pod != null) {
+ LOGGER.info("Pod: {}", objectMapper.writeValueAsString(pod));
+ return new ResponseEntity<>(pod, HttpStatus.OK);
+ }
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Unable to obtain or print Pod information", ex);
+ }
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ private Pod getCurrentPod(KubernetesClient kubernetesClient) {
+ String hostName = System.getenv(HOSTNAME);
+ try {
+ if (isServiceAccount() && Strings.isNotBlank(hostName)) {
+ return kubernetesClient.pods().withName(hostName).get();
+ }
+ } catch (Throwable t) {
+ LOGGER.debug("Unable to locate pod with name {}.", hostName);
+ }
+ return null;
+ }
+
+ private boolean isServiceAccount() {
+ return Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH).toFile().exists()
+ && Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH).toFile().exists();
+ }
+
+}
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml
index 7e9838e..4c6bb12 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml
@@ -1,5 +1,5 @@
server:
- port: 4567
+ port: 8080
servlet:
context-path: /sample