View Javadoc

1   package org.slf4j.impl;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.Set;
6   
7   import org.slf4j.spi.MDCAdapter;
8   
9   /**
10   * A <em>Mapped Diagnostic Context</em>, or MDC in short, is an instrument
11   * for distinguishing interleaved log output from different sources. Log output
12   * is typically interleaved when a server handles multiple clients
13   * near-simultaneously. <p> <b><em>The MDC is managed on a per thread basis</em></b>.
14   * A child thread automatically inherits a <em>copy</em> of the mapped
15   * diagnostic context of its parent. <p>
16   * 
17   * For more information about MDC, please refer to the online manual at
18   * http://logback.qos.ch/manual/mdc.html
19   * 
20   * @author Ceki G&uuml;lc&uuml;
21   */
22  public class LogbackMDCAdapter implements MDCAdapter {
23  
24    // final CopyOnInheritThreadLocal copyOnInheritThreadLocal = new
25    // CopyOnInheritThreadLocal();
26  
27    final CopyOnInheritThreadLocal copyOnInheritThreadLocal = new CopyOnInheritThreadLocal();
28  
29    LogbackMDCAdapter() {
30    }
31  
32    /**
33     * Put a context value (the <code>val</code> parameter) as identified with
34     * the <code>key</code> parameter into the current thread's context map.
35     * Note that contrary to log4j, the <code>val</code> parameter can be null.
36     * 
37     * <p> If the current thread does not have a context map it is created as a
38     * side effect of this call.
39     * 
40     * <p> Each time a value is added, a new instance of the map is created. This
41     * is to be certain that the serialization process will operate on the updated
42     * map and not send a reference to the old map, thus not allowing the remote
43     * logback component to see the latest changes.
44     * 
45     * @throws IllegalArgumentException
46     *                 in case the "key" parameter is null
47     */
48    public void put(String key, String val) throws IllegalArgumentException {
49      if (key == null) {
50        throw new IllegalArgumentException("key cannot be null");
51      }
52  
53      HashMap<String, String> oldMap = copyOnInheritThreadLocal.get();
54  
55      HashMap<String, String> newMap = new HashMap<String, String>();
56      if (oldMap != null) {
57        newMap.putAll(oldMap);
58      }
59      // the newMap replaces the old one for serialisation's sake
60      copyOnInheritThreadLocal.set(newMap);
61      newMap.put(key, val);
62    }
63  
64    /**
65     * Get the context identified by the <code>key</code> parameter.
66     * 
67     * <p> This method has no side effects.
68     */
69    public String get(String key) {
70      HashMap<String, String> hashMap = copyOnInheritThreadLocal.get();
71  
72      if ((hashMap != null) && (key != null)) {
73        return hashMap.get(key);
74      } else {
75        return null;
76      }
77    }
78  
79    /**
80     * Remove the the context identified by the <code>key</code> parameter.
81     * 
82     * <p> Each time a value is removed, a new instance of the map is created.
83     * This is to be certain that the serialization process will operate on the
84     * updated map and not send a reference to the old map, thus not allowing the
85     * remote logback component to see the latest changes.
86     */
87    public void remove(String key) {
88      HashMap<String, String> oldMap = copyOnInheritThreadLocal.get();
89  
90      HashMap<String, String> newMap = new HashMap<String, String>();
91      if (oldMap != null) {
92        newMap.putAll(oldMap);
93      }
94      // the newMap replaces the old one for serialisation's sake
95      copyOnInheritThreadLocal.set(newMap);
96      newMap.remove(key);
97    }
98  
99    /**
100    * Clear all entries in the MDC.
101    */
102   public void clear() {
103     HashMap<String, String> hashMap = copyOnInheritThreadLocal.get();
104 
105     if (hashMap != null) {
106       hashMap.clear();
107       copyOnInheritThreadLocal.remove();
108     }
109   }
110 
111   /**
112    * Get the current thread's MDC as a map. This method is intended to be used
113    * internally.
114    */
115   public Map<String, String> getPropertyMap() {
116     return copyOnInheritThreadLocal.get();
117   }
118 
119   /**
120    * Return a copy of the current thread's context map. Returned value may be
121    * null.
122    */
123   public Map getCopyOfContextMap() {
124     HashMap<String, String> hashMap = copyOnInheritThreadLocal.get();
125     if (hashMap == null) {
126       return null;
127     } else {
128       return new HashMap<String, String>(hashMap);
129     }
130   }
131 
132   /**
133    * Returns the keys in the MDC as a {@link Set}. The returned value can be
134    * null.
135    */
136   public Set<String> getKeys() {
137     HashMap<String, String> hashMap = copyOnInheritThreadLocal.get();
138 
139     if (hashMap != null) {
140       return hashMap.keySet();
141     } else {
142       return null;
143     }
144   }
145 
146   @SuppressWarnings("unchecked")
147   public void setContextMap(Map contextMap) {
148     HashMap<String, String> oldMap = copyOnInheritThreadLocal.get();
149 
150     HashMap<String, String> newMap = new HashMap<String, String>();
151     newMap.putAll(contextMap);
152 
153     // the newMap replaces the old one for serialisation's sake
154     copyOnInheritThreadLocal.set(newMap);
155 
156     // hints for the garbage collector
157     if (oldMap != null) {
158       oldMap.clear();
159       oldMap = null;
160     }
161   }
162 }