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 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 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 }