Log4j 1.x API compatibility layer that implements Apache Log4j API over SLF4J for seamless migration
—
Mapped Diagnostic Context (MDC) and Nested Diagnostic Context (NDC) for adding contextual information to log messages. Both contexts bridge to SLF4J's MDC mechanism for thread-local diagnostic data.
Thread-local key-value storage for contextual information that can be included in log messages. All operations delegate to SLF4J's MDC.
/**
* Put a key-value pair in the MDC
* @param key The key
* @param value The value as String
*/
public static void put(String key, String value);
/**
* Put a key-value pair in the MDC (Object converted to String)
* @param key The key
* @param value The value as Object (converted to String via toString())
*/
public static void put(String key, Object value);
/**
* Get value by key from MDC
* @param key The key to lookup
* @return The value or null if not found
*/
public static Object get(String key);
/**
* Remove key-value pair from MDC
* @param key The key to remove
*/
public static void remove(String key);
/**
* Clear all MDC data for current thread
*/
public static void clear();
/**
* Get MDC context as Hashtable (deprecated)
* @return Copy of MDC context as Hashtable
* @deprecated This method may be removed in future versions
*/
@Deprecated
public static Hashtable<String, String> getContext();Usage Examples:
import org.apache.log4j.MDC;
import org.apache.log4j.Logger;
Logger logger = Logger.getLogger(MyClass.class);
// Set context information
MDC.put("userId", "12345");
MDC.put("sessionId", "abc-def-ghi");
MDC.put("requestId", UUID.randomUUID().toString());
// Log messages will include MDC context (if configured in SLF4J implementation)
logger.info("Processing user request");
// Can put different types (converted to String)
MDC.put("timestamp", System.currentTimeMillis());
MDC.put("userRole", UserRole.ADMIN);
// Retrieve values
String userId = (String) MDC.get("userId");
String sessionId = (String) MDC.get("sessionId");
// Remove specific key
MDC.remove("requestId");
// Clear all context for thread
MDC.clear();
// Example in web application filter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
// Set context for request
MDC.put("requestId", generateRequestId());
MDC.put("remoteAddr", request.getRemoteAddr());
chain.doFilter(request, response);
} finally {
// Always clean up
MDC.clear();
}
}Stack-based diagnostic context for hierarchical information. Implemented using SLF4J's MDC with numbered keys.
/**
* NDC key prefix used for MDC storage
*/
public static final String PREFIX = "NDC";
/**
* Push a message onto the NDC stack
* @param message Message to push
*/
public static void push(String message);
/**
* Pop the top message from NDC stack
* @return The popped message or empty string if stack is empty
*/
public static String pop();
/**
* Peek at the top message without removing it
* @return The top message or empty string if stack is empty
*/
public static String peek();
/**
* Get current depth of NDC stack
* @return Stack depth
*/
public static int getDepth();
/**
* Clear all NDC data for current thread
*/
public static void clear();
/**
* Get NDC string (always returns null in this implementation)
* @return null
*/
public static String get();
/**
* Remove all NDC data (same as clear())
*/
public static void remove();
/**
* Clone NDC stack (always returns null in this implementation)
* @return null
*/
public static Stack<?> cloneStack();
/**
* Inherit NDC stack from another thread (no-op in this implementation)
* @param stack Stack to inherit from
*/
public static void inherit(Stack<?> stack);
/**
* Set maximum NDC depth (no-op in this implementation)
* @param maxDepth Maximum depth
*/
public static void setMaxDepth(int maxDepth);Usage Examples:
import org.apache.log4j.NDC;
import org.apache.log4j.Logger;
Logger logger = Logger.getLogger(MyClass.class);
// Build nested context
NDC.push("UserService");
logger.info("Starting user operation"); // Context: [UserService]
NDC.push("validateUser");
logger.debug("Validating user credentials"); // Context: [UserService, validateUser]
NDC.push("checkDatabase");
logger.debug("Querying user database"); // Context: [UserService, validateUser, checkDatabase]
// Check depth
int depth = NDC.getDepth(); // 3
// Peek without removing
String current = NDC.peek(); // "checkDatabase"
// Pop as operations complete
String finished = NDC.pop(); // "checkDatabase", depth now 2
logger.debug("Database check completed"); // Context: [UserService, validateUser]
NDC.pop(); // "validateUser", depth now 1
logger.info("User validation completed"); // Context: [UserService]
NDC.pop(); // "UserService", depth now 0
logger.info("User operation completed"); // Context: []
// Clear all context
NDC.clear();
// Example in method call hierarchy
public void processOrder(Order order) {
NDC.push("processOrder(" + order.getId() + ")");
try {
logger.info("Processing order");
validateOrder(order);
saveOrder(order);
notifyCustomer(order);
} finally {
NDC.pop();
}
}
private void validateOrder(Order order) {
NDC.push("validateOrder");
try {
logger.debug("Validating order data");
// validation logic
} finally {
NDC.pop();
}
}Guidelines for effective use of diagnostic contexts.
MDC Best Practices:
// Use try-finally to ensure cleanup
public void handleRequest(HttpServletRequest request) {
try {
MDC.put("requestId", generateRequestId());
MDC.put("userId", getCurrentUserId());
// Process request
processRequest(request);
} finally {
// Always clean up to prevent memory leaks
MDC.clear();
}
}
// Use meaningful, consistent key names
MDC.put("user.id", userId);
MDC.put("session.id", sessionId);
MDC.put("request.method", request.getMethod());
MDC.put("request.uri", request.getRequestURI());NDC Best Practices:
// Use try-finally pattern for NDC as well
public void complexOperation() {
NDC.push("complexOperation");
try {
logger.info("Starting complex operation");
subOperation1();
subOperation2();
logger.info("Complex operation completed");
} finally {
NDC.pop();
}
}
// Use descriptive context names
NDC.push("OrderService.processPayment");
NDC.push("PaymentGateway.authorizeCard");
NDC.push("BankAPI.validateAccount");Combined Usage:
// MDC for request-wide context, NDC for call hierarchy
public void processUserRequest(String userId, String operation) {
try {
// Set request context with MDC
MDC.put("userId", userId);
MDC.put("operation", operation);
MDC.put("timestamp", Instant.now().toString());
// Track call hierarchy with NDC
NDC.push("processUserRequest");
logger.info("Processing user request");
performOperation(operation);
} finally {
NDC.clear();
MDC.clear();
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-slf4j--log4j-over-slf4j