1 /*
2 * Copyright (c) 2004-2007 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.BasicMDCAdapter;
30 import org.slf4j.helpers.NOPMDCAdapter;
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. If the underlying system does not support MDC, e.g.
44 * java.util.logging, then SLF4J will use a {@link BasicMDCAdapter}.
45 *
46 * <p>
47 * Thus, as a SLF4J user, you can take advantage of MDC in the presence of log4j
48 * logback, or java.util.logging, but without forcing these systems as
49 * dependencies upon your users.
50 *
51 * <p>
52 * For more information on MDC please see the <a
53 * href="http://logback.qos.ch/manual/mdc.html">chapter on MDC</a> in the
54 * logback manual.
55 *
56 * <p>
57 * Please note that all methods in this class are static.
58 *
59 * @author Ceki Gülcü
60 * @since 1.4.1
61 */
62 public class MDC {
63
64 static final String NULL_MDCA_URL = "http://www.slf4j.org/codes.html#null_MDCA";
65 static final String NO_STATIC_MDC_BINDER_URL = "http://www.slf4j.org/codes.html#no_static_mdc_binder";
66 static MDCAdapter mdcAdapter;
67
68 private MDC() {
69 }
70
71 static {
72 try {
73 mdcAdapter = StaticMDCBinder.SINGLETON.getMDCA();
74 } catch (NoClassDefFoundError ncde) {
75 mdcAdapter = new NOPMDCAdapter();
76 String msg = ncde.getMessage();
77 if (msg != null && msg.indexOf("StaticMDCBinder") != -1) {
78 Util.report("Failed to load class \"org.slf4j.impl.StaticMDCBinder\".");
79 Util.report("Defaulting to no-operation MDCAdapter implementation.");
80 Util
81 .report("See " + NO_STATIC_MDC_BINDER_URL + " for further details.");
82 } else {
83 throw ncde;
84 }
85 } catch (Exception e) {
86 // we should never get here
87 Util.report("MDC binding unsuccessful.", e);
88 }
89 }
90
91 /**
92 * Put a context value (the <code>val</code> parameter) as identified with the
93 * <code>key</code> parameter into the current thread's context map. The
94 * <code>key</code> parameter cannot be null. The <code>val</code> parameter
95 * can be null only if the underlying implementation supports it.
96 *
97 * <p>
98 * This method delegates all work to the MDC of the underlying logging system.
99 *
100 * @throws IllegalArgumentException
101 * in case the "key" parameter is null
102 */
103 public static void put(String key, String val)
104 throws IllegalArgumentException {
105 if (key == null) {
106 throw new IllegalArgumentException("key parameter cannot be null");
107 }
108 if (mdcAdapter == null) {
109 throw new IllegalStateException("MDCAdapter cannot be null. See also "
110 + NULL_MDCA_URL);
111 }
112 mdcAdapter.put(key, val);
113 }
114
115 /**
116 * Get the context identified by the <code>key</code> parameter. The
117 * <code>key</code> parameter cannot be null.
118 *
119 * <p>
120 * This method delegates all work to the MDC of the underlying logging system.
121 *
122 * @return the string value identified by the <code>key</code> parameter.
123 * @throws IllegalArgumentException
124 * in case the "key" parameter is null
125 */
126 public static String get(String key) throws IllegalArgumentException {
127 if (key == null) {
128 throw new IllegalArgumentException("key parameter cannot be null");
129 }
130
131 if (mdcAdapter == null) {
132 throw new IllegalStateException("MDCAdapter cannot be null. See also "
133 + NULL_MDCA_URL);
134 }
135 return mdcAdapter.get(key);
136 }
137
138 /**
139 * Remove the the context identified by the <code>key</code> parameter using
140 * the underlying system's MDC implementation. The <code>key</code> parameter
141 * cannot be null. This method does nothing if there is no previous value
142 * associated with <code>key</code>.
143 *
144 * @throws IllegalArgumentException
145 * in case the "key" parameter is null
146 */
147 public static void remove(String key) throws IllegalArgumentException {
148 if (key == null) {
149 throw new IllegalArgumentException("key parameter cannot be null");
150 }
151
152 if (mdcAdapter == null) {
153 throw new IllegalStateException("MDCAdapter cannot be null. See also "
154 + NULL_MDCA_URL);
155 }
156 mdcAdapter.remove(key);
157 }
158
159 /**
160 * Clear all entries in the MDC of the underlying implementation.
161 */
162 public static void clear() {
163 if (mdcAdapter == null) {
164 throw new IllegalStateException("MDCAdapter cannot be null. See also "
165 + NULL_MDCA_URL);
166 }
167 mdcAdapter.clear();
168 }
169
170 /**
171 * Return a copy of the current thread's context map, with keys and values of
172 * type String. Returned value may be null.
173 *
174 * @return A copy of the current thread's context map. May be null.
175 * @since 1.5.1
176 */
177 public static Map getCopyOfContextMap() {
178 if (mdcAdapter == null) {
179 throw new IllegalStateException("MDCAdapter cannot be null. See also "
180 + NULL_MDCA_URL);
181 }
182 return mdcAdapter.getCopyOfContextMap();
183 }
184
185 /**
186 * Set the current thread's context map by first clearing any existing map and
187 * then copying the map passed as parameter. The context map passed as
188 * parameter must only contain keys and values of type String.
189 *
190 * @param contextMap
191 * must contain only keys and values of type String
192 * @since 1.5.1
193 */
194 public static void setContextMap(Map contextMap) {
195 if (mdcAdapter == null) {
196 throw new IllegalStateException("MDCAdapter cannot be null. See also "
197 + NULL_MDCA_URL);
198 }
199 mdcAdapter.setContextMap(contextMap);
200 }
201
202 /**
203 * Returns the MDCAdapter instance currently in use.
204 *
205 * @return the MDcAdapter instance currently in use.
206 * @since 1.4.2
207 */
208 public static MDCAdapter getMDCAdapter() {
209 return mdcAdapter;
210 }
211
212 }