// Copyright (C) 2009 Google Inc. // // Licensed 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 com.google.enterprise.connector.logging; import java.util.HashMap; /** * Traditional Mapped Diagnostic Context (MDC). The interface is similar * to the MDC class presented by the widely-used log4j. * * <p>The MDC class is similar to the {@link NDC} class except that it is * based on a Map instead of a Stack. The MDC is managed on a per thread basis. * The Map contains key/value pairs that might be useful for distinguishing * different threads running similar tasks. The {@link LayoutPattern} class * can insert the value associated with specified keys as it generates its * log messages. * * <p>A thread may assign an MDC mapping using {@link #put(String,String)}, * and retrieve the value associated with a key in the map by calling * {@link #get(String)}. An individual key/value association may be removed * from the MDC by calling {@link #remove(String)}. * * <p>the entire contents of the map may be cleared by calling {@link #clear}. * This discards any key/value associations in the map, but retains the * ThreadLocal used to maintain the map. This is useful if the thread will * be reused in the future, and desire diagnostic context. For instance, * threads in a thread-pool handling servlet requests could create a new * context when a thread is taken from the pool and given a request * packet. The context item could uniquely identify the request * by requester, port, cookie, etc. Once the request has been * serviced, the thread could clear the MDC map just before being * returned to the thread-pool. * * <p>When a thread will be unlikely to use a diagnostic context in * the future, it should call {@link #remove()} to release the ThreadLocal * resources used by the context. This is especially important if * when the thread exits, so these resources may get garbage collected. */ public class MDC { protected static final ThreadLocal<HashMap<String, String>> context = new ThreadLocal<HashMap<String, String>>(); /** * Put a context <code>value</code> as identified by <code>key</code> * into the current thread's context map. * * <p>If the current thread does not have a context map it is * created as a side effect. * * @param key * @param value */ public static void put(String key, String value) { getContext().put(key, value); } /** * Get the context identified by the <code>key<code> parameter. * * @param key * @return String value associated with that key, * or empty string if not found. */ public static String get(String key) { String value = getContext().get(key); return (value == null) ? "" : value; } /** * Remove the the context identified by the <code>key</code> parameter. * * @param key */ public static void remove(String key) { getContext().remove(key); } /** * Clear all entries in the MDC, but maintain the MDC ThreadLocal. * This is useful for threads that will be reused with a diagnostic * context, such as those in a thread-pool. */ public static void clear() { getContext().clear(); } /** * Remove all the diagnostic context from the thread. This clears * the MDC, and removes the MDC ThreadLocal. * * <p>Each thread that created a diagnostic context by calling * {@link #put put()} should call this method before exiting. Otherwise, * the memory used by the thread cannot be reclaimed by the VM. */ public static void remove() { context.remove(); } /** * Return this thread's MDC context. If this thread has no * MDC context, create one. */ protected static HashMap<String, String> getContext() { HashMap<String, String> mdcContext = context.get(); if (mdcContext == null) { mdcContext = new HashMap<String, String>(4); context.set(mdcContext); } return mdcContext; } }