This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/master by this push:
     new 1ebdfc1  LOG4J2-2716 - Add the ability to lookup Kubernetes attributes 
in the Log4j configuration. Allow Log4j properties to be retrieved from the 
Spring environment if it is available.
1ebdfc1 is described below

commit 1ebdfc1ec9c8ef602a6aa60306e0ab436c7d2435
Author: Ralph Goers <[email protected]>
AuthorDate: Mon Oct 28 11:03:18 2019 -0700

    LOG4J2-2716 - Add the ability to lookup Kubernetes attributes in the Log4j 
configuration. Allow Log4j properties to be retrieved from the Spring 
environment if it is available.
---
 .../java/org/apache/logging/log4j/LogManager.java  |   2 +-
 .../logging/log4j/spi/LoggerContextFactory.java    |   5 +-
 .../apache/logging/log4j/util/PropertiesUtil.java  | 150 ++++++++++++++
 .../apache/logging/log4j/util/PropertySource.java  |  28 ++-
 .../log4j/core/impl/Log4jContextFactory.java       |   2 +-
 .../logging/log4j/core/lookup/Interpolator.java    |  15 ++
 .../log4j/core/osgi/BundleContextSelector.java     |   8 +-
 .../log4j/core/selector/BasicContextSelector.java  |   3 +-
 .../core/selector/ClassLoaderContextSelector.java  |  11 +-
 .../log4j/core/selector/ContextSelector.java       |   4 +-
 .../log4j/core/selector/JndiContextSelector.java   |  15 +-
 log4j-kubernetes/pom.xml                           | 207 +++++++++++++++++++
 .../log4j/kubernetes/KubernetesClientBuilder.java  |  67 +++++++
 .../kubernetes/KubernetesClientProperties.java     | 191 ++++++++++++++++++
 .../logging/log4j/kubernetes/KubernetesLookup.java | 221 +++++++++++++++++++++
 log4j-kubernetes/src/site/markdown/index.md.vm     | 104 ++++++++++
 log4j-kubernetes/src/site/site.xml                 |  52 +++++
 .../client/Log4j2CloudConfigLoggingSystem.java     |   5 +-
 .../cloud/config/client/Log4j2EventListener.java   |   1 -
 ...ingLookup.java => SpringEnvironmentHolder.java} |  40 ++--
 .../spring/cloud/config/client/SpringLookup.java   |  13 +-
 ...SpringLookup.java => SpringPropertySource.java} |  34 ++--
 .../Dockerfile                                     |  19 +-
 .../k8s/deploy.sh                                  |  36 ++++
 .../k8s/sampleapp-deployment.yaml                  |  44 ++++
 .../k8s/undeploy.sh                                |  29 +++
 .../pom.xml                                        |   5 +
 .../src/main/resources/application.yml             |   5 +-
 .../src/main/config-repo/log4j2.xml                |  65 +++++-
 pom.xml                                            |  28 +++
 src/changes/changes.xml                            |   4 +
 src/site/asciidoc/manual/lookups.adoc              |  54 ++++-
 src/site/markdown/manual/cloud.md                  |  37 +++-
 33 files changed, 1408 insertions(+), 96 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
index 2da1e84..45b83ff 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
@@ -404,7 +404,7 @@ public class LogManager {
      *            used and if the caller is a class in the container's 
classpath then a different LoggerContext may
      *            be used.
      * @param allContexts if true all LoggerContexts that can be located will 
be shutdown.
-     * @since 3.0
+     * @since 2.13.0
      */
     public static void shutdown(final boolean currentContext, final boolean 
allContexts) {
         factory.shutdown(FQCN, null, currentContext, allContexts);
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
index 14aaa37..3dcee76 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
@@ -31,8 +31,7 @@ public interface LoggerContextFactory {
      * @param currentContext If true shuts down the current Context, if false 
shuts down the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @param allContexts if true all LoggerContexts that can be located will 
be shutdown.
-     * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     default void shutdown(String fqcn, ClassLoader loader, boolean 
currentContext, boolean allContexts) {
         if (hasContext(fqcn, loader, currentContext)) {
@@ -50,7 +49,7 @@ public interface LoggerContextFactory {
      * @param currentContext If true returns the current Context, if false 
returns the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     default boolean hasContext(String fqcn, ClassLoader loader, boolean 
currentContext) {
         return false;
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index 4feb207..6dd01b7 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -19,6 +19,9 @@ package org.apache.logging.log4j.util;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.Charset;
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -155,6 +158,24 @@ public final class PropertiesUtil {
     }
 
     /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the 
value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Boolean getBooleanProperty(final String[] prefixes, String key, 
Supplier<Boolean> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getBooleanProperty(prefix + key);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
      * Gets the named property as a Charset value.
      *
      * @param name the name of the property to look up
@@ -232,6 +253,24 @@ public final class PropertiesUtil {
     }
 
     /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the 
value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Integer getIntegerProperty(final String[] prefixes, String key, 
Supplier<Integer> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getIntegerProperty(prefix + key, 0);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
      * Gets the named property as a long.
      *
      * @param name         the name of the property to look up
@@ -249,6 +288,76 @@ public final class PropertiesUtil {
         }
         return defaultValue;
     }
+    /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the 
value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Long getLongProperty(final String[] prefixes, String key, 
Supplier<Long> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getLongProperty(prefix + key, 0);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
+     * Retrieves a Duration where the String is of the format nnn[unit] where 
nnn represents an integer value
+     * and unit represents a time unit.
+     * @param name The property name.
+     * @param defaultValue The default value.
+     * @return The value of the String as a Duration or the default value, 
which may be null.
+     * @since 2.13.0
+     */
+    public Duration getDurationProperty(final String name, Duration 
defaultValue) {
+        final String prop = getStringProperty(name);
+        if (prop != null) {
+            return TimeUnit.getDuration(prop);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the 
value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Duration getDurationProperty(final String[] prefixes, String key, 
Supplier<Duration> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getDurationProperty(prefix + key, null);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the 
value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public String getStringProperty(final String[] prefixes, String key, 
Supplier<String> supplier) {
+        for (String prefix : prefixes) {
+            String result = getStringProperty(prefix + key);
+            if (result != null) {
+                return result;
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
 
     /**
      * Gets the named property as a String.
@@ -387,6 +496,11 @@ public final class PropertiesUtil {
             if (hasSystemProperty(key)) {
                 return System.getProperty(key);
             }
+            for (final PropertySource source : sources) {
+                if (source.containsProperty(key)) {
+                    return source.getProperty(key);
+                }
+            }
             return tokenized.get(PropertySource.Util.tokenize(key));
         }
 
@@ -463,4 +577,40 @@ public final class PropertiesUtil {
         return getStringProperty("os.name", "").startsWith("Windows");
     }
 
+    private enum TimeUnit {
+        NANOS("ns,nano,nanos,nanosecond,nanoseconds", ChronoUnit.NANOS),
+        MICROS("us,micro,micros,microsecond,microseconds", ChronoUnit.MICROS),
+        MILLIS("ms,milli,millis,millsecond,milliseconds", ChronoUnit.MILLIS),
+        SECONDS("s,second,seconds", ChronoUnit.SECONDS),
+        MINUTES("m,minute,minutes", ChronoUnit.MINUTES),
+        HOURS("h,hour,hours", ChronoUnit.HOURS),
+        DAYS("d,day,days", ChronoUnit.DAYS);
+
+        private final String[] descriptions;
+        private final ChronoUnit timeUnit;
+
+        TimeUnit(String descriptions, ChronoUnit timeUnit) {
+            this.descriptions = descriptions.split(",");
+            this.timeUnit = timeUnit;
+        }
+
+        ChronoUnit getTimeUnit() {
+            return this.timeUnit;
+        }
+
+        static Duration getDuration(String time) {
+            String value = time.trim();
+            TemporalUnit temporalUnit = ChronoUnit.MILLIS;
+            long timeVal = 0;
+            for (TimeUnit timeUnit : values()) {
+                for (String suffix : timeUnit.descriptions) {
+                    if (value.endsWith(suffix)) {
+                        temporalUnit = timeUnit.timeUnit;
+                        timeVal = Long.parseLong(value.substring(0, 
value.length() - suffix.length()));
+                    }
+                }
+            }
+            return Duration.of(timeVal, temporalUnit);
+        }
+    }
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
index 75399d9..77ccd4b 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
@@ -45,7 +45,8 @@ public interface PropertySource {
      *
      * @param action action to perform on each key/value pair
      */
-    void forEach(BiConsumer<String, String> action);
+    default void forEach(BiConsumer<String, String> action) {
+    }
 
     /**
      * Converts a list of property name tokens into a normal form. For 
example, a list of tokens such as
@@ -54,7 +55,30 @@ public interface PropertySource {
      * @param tokens list of property name tokens
      * @return a normalized property name using the given tokens
      */
-    CharSequence getNormalForm(Iterable<? extends CharSequence> tokens);
+    default CharSequence getNormalForm(Iterable<? extends CharSequence> 
tokens) {
+        return null;
+    }
+
+    /**
+     * For PropertySources that cannot iterate over all the potential 
properties this provides a direct lookup.
+     * @param key The key to search for.
+     * @return The value or null;
+     * @since 2.13.0
+     */
+    default String getProperty(String key) {
+        return null;
+    }
+
+
+    /**
+     * For PropertySources that cannot iterate over all the potential 
properties this provides a direct lookup.
+     * @param key The key to search for.
+     * @return The value or null;
+     * @since 2.13.0
+     */
+    default boolean containsProperty(String key) {
+        return false;
+    }
 
     /**
      * Comparator for ordering PropertySource instances by priority.
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
index e00eb29..1ca8280 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
@@ -299,7 +299,7 @@ public class Log4jContextFactory implements 
LoggerContextFactory, ShutdownCallba
      * @param currentContext If true returns the current Context, if false 
returns the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     @Override
     public boolean hasContext(String fqcn, ClassLoader loader, boolean 
currentContext) {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
index 10a63b0..7003e3f 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
@@ -40,6 +40,8 @@ public class Interpolator extends 
AbstractConfigurationAwareLookup {
 
     private static final String LOOKUP_KEY_DOCKER = "docker";
 
+    private static final String LOOKUP_KEY_KUBERNETES = "kubernetes";
+
     private static final String LOOKUP_KEY_SPRING = "spring";
 
     private static final String LOOKUP_KEY_JNDI = "jndi";
@@ -145,6 +147,14 @@ public class Interpolator extends 
AbstractConfigurationAwareLookup {
         } catch (final Exception ignored) {
             handleError(LOOKUP_KEY_SPRING, ignored);
         }
+        try {
+            strLookupMap.put(LOOKUP_KEY_KUBERNETES,
+                    
Loader.newCheckedInstanceOf("org.apache.logging.log4j.kubernetes.KubernetesLookup",
 StrLookup.class));
+        } catch (final Exception ignored) {
+            handleError(LOOKUP_KEY_KUBERNETES, ignored);
+        } catch (final NoClassDefFoundError error) {
+            handleError(LOOKUP_KEY_KUBERNETES, error);
+        }
     }
 
     public Map<String, StrLookup> getStrLookupMap() {
@@ -172,6 +182,11 @@ public class Interpolator extends 
AbstractConfigurationAwareLookup {
                 break;
             case LOOKUP_KEY_DOCKER: case LOOKUP_KEY_SPRING:
                 break;
+            case LOOKUP_KEY_KUBERNETES:
+                if (t instanceof NoClassDefFoundError) {
+                    LOGGER.warn("Unable to create Kubernetes lookup due to 
missing dependency: {}", t.getMessage());
+                }
+                break;
             default:
                 LOGGER.error("Unable to create Lookup for {}", lookupKey, t);
         }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
index 7cb433f..ba0a14e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
@@ -77,8 +77,6 @@ public class BundleContextSelector extends 
ClassLoaderContextSelector {
                 }
             }
         }
-
-
     }
 
     private LoggerContext getLoggerContext(final Bundle bundle) {
@@ -97,7 +95,7 @@ public class BundleContextSelector extends 
ClassLoaderContextSelector {
     @Override
     public boolean hasContext(final String fqcn, final ClassLoader loader, 
final boolean currentContext) {
         if (currentContext && ContextAnchor.THREAD_CONTEXT.get() != null) {
-            return true;
+            return ContextAnchor.THREAD_CONTEXT.get().isStarted();
         }
         if (loader instanceof BundleReference) {
             return hasContext(((BundleReference) loader).getBundle());
@@ -106,7 +104,7 @@ public class BundleContextSelector extends 
ClassLoaderContextSelector {
         if (callerClass != null) {
             return hasContext(FrameworkUtil.getBundle(callerClass));
         }
-        return ContextAnchor.THREAD_CONTEXT.get() != null;
+        return ContextAnchor.THREAD_CONTEXT.get() != null && 
ContextAnchor.THREAD_CONTEXT.get().isStarted();
     }
 
     @Override
@@ -134,7 +132,7 @@ public class BundleContextSelector extends 
ClassLoaderContextSelector {
     private static boolean hasContext(final Bundle bundle) {
         final String name = Objects.requireNonNull(bundle, "No Bundle 
provided").getSymbolicName();
         final AtomicReference<WeakReference<LoggerContext>> ref = 
CONTEXT_MAP.get(name);
-        return ref != null && ref.get() != null;
+        return ref != null && ref.get() != null && ref.get().get() != null && 
ref.get().get().isStarted();
     }
 
     private static LoggerContext locateContext(final Bundle bundle, final URI 
configLocation) {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
index 1006a60..aac0221 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
@@ -39,7 +39,8 @@ public class BasicContextSelector implements ContextSelector {
 
     @Override
     public boolean hasContext(String fqcn, ClassLoader loader, boolean 
currentContext) {
-        return ContextAnchor.THREAD_CONTEXT.get() != null;
+        LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
+        return ctx != null && ctx.isStarted();
     }
 
     @Override
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
index b2c7282..9a8b6c9 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
@@ -83,17 +83,20 @@ public class ClassLoaderContextSelector implements 
ContextSelector, LoggerContex
 
     @Override
     public boolean hasContext(final String fqcn, final ClassLoader loader, 
final boolean currentContext) {
+        LoggerContext ctx;
         if (currentContext) {
-            return ContextAnchor.THREAD_CONTEXT.get() != null;
+            ctx = ContextAnchor.THREAD_CONTEXT.get();
         } else if (loader != null) {
-            return findContext(loader) != null;
+            ctx = findContext(loader);
         } else {
             final Class<?> clazz = StackLocatorUtil.getCallerClass(fqcn);
             if (clazz != null) {
-                return findContext(clazz.getClassLoader()) != null;
+                ctx = findContext(clazz.getClassLoader());
+            } else {
+                ctx = ContextAnchor.THREAD_CONTEXT.get();
             }
-            return ContextAnchor.THREAD_CONTEXT.get() != null;
         }
+        return ctx != null && ctx.isStarted();
     }
 
     private LoggerContext findContext(ClassLoader loaderOrNull) {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
index 41f7d39..3eb0837 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
@@ -35,7 +35,7 @@ public interface ContextSelector {
      * @param loader The ClassLoader to use or null.
      * @param currentContext If true returns the current Context, if false 
returns the Context appropriate
      * @param allContexts if true all LoggerContexts that can be located will 
be shutdown.
-     * @since 3.0
+     * @since 2.13.0
      */
     default void shutdown(final String fqcn, final ClassLoader loader, final 
boolean currentContext,
                           final boolean allContexts) {
@@ -51,7 +51,7 @@ public interface ContextSelector {
      * @param currentContext If true returns the current Context, if false 
returns the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     default boolean hasContext(String fqcn, ClassLoader loader, boolean 
currentContext) {
         return false;
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
index 67c32ae..36571fd 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
@@ -109,14 +109,15 @@ public class JndiContextSelector implements 
NamedContextSelector {
 
     @Override
     public boolean hasContext(String fqcn, ClassLoader loader, boolean 
currentContext) {
-        if (ContextAnchor.THREAD_CONTEXT.get() != null) {
-            return true;
-        }
-        String loggingContextName = getContextName();
-        if (loggingContextName == null) {
-            return false;
+        LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
+        if (ctx == null) {
+            String loggingContextName = getContextName();
+            if (loggingContextName == null) {
+                return false;
+            }
+            ctx = CONTEXT_MAP.get(loggingContextName);
         }
-        return CONTEXT_MAP.containsKey(loggingContextName);
+        return ctx != null && ctx.isStarted();
     }
 
     @Override
diff --git a/log4j-kubernetes/pom.xml b/log4j-kubernetes/pom.xml
new file mode 100644
index 0000000..474d097
--- /dev/null
+++ b/log4j-kubernetes/pom.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging.log4j</groupId>
+    <artifactId>log4j</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+  <artifactId>log4j-kubernetes</artifactId>
+  <packaging>jar</packaging>
+  <name>Apache Log4j Kubernetes Library</name>
+  <description>Apache Log4j Kubernetes Support</description>
+  <properties>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>Log4j Kubernetes Library Documentation</docLabel>
+    <projectDir>/kubernetes</projectDir>
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+    <module.name>org.apache.logging.log4j.kubernetes</module.name>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
+    <!-- Kubernetes Client -->
+    <dependency>
+      <groupId>io.fabric8</groupId>
+      <artifactId>kubernetes-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-toolchains-plugin</artifactId>
+        <version>1.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>toolchain</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <toolchains>
+            <jdk>
+              <version>[8, )</version>
+            </jdk>
+          </toolchains>
+        </configuration>
+      </plugin>
+      <!-- Include the standard NOTICE and LICENSE -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <skip>false</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkCount>1</forkCount>
+          <reuseForks>false</reuseForks>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <version>${changes.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+          <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+          <useJql>true</useJql>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.plugin.version}</version>
+        <configuration>
+          
<!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation>
 -->
+          <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+          
<suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+          <enableRulesSummary>false</enableRulesSummary>
+          <propertyExpansion>basedir=${basedir}</propertyExpansion>
+          
<propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>${javadoc.plugin.version}</version>
+        <configuration>
+          <bottom><![CDATA[<p align="center">Copyright &#169; 
{inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
+            Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather 
logo, the Apache Logging project logo,
+            and the Apache Log4j logo are trademarks of The Apache Software 
Foundation.</p>]]></bottom>
+          <!-- module link generation is completely broken in the javadoc 
plugin for a multi-module non-aggregating
+               project -->
+          <detectOfflineLinks>false</detectOfflineLinks>
+          <linksource>true</linksource>
+        </configuration>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>javadoc</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>findbugs-maven-plugin</artifactId>
+        <version>${findbugs.plugin.version}</version>
+        <configuration>
+          <fork>true</fork>
+          <jvmArgs>-Duser.language=en</jvmArgs>
+          <threshold>Normal</threshold>
+          <effort>Default</effort>
+          
<excludeFilterFile>${log4jParentDir}/findbugs-exclude-filter.xml</excludeFilterFile>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+        <version>${jxr.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>jxr</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <reports>
+              <report>aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+        <version>${pmd.plugin.version}</version>
+        <configuration>
+          <targetJdk>${maven.compiler.target}</targetJdk>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>net.sourceforge.maven-taglib</groupId>
+        <artifactId>maven-taglib-plugin</artifactId>
+        <version>2.4</version>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
+
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
new file mode 100644
index 0000000..414f9e7
--- /dev/null
+++ 
b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java
@@ -0,0 +1,67 @@
+/*
+ * 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 org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.ConfigBuilder;
+import io.fabric8.kubernetes.client.DefaultKubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+/**
+ * Builds a Kubernetes Client.
+ */
+public class KubernetesClientBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    public KubernetesClient createClient() {
+        return new DefaultKubernetesClient(kubernetesClientConfig());
+    }
+
+    private Config kubernetesClientConfig() {
+        Config base = Config.autoConfigure(null);
+        KubernetesClientProperties props = new 
KubernetesClientProperties(base);
+        Config properties = new ConfigBuilder(base)
+                .withApiVersion(props.getApiVersion())
+                .withCaCertData(props.getCaCertData())
+                .withCaCertFile(props.getCaCertFile())
+                .withClientCertData(props.getClientCertData())
+                .withClientCertFile(props.getClientCertFile())
+                .withClientKeyAlgo(props.getClientKeyAlgo())
+                .withClientKeyData(props.getClientKeyData())
+                .withClientKeyFile(props.getClientKeyFile())
+                .withClientKeyPassphrase(props.getClientKeyPassphrase())
+                .withConnectionTimeout(props.getConnectionTimeout())
+                .withHttpProxy(props.getHttpProxy())
+                .withHttpsProxy(props.getHttpsProxy())
+                .withMasterUrl(props.getMasterUrl())
+                .withNamespace(props.getNamespace())
+                .withNoProxy(props.getNoProxy())
+                .withPassword(props.getPassword())
+                .withProxyPassword(props.getProxyPassword())
+                .withProxyUsername(props.getProxyUsername())
+                .withRequestTimeout(props.getRequestTimeout())
+                .withRollingTimeout(props.getRollingTimeout())
+                .withTrustCerts(props.isTrustCerts())
+                .withUsername(props.getUsername())
+                .build();
+        return properties;
+    }
+}
diff --git 
a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientProperties.java
 
b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientProperties.java
new file mode 100644
index 0000000..61f50e0
--- /dev/null
+++ 
b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientProperties.java
@@ -0,0 +1,191 @@
+/*
+ * 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.time.Duration;
+
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+import io.fabric8.kubernetes.client.Config;
+
+/**
+ * Obtains properties used to configure the Kubernetes client.
+ */
+public class KubernetesClientProperties {
+
+    private static final String[] PREFIXES = {"log4j2.kubernetes.client.", 
"spring.cloud.kubernetes.client."};
+    private static final String API_VERSION = "apiVersion";
+    private static final String CA_CERT_FILE = "caCertFile";
+    private static final String CA_CERT_DATA = "caCertData";
+    private static final String CLIENT_CERT_FILE = "clientCertFile";
+    private static final String CLIENT_CERT_DATA = "clientCertData";
+    private static final String CLIENT_KEY_FILE = "clientKeyFile";
+    private static final String CLIENT_KEY_DATA = "cientKeyData";
+    private static final String CLIENT_KEY_ALGO = "clientKeyAlgo";
+    private static final String CLIENT_KEY_PASSPHRASE = "clientKeyPassphrase";
+    private static final String CONNECTION_TIMEOUT = "connectionTimeout";
+    private static final String HTTP_PROXY = "httpProxy";
+    private static final String HTTPS_PROXY = "httpsProxy";
+    private static final String LOGGING_INTERVAL = "loggingInterval";
+    private static final String MASTER_URL = "masterUrl";
+    private static final String NAMESPACE = "namespace";
+    private static final String NO_PROXY = "noProxy";
+    private static final String PASSWORD = "password";
+    private static final String PROXY_USERNAME = "proxyUsername";
+    private static final String PROXY_PASSWORD = "proxyPassword";
+    private static final String REQUEST_TIMEOUT = "requestTimeout";
+    private static final String ROLLING_TIMEOUT = "rollingTimeout";
+    private static final String TRUST_CERTS = "trustCerts";
+    private static final String USERNAME = "username";
+    private static final String WATCH_RECONNECT_INTERVAL = 
"watchReconnectInterval";
+    private static final String WATCH_RECONNECT_LIMIT = "watchReconnectLimit";
+
+    private PropertiesUtil props = PropertiesUtil.getProperties();
+    private final Config base;
+
+    public KubernetesClientProperties(Config base) {
+        this.base = base;
+    }
+
+
+    public String getApiVersion() {
+        return props.getStringProperty(PREFIXES, API_VERSION, 
base::getApiVersion);
+    }
+    public String getCaCertFile() {
+        return props.getStringProperty(PREFIXES, CA_CERT_FILE, 
base::getCaCertFile);
+    }
+
+    public String getCaCertData() {
+        return props.getStringProperty(PREFIXES, CA_CERT_DATA, 
base::getCaCertData);
+    }
+
+    public String getClientCertFile() {
+        return props.getStringProperty(PREFIXES, CLIENT_CERT_FILE, 
base::getClientCertFile);
+    }
+
+    public String getClientCertData() {
+        return props.getStringProperty(PREFIXES, CLIENT_CERT_DATA, 
base::getClientCertData);
+    }
+
+    public String getClientKeyFile() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_FILE, 
base::getClientKeyFile);
+    }
+
+    public String getClientKeyData() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_DATA, 
base::getClientKeyData);
+    }
+
+    public String getClientKeyAlgo() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_ALGO, 
base::getClientKeyAlgo);
+    }
+
+    public String getClientKeyPassphrase() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_PASSPHRASE, 
base::getClientKeyPassphrase);
+    }
+
+    public int getConnectionTimeout() {
+        Duration timeout = props.getDurationProperty(PREFIXES, 
CONNECTION_TIMEOUT, null);
+        if (timeout != null) {
+            return (int) timeout.toMillis();
+        }
+        return base.getConnectionTimeout();
+    }
+
+    public String getHttpProxy() {
+        return props.getStringProperty(PREFIXES, HTTP_PROXY, 
base::getHttpProxy);
+    }
+
+    public String getHttpsProxy() {
+        return props.getStringProperty(PREFIXES, HTTPS_PROXY, 
base::getHttpsProxy);
+    }
+
+    public int getLoggingInterval() {
+        Duration interval = props.getDurationProperty(PREFIXES, 
LOGGING_INTERVAL, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getLoggingInterval();
+    }
+
+    public String getMasterUrl() {
+        return props.getStringProperty(PREFIXES, MASTER_URL, 
base::getMasterUrl);
+    }
+
+    public String getNamespace() {
+        return props.getStringProperty(PREFIXES, NAMESPACE, 
base::getNamespace);
+    }
+
+    public String[] getNoProxy() {
+        String result = props.getStringProperty(PREFIXES, NO_PROXY, null);
+        if (result != null) {
+            return result.replace("\\s", "").split(",");
+        }
+        return base.getNoProxy();
+    }
+
+    public String getPassword() {
+        return props.getStringProperty(PREFIXES, PASSWORD, base::getPassword);
+    }
+
+    public String getProxyUsername() {
+        return props.getStringProperty(PREFIXES, PROXY_USERNAME, 
base::getProxyUsername);
+    }
+
+    public String getProxyPassword() {
+        return props.getStringProperty(PREFIXES, PROXY_PASSWORD, 
base::getProxyPassword);
+    }
+
+    public int getRequestTimeout() {
+        Duration interval = props.getDurationProperty(PREFIXES, 
REQUEST_TIMEOUT, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getRequestTimeout();
+    }
+
+    public long getRollingTimeout() {
+        Duration interval = props.getDurationProperty(PREFIXES, 
ROLLING_TIMEOUT, null);
+        if (interval != null) {
+            return interval.toMillis();
+        }
+        return base.getRollingTimeout();
+    }
+
+    public Boolean isTrustCerts() {
+        return props.getBooleanProperty(PREFIXES, TRUST_CERTS, 
base::isTrustCerts);
+    }
+
+    public String getUsername() {
+        return props.getStringProperty(PREFIXES, USERNAME, base::getUsername);
+    }
+
+    public int getWatchReconnectInterval() {
+        Duration interval = props.getDurationProperty(PREFIXES, 
WATCH_RECONNECT_INTERVAL, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getWatchReconnectInterval();
+    }
+
+    public int getWatchReconnectLimit() {
+        Duration interval = props.getDurationProperty(PREFIXES, 
WATCH_RECONNECT_LIMIT, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getWatchReconnectLimit();
+    }
+}
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
new file mode 100644
index 0000000..56d7617
--- /dev/null
+++ 
b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java
@@ -0,0 +1,221 @@
+/*
+ * 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.net.URL;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.lookup.AbstractLookup;
+import org.apache.logging.log4j.core.lookup.StrLookup;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.Strings;
+
+import io.fabric8.kubernetes.api.model.Container;
+import io.fabric8.kubernetes.api.model.ContainerStatus;
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+
+/**
+ * Retrieve various Kubernetes attributes. Supported keys are:
+ *  accountName, containerId, containerName, clusterName, host, hostIp, 
labels, labels.app,
+ *  labels.podTemplateHash, masterUrl, namespaceId, namespaceName, podId, 
podIp, podName,
+ *  imageId, imageName.
+ */
+@Plugin(name = "k8s", category = StrLookup.CATEGORY)
+public class KubernetesLookup extends AbstractLookup {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String HOSTNAME = "HOSTNAME";
+    private static final String SPRING_ENVIRONMENT_KEY = "SpringEnvironment";
+
+    private static volatile KubernetesInfo kubernetesInfo;
+    private static Lock initLock = new ReentrantLock();
+    private static boolean isSpringIncluded =
+            
LoaderUtil.isClassAvailable("org.apache.logging.log4j.spring.cloud.config.client.SpringEnvironmentHolder");
+
+    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();
+                            }
+                            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();
+                            }
+                            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();
+                            }
+                            kubernetesInfo = info;
+                        }
+                    }
+                } finally {
+                    initLock.unlock();
+                }
+            }
+        }
+        return kubernetesInfo != null;
+    }
+
+    @Override
+    public String lookup(LogEvent event, String key) {
+        if (!initialize()) {
+            return null;
+        }
+        switch (key) {
+            case "accountName": {
+                return kubernetesInfo.accountName;
+            }
+            case "containerId": {
+                return kubernetesInfo.containerId;
+            }
+            case "containerName": {
+                return kubernetesInfo.containerName;
+            }
+            case "clusterName": {
+                return kubernetesInfo.clusterName;
+            }
+            case "host": {
+                return kubernetesInfo.hostName;
+            }
+            case "hostIp": {
+                return kubernetesInfo.hostIp;
+            }
+            case "labels": {
+                return kubernetesInfo.labels.toString();
+            }
+            case "labels.app": {
+                return kubernetesInfo.app;
+            }
+            case "labels.podTemplateHash": {
+                return kubernetesInfo.podTemplateHash;
+            }
+            case "masterUrl": {
+                return kubernetesInfo.masterUrl.toString();
+            }
+            case "namespaceId": {
+                return kubernetesInfo.namespaceId;
+            }
+            case "namespaceName": {
+                return kubernetesInfo.namespace;
+            }
+            case "podId": {
+                return kubernetesInfo.podId;
+            }
+            case "podIp": {
+                return kubernetesInfo.podIp;
+            }
+            case "podName": {
+                return kubernetesInfo.podName;
+            }
+            case "imageId": {
+                return kubernetesInfo.imageId;
+            }
+            case "imageName": {
+                return kubernetesInfo.imageName;
+            }
+            default:
+                return null;
+        }
+    }
+
+    private String getHostname() {
+        return System.getenv(HOSTNAME);
+    }
+
+    private Pod getCurrentPod(String hostName, KubernetesClient 
kubernetesClient) {
+        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();
+    }
+
+    private boolean isSpringActive() {
+        return isSpringIncluded && LogManager.getFactory() != null
+            && 
LogManager.getFactory().hasContext(KubernetesLookup.class.getName(), null, 
false)
+            && LogManager.getContext(false).getObject(SPRING_ENVIRONMENT_KEY) 
!= null;
+    }
+
+    private static class KubernetesInfo {
+        boolean isSpringActive;
+        String accountName;
+        String app;
+        String clusterName;
+        String containerId;
+        String containerName;
+        String hostName;
+        String hostIp;
+        String imageId;
+        String imageName;
+        Map<String, String> labels;
+        URL masterUrl;
+        String namespace;
+        String namespaceId;
+        String podId;
+        String podIp;
+        String podName;
+        String podTemplateHash;
+    }
+}
diff --git a/log4j-kubernetes/src/site/markdown/index.md.vm 
b/log4j-kubernetes/src/site/markdown/index.md.vm
new file mode 100644
index 0000000..d51e757
--- /dev/null
+++ b/log4j-kubernetes/src/site/markdown/index.md.vm
@@ -0,0 +1,104 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    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.
+-->
+#set($dollar = '$')
+#set($h1='#')
+#set($h2='##')
+
+$h1 Log4j Kubernetes Support
+
+Log4j supports Kubernetes by providing a Lookup to retrieve container 
information.
+
+$h2 Accessing Kubernetes
+
+The Log4j Kubernetes support requires access to the Docker REST interface. In 
many cases the REST service
+can be accessed automatically. If needed the Kubernetes client can be 
configured any of the standard
+Log4j configuration locations or via the Spring Boot configuration. Note, 
however, that since Spring Boot
+causes logging to initialize 3 times and since the Spring environment is only 
available during the last
+Log4j initialization Spring properties will only be available to Log4j in the 
last initialization.
+
+$h2 Lookup Attributes
+
+Log4j Kubernetes provides access to the following container attributes:
+
+* accountName - The service account name.
+* clusterName - The name of the cluster the application is running in.
+* containerId - The full id assigned to the container.
+* containerName - The name assigned to the container.
+* host - The name of the host.
+* hostIp - The host's ip address.
+* imageId - The id assigned to the image.
+* imageName - The name assigned to the image.
+* labels - All labels formatted in a list.
+* labels.app - The application name.
+* labels.podTemplateHash - The pod's template hash value.
+* masterUrl - The url needed to access the API server.
+* namespaceId - The id of the namespace the various kubernetes components are 
located within.
+* namespaceName - The namespace the various kubernetes components are located 
within.
+* podId - The pod's id number.
+* podIp - The pod's ip address.
+* podName - The name of the pod.
+
+#set( $D = '${' )
+#set( $container = 'k8s:containerId}')
+Attributes may be accessed by adding
+```
+$D$container
+```
+to the configuration. Note that kubernetes variables are only resolved once 
during logging initialization so they
+shouldn't be referenced with more than one '$' character.
+
+$h2 Configuration
+
+Much of the configuration needed to access the Kubernetes API server is 
provided automatically by Kubernetes.
+However, it is not uncommon to need to provide the url required to access the 
Kubernetes API server or the
+namespace the application is assigned to. The properties below may either be 
configured using the Log4j
+variable names and located by Log4j's normal property resolution mechansim or 
Log4j will resolve the
+spring properties when the application is running in Spring Boot and the 
Spring Environment has been created.
+Note that Spring Boot initializes logging 3 times and only the last will have 
a Spring Environment present.
+
+| Log4j Property Name     | Spring Property Name  | Default   | Description |
+|------------------------ |----------------------:|----------:|------------:|
+| log4j2.kubernetes.client.apiVersion | 
spring.cloud.kubernetes.client.apiVersion | v1 | Kubernetes API Version |
+| log4j2.kubernetes.client.caCertData | 
spring.cloud.kubernetes.client.caCertData | | Kubernetes API CACertData |
+| log4j2.kubernetes.client.caCertFile | 
spring.cloud.kubernetes.client.caCertFile | | Kubernetes API CACertFile |
+| log4j2.kubernetes.client.clientCertData | 
spring.cloud.kubernetes.client.clientCertData | | Kubernetes API ClientCertData 
|
+| log4j2.kubernetes.client.clientCertFile | 
spring.cloud.kubernetes.client.clientCertFile | | Kubernetes API ClientCertFile 
|
+| log4j2.kubernetes.client.clientKeyAlgo | 
spring.cloud.kubernetes.client.clientKeyAlgo | RSA | Kubernetes API 
ClientKeyAlgo |
+| log4j2.kubernetes.client.clientKeyData | 
spring.cloud.kubernetes.client.clientKeyData | | Kubernetes API ClientKeyData |
+| log4j2.kubernetes.client.clientKeyFile | 
spring.cloud.kubernetes.client.clientKeyFile | | Kubernetes API ClientKeyFile |
+| log4j2.kubernetes.client.clientKeyPassPhrase | 
spring.cloud.kubernetes.client.clientKeyPassphrase | changeit | Kubernetes API 
ClientKeyPassphrase |
+| log4j2.kubernetes.client.connectionTimeout | 
spring.cloud.kubernetes.client.connectionTimeout | 10s | Connection timeout |
+| log4j2.kubernetes.client.httpProxy | 
spring.cloud.kubernetes.client.http-proxy | | |
+| log4j2.kubernetes.client.httpsProxy | 
spring.cloud.kubernetes.client.https-proxy | | |
+| log4j2.kubernetes.client.loggingInberval | 
spring.cloud.kubernetes.client.loggingInterval | 20s | Logging interval |
+| log4j2.kubernetes.client.masterUrl | 
spring.cloud.kubernetes.client.masterUrl | kubernetes.default.svc | Kubernetes 
API Master Node URL |
+| log4j2.kubernetes.client.namespacce | 
spring.cloud.kubernetes.client.namespace | default | Kubernetes Namespace |
+| log4j2.kubernetes.client.noProxy | spring.cloud.kubernetes.client.noProxy | 
| |
+| log4j2.kubernetes.client.password | spring.cloud.kubernetes.client.password 
| | Kubernetes API Password |
+| log4j2.kubernetes.client.proxyPassword | 
spring.cloud.kubernetes.client.proxyPassword | | |
+| log4j2.kubernetes.client.proxyUsername | 
spring.cloud.kubernetes.client.proxyUsername | | |
+| log4j2.kubernetes.client.requestTimeout | 
spring.cloud.kubernetes.client.requestTimeout | 10s | Request timeout |
+| log4j2.kubernetes.client.rollingTimeout | 
spring.cloud.kubernetes.client.rollingTimeout | 900s | Rolling timeout |
+| log4j2.kubernetes.client.trustCerts | 
spring.cloud.kubernetes.client.trustCerts | false | Kubernetes API Trust 
Certificates |
+| log4j2.kubernetes.client.username | spring.cloud.kubernetes.client.username 
| | Kubernetes API Username |
+| log4j2.kubernetes.client.watchReconnectInterval | 
spring.cloud.kubernetes.client.watchReconnectInterval | 1s | Reconnect Interval 
|
+| log4j2.kubernetes.client.watchReconnectLimit | 
spring.cloud.kubernetes.client.watchReconnectLimit | -1 | Reconnect Interval 
limit retries |
+
+$h2 Requirements
+Log4j Kubernetes requires Log4j Core, Log4j API and a minimum of Java 8.
+For more information, see [Runtime Dependencies](../runtime-dependencies.html).
diff --git a/log4j-kubernetes/src/site/site.xml 
b/log4j-kubernetes/src/site/site.xml
new file mode 100644
index 0000000..7322f3b
--- /dev/null
+++ b/log4j-kubernetes/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+
+-->
+<project name="Log4j Docker Support"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 
http://maven.apache.org/xsd/decoration-1.4.0.xsd";>
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/"; />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+       <!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" 
href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" 
/>
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
index 5c4aea0..cf2a220 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.spring.cloud.config.client;
 
+import javax.net.ssl.HttpsURLConnection;
 import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -24,7 +25,6 @@ import java.net.URLConnection;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Properties;
-import javax.net.ssl.HttpsURLConnection;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.LoggerContext;
@@ -68,7 +68,6 @@ public class Log4j2CloudConfigLoggingSystem extends 
Log4J2LoggingSystem {
         super.initialize(initializationContext, configLocation, logFile);
     }
 
-
     @Override
     protected String[] getStandardConfigLocations() {
         String[] locations = super.getStandardConfigLocations();
@@ -77,7 +76,7 @@ public class Log4j2CloudConfigLoggingSystem extends 
Log4J2LoggingSystem {
         if (location != null) {
             List<String> list = 
Arrays.asList(super.getStandardConfigLocations());
             list.add(location);
-            locations = list.toArray(new String[list.size()]);
+            locations = list.toArray(new String[0]);
         }
         return locations;
     }
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
index 96812d2..eb21607 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
@@ -19,7 +19,6 @@ package org.apache.logging.log4j.spring.cloud.config.client;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-
 import org.springframework.cloud.bus.ConditionalOnBusEnabled;
 import org.springframework.cloud.bus.SpringCloudBusClient;
 import org.springframework.cloud.bus.event.RemoteApplicationEvent;
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringEnvironmentHolder.java
similarity index 52%
copy from 
log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
copy to 
log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringEnvironmentHolder.java
index 53c97ea..c633e8a 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringEnvironmentHolder.java
@@ -17,34 +17,32 @@
 package org.apache.logging.log4j.spring.cloud.config.client;
 
 import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.lookup.StrLookup;
-import org.apache.logging.log4j.plugins.Plugin;
 import org.springframework.core.env.Environment;
 
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
 /**
- * Lookup for Spring properties.
+ * Provides access to the Spring Environment.
  */
-@Plugin(name = "spring", category = StrLookup.CATEGORY)
-public class SpringLookup implements StrLookup {
+public class SpringEnvironmentHolder {
 
-    private final Environment environment;
+    private volatile Environment environment;
+    private Lock lock = new ReentrantLock();
 
-    public SpringLookup() {
-        Object obj = 
LogManager.getContext(false).getObject(Log4j2CloudConfigLoggingSystem.ENVIRONMENT_KEY);
-        environment = obj instanceof Environment ? (Environment) obj : null;
-    }
 
-    @Override
-    public String lookup(String key) {
-        if (environment != null) {
-            return environment.getProperty(key);
+    protected Environment getEnvironment() {
+        if (environment == null && LogManager.getFactory() != null && 
LogManager.getFactory().hasContext(SpringEnvironmentHolder.class.getName(), 
null, false)) {
+            lock.lock();
+            try {
+                if (environment == null) {
+                    Object obj = 
LogManager.getContext(false).getObject(Log4j2CloudConfigLoggingSystem.ENVIRONMENT_KEY);
+                    environment = obj instanceof Environment ? (Environment) 
obj : null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
-        return null;
-    }
-
-    @Override
-    public String lookup(LogEvent event, String key) {
-        return lookup((key));
+        return environment;
     }
 }
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
index 53c97ea..076f3b1 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
@@ -16,7 +16,6 @@
  */
 package org.apache.logging.log4j.spring.cloud.config.client;
 
-import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.lookup.StrLookup;
 import org.apache.logging.log4j.plugins.Plugin;
@@ -26,19 +25,17 @@ import org.springframework.core.env.Environment;
  * Lookup for Spring properties.
  */
 @Plugin(name = "spring", category = StrLookup.CATEGORY)
-public class SpringLookup implements StrLookup {
-
-    private final Environment environment;
+public class SpringLookup extends SpringEnvironmentHolder implements StrLookup 
{
 
     public SpringLookup() {
-        Object obj = 
LogManager.getContext(false).getObject(Log4j2CloudConfigLoggingSystem.ENVIRONMENT_KEY);
-        environment = obj instanceof Environment ? (Environment) obj : null;
+        getEnvironment();
     }
 
     @Override
     public String lookup(String key) {
-        if (environment != null) {
-            return environment.getProperty(key);
+        Environment env = getEnvironment();
+        if (env != null) {
+            return env.getProperty(key);
         }
         return null;
     }
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringPropertySource.java
similarity index 59%
copy from 
log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
copy to 
log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringPropertySource.java
index 53c97ea..8ffed65 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringPropertySource.java
@@ -16,27 +16,27 @@
  */
 package org.apache.logging.log4j.spring.cloud.config.client;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.lookup.StrLookup;
-import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.util.PropertySource;
 import org.springframework.core.env.Environment;
 
 /**
- * Lookup for Spring properties.
+ * Returns properties from Spring.
  */
-@Plugin(name = "spring", category = StrLookup.CATEGORY)
-public class SpringLookup implements StrLookup {
+public class SpringPropertySource extends SpringEnvironmentHolder implements 
PropertySource {
 
-    private final Environment environment;
-
-    public SpringLookup() {
-        Object obj = 
LogManager.getContext(false).getObject(Log4j2CloudConfigLoggingSystem.ENVIRONMENT_KEY);
-        environment = obj instanceof Environment ? (Environment) obj : null;
+    /**
+     * System properties take precendence followed by properties in Log4j 
properties files. Spring properties
+     * follow.
+     * @return This PropertySource's priority.
+     */
+    @Override
+    public int getPriority() {
+        return -50;
     }
 
     @Override
-    public String lookup(String key) {
+    public String getProperty(String key) {
+        Environment environment = getEnvironment();
         if (environment != null) {
             return environment.getProperty(key);
         }
@@ -44,7 +44,11 @@ public class SpringLookup implements StrLookup {
     }
 
     @Override
-    public String lookup(LogEvent event, String key) {
-        return lookup((key));
+    public boolean containsProperty(String key) {
+        Environment environment = getEnvironment();
+        if (environment != null) {
+            return environment.containsProperty(key);
+        }
+        return false;
     }
 }
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
index 89d1ee9..d4402e8 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
@@ -1,3 +1,19 @@
+#
+# 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.
+#
 # Alpine Linux with OpenJDK
 #FROM openjdk:8-jdk-alpine
 FROM openjdk:11-jdk-slim
@@ -13,4 +29,5 @@ WORKDIR /service
 EXPOSE 8080
 
 #CMD java 
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005" -jar 
sampleapp.jar
-CMD java -jar -Xmx2G sampleapp.jar
+ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar -Xmx1G sampleapp.jar"]
+
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/deploy.sh
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/deploy.sh
new file mode 100755
index 0000000..9f67de2
--- /dev/null
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/deploy.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+#
+# 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.
+#
+
+echo "Building, (re)creating, starting, and attaching to containers for a 
service."
+
+imageName=sampleapp
+containerName=sampleapp-container
+networkName=docker_sampleapp
+debug_port=5005
+#debug_expose="-p $debug_port:$debug_port"
+exposed_ports="-p 8080:8090 $debug_expose"
+
+mvn clean package -DskipTests=true
+docker build --no-cache -t $imageName -f Dockerfile  .
+
+docker tag $imageName localhost:5000/$imageName
+docker push localhost:5000/$imageName
+kubectl apply -f k8s/sampleapp-deployment.yaml
\ No newline at end of file
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
new file mode 100644
index 0000000..fe5d2b7
--- /dev/null
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml
@@ -0,0 +1,44 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: sampleapp
+  labels:
+    app: sampleapp
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: sampleapp
+  template:
+    metadata:
+      labels:
+        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"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: sampleapp
+spec:
+  type: NodePort
+  selector:
+    app: sampleapp
+  ports:
+    - protocol: TCP
+      port: 8080
+      nodePort: 30011
+      name: http
+    - protocol: TCP
+      port: 5005
+      nodePort: 30012
+      name: debug
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/undeploy.sh
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/undeploy.sh
new file mode 100755
index 0000000..c5255c9
--- /dev/null
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/undeploy.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+#
+#
+# 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.
+#
+
+echo "Building, (re)creating, starting, and attaching to containers for a 
service."
+
+imageName=sampleapp
+containerName=sampleapp-container
+networkName=docker_sampleapp
+
+kubectl delete deploy/$imageName svc/$imageName
+
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
index 412ea24..1fd45b4 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
@@ -92,6 +92,11 @@
       <artifactId>log4j-docker</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-kubernetes</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <!-- Required for Async Loggers -->
     <dependency>
       <groupId>com.lmax</groupId>
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 71ca238..7e9838e 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
@@ -27,4 +27,7 @@ spring:
     addresses: rabbit
     port: 5672
     username: guest
-    password: guest
\ No newline at end of file
+    password: guest
+
+log4j2:
+  debug: true
\ No newline at end of file
diff --git 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
index 40d3098..2e9dcfa 100644
--- 
a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
+++ 
b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
@@ -1,15 +1,27 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
 <Configuration status="DEBUG" monitorInterval="0">
   <Properties>
     <Property name="spring.application.name">sampleapp</Property>
   </Properties>
   <Appenders>
-    <Console name="console" target="SYSTEM_OUT">
-      <JsonLayout properties="true" compact="true" eventEol="true" 
stackTraceAsString="true">
-      </JsonLayout>
-    </Console>
-    <Flume name="flume" ignoreExceptions="false" type="Embedded" 
compress="false">
+    <!--<Flume name="flume" ignoreExceptions="false" type="Embedded" 
compress="false">
       <Property name="channel.type">memory</Property>
       <Property name="channel.capacity">100000</Property>
       <Property name="channel.transactionCapacity">5000</Property>
@@ -88,20 +100,53 @@
       </RFC5424Layout>
       <SizeBasedTriggeringPolicy size="10MB" />
       <DefaultRolloverStrategy max="5"/>
-    </RollingFile>
+    </RollingFile>-->
+    <Socket name="Elastic" host="\${sys:elastic.search.host:-localhost}" 
port="12222" protocol="tcp" bufferedIo="true" ignoreExceptions="false">
+      <GelfLayout includeStackTrace="true" host="${hostName}" 
includeThreadContext="true" includeNullDelimiter="true"
+                  compressionType="OFF">
+        
<ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,corpAcctNumber,callingHost,ohBehalfOf,onBehalfOfAccount</ThreadContextIncludes>
+        <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, 
ipAddress, corpAcctNumber} %C{1.}.%M:%L - %m%n</MessagePattern>
+        <KeyValuePair key="docker.containerId" 
value="\${docker:containerId:-}"/>
+        <KeyValuePair key="application" 
value="$\${lower:\${spring:spring.application.name}}"/>
+        <KeyValuePair key="kubernetes.serviceAccountName" 
value="\${k8s:accountName:-}"/>
+        <KeyValuePair key="kubernetes.containerId" 
value="\${k8s:containerId:-}"/>
+        <KeyValuePair key="kubernetes.containerName" 
value="\${k8s:containerName:-}"/>
+        <KeyValuePair key="kubernetes.host" value="\${k8s:host:-}"/>
+        <KeyValuePair key="kubernetes.labels.app" 
value="\${k8s:labels.app:-}"/>
+        <KeyValuePair key="kubernetes.labels.pod-template-hash" 
value="\${k8s:labels.podTemplateHash:-}"/>
+        <KeyValuePair key="kubernetes.master_url" value="\${k8s:masterUrl:-}"/>
+        <KeyValuePair key="kubernetes.namespaceId" 
value="\${k8s:namespaceId:-}"/>
+        <KeyValuePair key="kubernetes.namespaceName" 
value="\${k8s:namespaceName:-}"/>
+        <KeyValuePair key="kubernetes.podID" value="\${k8s:podId:-}"/>
+        <KeyValuePair key="kubernetes.podIP" value="\${k8s:podIp:-}"/>
+        <KeyValuePair key="kubernetes.podName" value="\${k8s:podName:-}"/>
+        <KeyValuePair key="kubernetes.imageId" value="\${k8s:imageId:-}"/>
+        <KeyValuePair key="kubernetes.imageName" value="\${k8s:imageName:-}"/>
+      </GelfLayout>
+    </Socket>
+    <Console name="Console" target="SYSTEM_OUT">
+      <RFC5424Layout enterpriseNumber="50177" includeMDC="true" 
mdcId="RequestContext" appName="SalesforceGateway"
+                     mdcPrefix="" newLine="true" 
mdcIncludes="requestId,sessionId,loginId,userId,ipAddress,corpAcctNumber"/>
+    </Console>
+    <Failover name="log4j" primary="Elastic">
+      <Failovers>
+        <AppenderRef ref="Console"/>
+      </Failovers>
+    </Failover>
   </Appenders>
+
   <Loggers>
     <Logger name="org.apache.kafka" level="warn" additivity="false">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Logger>
     <Logger name="org.apache.flume" level="warn" additivity="false">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Logger>
     <Logger name="org.apache.avro" level="warn" additivity="false">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Logger>
     <Root level="DEBUG">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Root>
   </Loggers>
 </Configuration>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 425915c..59e7307 100644
--- a/pom.xml
+++ b/pom.xml
@@ -192,6 +192,7 @@
     <jackson1Version>1.9.13</jackson1Version>
     <jackson2Version>2.9.9</jackson2Version>
     <springVersion>3.2.18.RELEASE</springVersion>
+    <kubernetes-client.version>4.6.1</kubernetes-client.version>
     <flumeVersion>1.9.0</flumeVersion>
     <disruptorVersion>3.4.2</disruptorVersion>
     <conversantDisruptorVersion>1.2.15</conversantDisruptorVersion>
@@ -745,6 +746,11 @@
         <version>${springVersion}</version>
       </dependency>
       <dependency>
+        <groupId>io.fabric8</groupId>
+        <artifactId>kubernetes-client</artifactId>
+        <version>${kubernetes-client.version}</version>
+      </dependency>
+      <dependency>
         <groupId>org.hsqldb</groupId>
         <artifactId>hsqldb</artifactId>
         <version>2.4.1</version>
@@ -1265,6 +1271,13 @@
             <!-- Other -->
             <exclude>felix-cache/**</exclude>
             <exclude>RELEASE-NOTES.md</exclude>
+            <exclude>**/*.yml</exclude>
+            <exclude>**/*.yaml</exclude>
+            <exclude>**/*.json</exclude>
+            <excllude>**/images/*.drawio</excllude>
+            <exclude>**/fluent-bit.conf</exclude>
+            <exclude>**/rabbitmq.config</exclude>
+            <exclude>**/MANIFEST.MF</exclude>
           </excludes>
         </configuration>
       </plugin>
@@ -1448,6 +1461,13 @@
             <!-- Other -->
             <exclude>felix-cache/**</exclude>
             <exclude>RELEASE-NOTES.txt</exclude>
+            <exclude>**/*.yml</exclude>
+            <exclude>**/*.yaml</exclude>
+            <exclude>**/*.json</exclude>
+            <excllude>**/images/*.drawio</excllude>
+            <exclude>**/fluent-bit.conf</exclude>
+            <exclude>**/rabbitmq.config</exclude>
+            <exclude>**/MANIFEST.MF</exclude>
           </excludes>
         </configuration>
       </plugin>
@@ -1515,6 +1535,7 @@
     <module>log4j-smtp</module>
     <module>log4j-osgi</module>
     <module>log4j-docker</module>
+    <module>log4j-kubernetes</module>
     <module>log4j-spring-cloud-config</module>
   </modules>
   <profiles>
@@ -1634,6 +1655,13 @@
                 <!-- Other -->
                 <exclude>felix-cache/**</exclude>
                 <exclude>RELEASE-NOTES.md</exclude>
+                <exclude>**/*.yml</exclude>
+                <exclude>**/*.yaml</exclude>
+                <exclude>**/*.json</exclude>
+                <excllude>**/images/*.drawio</excllude>
+                <exclude>**/fluent-bit.conf</exclude>
+                <exclude>**/rabbitmq.config</exclude>
+                <exclude>**/MANIFEST.MF</exclude>
               </excludes>
             </configuration>
             <executions>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5ecb436..e7ab73f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -157,6 +157,10 @@
       </action>
     </release>
     <release version="2.13.0" date="2019-MM-DD" description="GA Release 
2.13.0">
+      <action issue="LOG4J2-2716" dev="rgoers" type="add">
+        Add the ability to lookup Kubernetes attributes in the Log4j 
configuration. Allow Log4j properties to
+        be retrieved from the Spring environment if it is available.
+      </action>
       <action issue="LOG4J2-2710" dev="rgoers" type="add">
         Allow Spring Boot application properties to be accessed in the Log4j 2 
configuraiton. Add
         lower and upper case Lookups.
diff --git a/src/site/asciidoc/manual/lookups.adoc 
b/src/site/asciidoc/manual/lookups.adoc
index cea14ff..601b67f 100644
--- a/src/site/asciidoc/manual/lookups.adoc
+++ b/src/site/asciidoc/manual/lookups.adoc
@@ -80,7 +80,7 @@ Log4j Docker provides access to the following container 
attributes:
 |containerId
 |The full id assigned to the container.
 
-|containreName
+|containerName
 |The name assigned to the container.
 
 |imageId
@@ -221,6 +221,58 @@ 
https://docs.oracle.com/javase/8/docs/api/java/lang/management/RuntimeMXBean.htm
 
 *Java's JMX module is not available on Android or on Google App Engine.*
 
+[#KubernetesLookup]
+== Kubernetes Lookup
+
+The KubernetesLookup can be used to lookup attributes from the Kubernetes 
environment for the container
+the application is running in.
+
+Log4j Kubernetes provides access to the following container attributes:
+[cols="1m,4a"]
+|===
+|Attribute |Description
+|accountName|The service account name
+|clusterName|The name of the cluster the application is deployed in
+|containerId|>The full id assigned to the container
+|containerName|The name assigned to the container
+|host|The name assigned to the host operating system
+|hostIp|The host's ip address
+|imageId|The id assigned to the container image
+|imageName|The name assigned to the container image
+|labels|All labels formatted in a list
+|labesl.app|The application name
+|labels.podTemplateHash|The pod's template hash value
+|masterUrl|The URL used to access the API server
+|namespaceId|The id of the namespace the various kubernetes components are 
located within
+|namespaceName|The namespace the various kubernetes components are located 
within
+|podId|The pod's ip number
+|podIp|The pod's ip address
+|podName|The name of the pod
+
+      <GelfLayout includeStackTrace="true" host="${hostName}" 
includeThreadContext="true" includeNullDelimiter="true" compressionType="OFF">
+        
<ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,callingHost</ThreadContextIncludes>
+        <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, 
ipAddress} %C{1.}.%M:%L - %m%n</MessagePattern>
+        <KeyValuePair key="docker.containerId" 
value="${docker:containerId:-}"/>
+        <KeyValuePair key="application" 
value="$${lower:${spring:spring.application.name}}"/>
+        <KeyValuePair key="kubernetes.serviceAccountName" 
value="${k8s:accountName:-}"/>
+        <KeyValuePair key="kubernetes.clusterName" 
value="${k8s:clusterName:-}/>
+        <KeyValuePair key="kubernetes.containerId" 
value="${k8s:containerId:-}"/>
+        <KeyValuePair key="kubernetes.containerName" 
value="${k8s:containerName:-}"/>
+        <KeyValuePair key="kubernetes.host" value="${k8s:host:-}"/>
+        <KeyValuePair key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
+        <KeyValuePair key="kubernetes.labels.pod-template-hash" 
value="${k8s:labels.podTemplateHash:-}"/>
+        <KeyValuePair key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
+        <KeyValuePair key="kubernetes.namespaceId" 
value="${k8s:namespaceId:-}"/>
+        <KeyValuePair key="kubernetes.namespaceName" 
value="${k8s:namespaceName:-}"/>
+        <KeyValuePair key="kubernetes.podID" value="${k8s:podId:-}"/>
+        <KeyValuePair key="kubernetes.podIP" value="${k8s:podIp:-}"/>
+        <KeyValuePair key="kubernetes.podName" value="${k8s:podName:-}"/>
+        <KeyValuePair key="kubernetes.imageId" value="${k8s:imageId:-}"/>
+        <KeyValuePair key="kubernetes.imageName" value="${k8s:imageName:-}"/>
+      </GelfLayout>]]></pre>
+
+This Lookup is subject to the configuration requirements listed at 
link:../log4j-kubernetes/index.html[Log4j Kubernetes Support]
+
 [#Log4jConfigLookup]
 == Log4j Configuration Location Lookup
 
diff --git a/src/site/markdown/manual/cloud.md 
b/src/site/markdown/manual/cloud.md
index 9336914..e71753e 100644
--- a/src/site/markdown/manual/cloud.md
+++ b/src/site/markdown/manual/cloud.md
@@ -45,7 +45,6 @@ per logging call vs 1.5 microseconds when writing to the file.
     OutputBenchmark.file      thrpt   20  654584.309 ± 59399.092  ops/s
     OutputBenchmark.redirect  thrpt   20   70284.576 ±  7452.167  ops/s
     ```
-
 1. When performing audit logging using a framework such as log4j-audit 
guaranteed delivery of the audit events
 is required. Many of the options for writing the output, including writing to 
the standard output stream, do
 not guarantee delivery. In these cases the event must be delivered to a 
"forwarder" that acknowledges receipt
@@ -134,6 +133,20 @@ one ip address associated with its DNS entry the socket 
appender will fail throu
         <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, 
ipAddress} %C{1.}.%M:%L - %m%n</MessagePattern>
         <KeyValuePair key="containerId" value="${docker:containerId:-}"/>
         <KeyValuePair key="application" 
value="$${lower:${spring:spring.application.name:-spring}}"/>
+        <KeyValuePair key="kubernetes.serviceAccountName" 
value="${k8s:accountName:-}"/>
+        <KeyValuePair key="kubernetes.containerId" 
value="${k8s:containerId:-}"/>
+        <KeyValuePair key="kubernetes.containerName" 
value="${k8s:containerName:-}"/>
+        <KeyValuePair key="kubernetes.host" value="${k8s:host:-}"/>
+        <KeyValuePair key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
+        <KeyValuePair key="kubernetes.labels.pod-template-hash" 
value="${k8s:labels.podTemplateHash:-}"/>
+        <KeyValuePair key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
+        <KeyValuePair key="kubernetes.namespaceId" 
value="${k8s:namespaceId:-}"/>
+        <KeyValuePair key="kubernetes.namespaceName" 
value="${k8s:namespaceName:-}"/>
+        <KeyValuePair key="kubernetes.podID" value="${k8s:podId:-}"/>
+        <KeyValuePair key="kubernetes.podIP" value="${k8s:podIp:-}"/>
+        <KeyValuePair key="kubernetes.podName" value="${k8s:podName:-}"/>
+        <KeyValuePair key="kubernetes.imageId" value="${k8s:imageId:-}"/>
+        <KeyValuePair key="kubernetes.imageName" value="${k8s:imageName:-}"/>
       </GelfLayout>
     </Socket>
 
@@ -182,12 +195,11 @@ With the above configurations the message field will 
contain a fully formatted l
 a file Appender. The ThreadContext attributes, custome fields, thread name, 
etc. will all be available as attributes
 on each log event that can be used for filtering.
 
-
 ## Managing Logging Configuration
 
 Spring Boot provides another least common denominator approach to logging 
configuration. It will let you set the 
 log level for various Loggers within an application which can be dynamically 
updated via REST endpoints provided 
-by Spring. While this works in a lot of cases it does not support any of the 
more advanced filtering features of
+by Spring. While this works in a lot of cases it does not support any of the 
more advanced filtering features of 
 Log4j. For example, since it cannot add or modify any Filters other than the 
log level of a logger, changes cannot be made to allow 
 all log events for a specific user or customer to temporarily be logged 
 (see [DynamicThresholdFilter](filters.html#DynamicThresholdFilter) or 
@@ -220,13 +232,20 @@ attributes in the formatted log event as described at
 provides similar functionality via the [Docker 
Lookup](lookups.html#DockerLookup). More information on
 Log4j's Docker support may also be found at 
[Log4j-Docker](../log4j-docker/index.html). 
 
+## Integration with Kubernetes
+
+Applications managed by Kubernetes can bypass the Docker/Kubernetes logging 
infrastructure and log directly to 
+either a sidecar forwarder or a logging aggragator cluster while still 
including all the kubernetes 
+attributes by using the Log4j 2 [Kubernetes 
Lookup](lookups.html#KubernetesLookup). More information on
+Log4j's Kubernetes support may also be found at 
[Log4j-Kubernetes](../log4j-kubernetes/index.html). 
+
 ## Appender Performance
-The numbers in the table below represent how much time in seconds was required 
for the application to
-call logger.debug 100,000 times. These numbers only include the time taken to 
deliver to the specifically
-noted endpoint and many not include the actual time required before they are 
available for viewing. All
+The numbers in the table below represent how much time in seconds was required 
for the application to 
+call logger.debug 100,000 times. These numbers only include the time taken to 
deliver to the specifically 
+noted endpoint and many not include the actual time required before they are 
available for viewing. All 
 measurements were performed on a MacBook Pro with a 2.9GHz Intel Core I9 
processor with 6 physical and 12 
 logical cores, 32GB of 2400 MHz DDR4 RAM, and 1TB of Apple SSD storage. The VM 
used by Docker was managed 
-by VMWare Fusion and had 4 CPUs and 2 GB of RAM. These number should be used 
for relative performance comparisons
+by VMWare Fusion and had 4 CPUs and 2 GB of RAM. These number should be used 
for relative performance comparisons 
 as the results on another system may vary considerably.
 
 The sample application used can be found under the 
log4j-spring-cloud-config/log4j-spring-cloud-config-samples
@@ -285,9 +304,9 @@ the performance numbers show, so long as the volume of 
logging is not high enoug
 circular buffer the overhead of logging will almost be unnoticeable to the 
application.
 1. If overall performance is a consideration or you require multiline events 
such as stack traces
 be processed properly then log via TCP to a companion container that acts as a 
log forwarder or directly
-to a log aggregator as shown above in [Logging with ELK](#ELK). Use the 
+to a log aggregator as shown above in [Logging with ELK](#ELK). Use the  
 Log4j Docker Lookup to add the container information to each log event.
-1. Whenever guaranteed delivery is required use Flume Avro with a batch size 
of 1 or another Appender such
+1. Whenever guaranteed delivery is required use Flume Avro with a batch size 
of 1 or another Appender such 
 as the Kafka Appender with syncSend set to true that only return control after 
the downstream agent 
 acknowledges receipt of the event. Beware that using an Appender that writes 
each event individually should 
 be kept to a minimum since it is much slower than sending buffered events. 

Reply via email to