package org.dcache.util; import org.slf4j.MDC; import java.util.Map; /** * The class emulates the Nested Diagnostic Context of Log4j. * * Besides providing static methods for working with the NDC, the * class can be instantiated to capture the state of the NDC. */ public class NDC { /* Internally the class uses the MDC. Two MDC keys are used: One * to hold the NDC in string form, and another to hold a comma * separated list of positions in the NDC string indicating the * boundaries. */ public static final String KEY_NDC = "org.dcache.ndc"; public static final String KEY_POSITIONS = "org.dcache.ndc.positions"; private final String _ndc; private final String _positions; public NDC(String ndc, String positions) { _ndc = ndc; _positions = positions; } public String getNdc() { return _ndc; } public String getPositions() { return _positions; } /** * Wrapper around <code>MDC.put</code> and * <code>MDC.remove</code>. <code>value</code> is allowed to be * null. */ private static void setMdc(String key, String value) { if (value != null) { MDC.put(key, value); } else { MDC.remove(key); } } /** * Clear any nested diagnostic information if any. */ public static void clear() { MDC.remove(KEY_NDC); MDC.remove(KEY_POSITIONS); } /** * Returns the nested diagnostic context for the current thread. */ public static NDC cloneNdc() { return new NDC(MDC.get(KEY_NDC), MDC.get(KEY_POSITIONS)); } /** * Replace the nested diagnostic context. */ public static void set(NDC ndc) { setMdc(KEY_NDC, ndc.getNdc()); setMdc(KEY_POSITIONS, ndc.getPositions()); } /** * Push new diagnostic context information for the current * thread. */ public static void push(String message) { String ndc = MDC.get(KEY_NDC); if (ndc == null) { MDC.put(KEY_NDC, message); MDC.put(KEY_POSITIONS, "0"); } else { MDC.put(KEY_NDC, ndc + ' ' + message); MDC.put(KEY_POSITIONS, MDC.get(KEY_POSITIONS) + ',' + ndc.length()); } } /** * Removes the diagnostic context information pushed the last. * Clients should call this method before leaving a diagnostic * context. */ public static String pop() { String top = null; String ndc = MDC.get(KEY_NDC); if (ndc != null) { String positions = MDC.get(KEY_POSITIONS); int pos = positions.lastIndexOf(','); if (pos == -1) { top = ndc; MDC.remove(KEY_NDC); MDC.remove(KEY_POSITIONS); } else { int offset = Integer.parseInt(positions.substring(pos + 1)); top = ndc.substring(offset+1); MDC.put(KEY_NDC, ndc.substring(0, offset)); MDC.put(KEY_POSITIONS, positions.substring(0, pos)); } } return top; } public static String ndcFromMdc(Map<String, String> mdc) { return mdc.get(KEY_NDC); } }