diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java index e51ea76cf..79d757bdd 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java @@ -135,7 +135,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { return authProvider.getResource(); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -153,7 +153,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { return authProvider.updateCredentials(credentials); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -249,7 +249,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -272,7 +272,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { return authProvider.updateAuthenticatedUser(authenticatedUser, credentials); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -318,7 +318,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -342,7 +342,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { return authProvider.updateUserContext(context, authenticatedUser, credentials); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -362,7 +362,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { return authProvider.decorate(context, authenticatedUser, credentials); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -383,7 +383,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { authenticatedUser, credentials); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } @@ -396,7 +396,7 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { authProvider.shutdown(); } finally { - MDC.put(LogModule.MDC_CONTEXT_KEY, LogModule.MDC_CONTEXT_ROOT); + MDC.remove(LogModule.MDC_CONTEXT_KEY); } } diff --git a/guacamole/src/main/java/org/apache/guacamole/log/InheritableMDCAdapter.java b/guacamole/src/main/java/org/apache/guacamole/log/InheritableMDCAdapter.java index 493925476..e75586b47 100644 --- a/guacamole/src/main/java/org/apache/guacamole/log/InheritableMDCAdapter.java +++ b/guacamole/src/main/java/org/apache/guacamole/log/InheritableMDCAdapter.java @@ -33,8 +33,26 @@ import org.slf4j.spi.MDCAdapter; */ public class InheritableMDCAdapter implements MDCAdapter { + // + // IMPORTANT: Thread-local values MUST be removed at web application + // shutdown or a memory leak may result. To avoid this, care must be + // taken in this implementation: + // + // * Ensure that a balanced remove() for every put() is sufficient to + // clear and remove the thread-local itself. + // + // * Calls to ThreadLocal.get() implicitly assign a value to the + // thread-local if no value was present before. This value needs to be + // removed to avoid leaking references at web application shutdown. + // + /** * MDC context map that is automatically inherited by child threads. + *
+ * IMPORTANT: As a thread-local value, it is critical that this value be
+ * removed at web application shutdown or a memory leak may result. Here,
+ * we maintain a reference within the thread-local only as long as at least
+ * one value is stored. Once the map is empty, the thread-local is removed.
*/
private final InheritableThreadLocal
+ * IMPORTANT: As a thread-local value, it is critical that this value be
+ * removed at web application shutdown or a memory leak may result. Here,
+ * we maintain a reference within the thread-local only as long as at least
+ * one non-empty deque is stored. Once no non-empty deques are present
+ * empty, the thread-local is removed.
*/
private final ThreadLocal