1 /**
2 * Copyright (c) 2004-2011 QOS.ch
3 * All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25 package org.slf4j;
26
27 import java.util.Map;
28
29 import org.slf4j.helpers.NOPMDCAdapter;
30 import org.slf4j.helpers.BasicMDCAdapter;
31 import org.slf4j.helpers.Util;
32 import org.slf4j.impl.StaticMDCBinder;
33 import org.slf4j.spi.MDCAdapter;
34
35 /**
36 * This class hides and serves as a substitute for the underlying logging
37 * system's MDC implementation.
38 *
39 * <p>
40 * If the underlying logging system offers MDC functionality, then SLF4J's MDC,
41 * i.e. this class, will delegate to the underlying system's MDC. Note that at
42 * this time, only two logging systems, namely log4j and logback, offer MDC
43 * functionality. For java.util.logging which does not support MDC,
44 * {@link BasicMDCAdapter} will be used. For other systems, i.e slf4j-simple
45 * and slf4j-nop, {@link NOPMDCAdapter} will be used.
46 *
47 * <p>
48 * Thus, as a SLF4J user, you can take advantage of MDC in the presence of log4j,
49 * logback, or java.util.logging, but without forcing these systems as
50 * dependencies upon your users.
51 *
52 * <p>
53 * For more information on MDC please see the <a
54 * href="http://logback.qos.ch/manual/mdc.html">chapter on MDC</a> in the
55 * logback manual.
56 *
57 * <p>
58 * Please note that all methods in this class are static.
59 *
60 * @author Ceki Gülcü
61 * @since 1.4.1
62 */
63 public class MDC {
64
65 static final String NULL_MDCA_URL = "http://www.slf4j.org/codes.html#null_MDCA";
66 static final String NO_STATIC_MDC_BINDER_URL = "http://www.slf4j.org/codes.html#no_static_mdc_binder";
67 static MDCAdapter mdcAdapter;
68
69 private MDC() {
70 }
71
72 static {
73 try {
74 mdcAdapter = StaticMDCBinder.SINGLETON.getMDCA();
75 } catch (NoClassDefFoundError ncde) {
76 mdcAdapter = new NOPMDCAdapter();
77 String msg = ncde.getMessage();
78 if (msg != null && msg.indexOf("StaticMDCBinder") != -1) {
79 Util.report("Failed to load class \"org.slf4j.impl.StaticMDCBinder\".");
80 Util.report("Defaulting to no-operation MDCAdapter implementation.");
81 Util
82 .report("See " + NO_STATIC_MDC_BINDER_URL + " for further details.");
83 } else {
84 throw ncde;
85 }
86 } catch (Exception e) {
87 // we should never get here
88 Util.report("MDC binding unsuccessful.", e);
89 }
90 }
91
92 /**
93 * Put a diagnostic context value (the <code>val</code> parameter) as identified with the
94 * <code>key</code> parameter into the current thread's diagnostic context map. The
95 * <code>key</code> parameter cannot be null. The <code>val</code> parameter
96 * can be null only if the underlying implementation supports it.
97 *
98 * <p>
99 * This method delegates all work to the MDC of the underlying logging system.
100 *
101 * @param key non-null key
102 * @param val value to put in the map
103 *
104 * @throws IllegalArgumentException
105 * in case the "key" parameter is null
106 */
107 public static void put(String key, String val)
108 throws IllegalArgumentException {
109 if (key == null) {
110 throw new IllegalArgumentException("key parameter cannot be null");
111 }
112 if (mdcAdapter == null) {
113 throw new IllegalStateException("MDCAdapter cannot be null. See also "
114 + NULL_MDCA_URL);
115 }
116 mdcAdapter.put(key, val);
117 }
118
119 /**
120 * Get the diagnostic context identified by the <code>key</code> parameter. The
121 * <code>key</code> parameter cannot be null.
122 *
123 * <p>
124 * This method delegates all work to the MDC of the underlying logging system.
125 *
126 * @param key
127 * @return the string value identified by the <code>key</code> parameter.
128 * @throws IllegalArgumentException
129 * in case the "key" parameter is null
130 */
131 public static String get(String key) throws IllegalArgumentException {
132 if (key == null) {
133 throw new IllegalArgumentException("key parameter cannot be null");
134 }
135
136 if (mdcAdapter == null) {
137 throw new IllegalStateException("MDCAdapter cannot be null. See also "
138 + NULL_MDCA_URL);
139 }
140 return mdcAdapter.get(key);
141 }
142
143 /**
144 * Remove the diagnostic context identified by the <code>key</code> parameter using
145 * the underlying system's MDC implementation. The <code>key</code> parameter
146 * cannot be null. This method does nothing if there is no previous value
147 * associated with <code>key</code>.
148 *
149 * @param key
150 * @throws IllegalArgumentException
151 * in case the "key" parameter is null
152 */
153 public static void remove(String key) throws IllegalArgumentException {
154 if (key == null) {
155 throw new IllegalArgumentException("key parameter cannot be null");
156 }
157
158 if (mdcAdapter == null) {
159 throw new IllegalStateException("MDCAdapter cannot be null. See also "
160 + NULL_MDCA_URL);
161 }
162 mdcAdapter.remove(key);
163 }
164
165 /**
166 * Clear all entries in the MDC of the underlying implementation.
167 */
168 public static void clear() {
169 if (mdcAdapter == null) {
170 throw new IllegalStateException("MDCAdapter cannot be null. See also "
171 + NULL_MDCA_URL);
172 }
173 mdcAdapter.clear();
174 }
175
176 /**
177 * Return a copy of the current thread's context map, with keys and values of
178 * type String. Returned value may be null.
179 *
180 * @return A copy of the current thread's context map. May be null.
181 * @since 1.5.1
182 */
183 public static Map<String, String> getCopyOfContextMap() {
184 if (mdcAdapter == null) {
185 throw new IllegalStateException("MDCAdapter cannot be null. See also "
186 + NULL_MDCA_URL);
187 }
188 return mdcAdapter.getCopyOfContextMap();
189 }
190
191 /**
192 * Set the current thread's context map by first clearing any existing map and
193 * then copying the map passed as parameter. The context map passed as
194 * parameter must only contain keys and values of type String.
195 *
196 * @param contextMap
197 * must contain only keys and values of type String
198 * @since 1.5.1
199 */
200 public static void setContextMap(Map<String, String> contextMap) {
201 if (mdcAdapter == null) {
202 throw new IllegalStateException("MDCAdapter cannot be null. See also "
203 + NULL_MDCA_URL);
204 }
205 mdcAdapter.setContextMap(contextMap);
206 }
207
208 /**
209 * Returns the MDCAdapter instance currently in use.
210 *
211 * @return the MDcAdapter instance currently in use.
212 * @since 1.4.2
213 */
214 public static MDCAdapter getMDCAdapter() {
215 return mdcAdapter;
216 }
217
218 }