CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-logging-log4j--log4j-1-2-api

The Apache Log4j 1.x Compatibility API providing a bridge to Log4j 2.x implementations

Pending
Overview
Eval results
Files

context.mddocs/

Thread Context

Thread context provides thread-local diagnostic information storage through MDC (Mapped Diagnostic Context) and NDC (Nested Diagnostic Context). This enables context-aware logging across application threads.

Mapped Diagnostic Context (MDC)

MDC Class

public final class MDC {
    // Context management
    public static void put(String key, String value);
    public static Object get(String key);
    public static String get(String key, String defaultValue);
    public static void remove(String key);
    public static void clear();
    
    // Context retrieval
    public static Hashtable<String, Object> getContext();
    public static Map<String, String> getCopyOfContextMap();
    public static void setContextMap(Map<String, String> contextMap);
    
    // Utility methods
    public static Set<String> getKeys();
    public static boolean isEmpty();
}

Parameters:

  • key - String key for the context value
  • value - String value to store
  • defaultValue - String default value if key not found
  • contextMap - Map of context key-value pairs

Returns:

  • Object or String value for the specified key
  • Hashtable<String, Object> current context
  • Map<String, String> copy of context map
  • Set<String> set of all keys
  • boolean indicating if context is empty

Nested Diagnostic Context (NDC)

NDC Class

public final class NDC {
    // Stack operations
    public static void push(String message);
    public static String pop();
    public static String peek();
    public static void clear();
    public static void remove();
    
    // Stack information
    public static int getDepth();
    public static Stack cloneStack();
    public static void inherit(Stack stack);
    
    // Formatting
    public static String get();
}

Parameters:

  • message - String message to push onto the stack
  • stack - Stack to inherit from another thread

Returns:

  • String popped or peeked message
  • int current stack depth
  • Stack cloned copy of current stack
  • String formatted NDC string

MDC Usage Patterns

Basic MDC Operations

import org.apache.log4j.MDC;
import org.apache.log4j.Logger;

public class MDCExample {
    private static final Logger logger = Logger.getLogger(MDCExample.class);
    
    public void processUserRequest(String userId, String sessionId) {
        // Set context information
        MDC.put("userId", userId);
        MDC.put("sessionId", sessionId);
        MDC.put("operation", "processRequest");
        
        try {
            logger.info("Starting user request processing");
            
            // Business logic
            processBusinessLogic();
            
            logger.info("User request completed successfully");
        } catch (Exception e) {
            logger.error("User request failed", e);
        } finally {
            // Clean up context
            MDC.clear();
        }
    }
    
    private void processBusinessLogic() {
        // This method can access MDC context
        String userId = (String) MDC.get("userId");
        logger.debug("Processing business logic for user: " + userId);
        
        // Add more context
        MDC.put("step", "validation");
        validateUserData();
        
        MDC.put("step", "processing");
        performProcessing();
        
        MDC.remove("step");
    }
    
    private void validateUserData() {
        logger.debug("Validating user data");
    }
    
    private void performProcessing() {
        logger.debug("Performing main processing");
    }
}

Web Application MDC Filter

import org.apache.log4j.MDC;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;

public class MDCFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        
        try {
            // Set request-specific context
            MDC.put("requestId", UUID.randomUUID().toString());
            MDC.put("remoteAddr", request.getRemoteAddr());
            MDC.put("requestURI", httpRequest.getRequestURI());
            MDC.put("method", httpRequest.getMethod());
            
            // Add user context if available
            String userId = httpRequest.getRemoteUser();
            if (userId != null) {
                MDC.put("userId", userId);
            }
            
            // Continue filter chain
            chain.doFilter(request, response);
            
        } finally {
            // Always clean up MDC
            MDC.clear();
        }
    }
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Filter initialization
    }
    
    @Override
    public void destroy() {
        // Filter cleanup
    }
}

MDC Context Map Operations

import org.apache.log4j.MDC;
import java.util.Map;
import java.util.HashMap;

public class MDCContextExample {
    
    public void demonstrateContextOperations() {
        // Set individual values
        MDC.put("user", "john");
        MDC.put("session", "abc123");
        MDC.put("operation", "login");
        
        // Get context copy
        Map<String, String> contextCopy = MDC.getCopyOfContextMap();
        System.out.println("Current context: " + contextCopy);
        
        // Check if context is empty
        boolean isEmpty = MDC.isEmpty();
        System.out.println("Context empty: " + isEmpty);
        
        // Get all keys
        Set<String> keys = MDC.getKeys();
        System.out.println("Context keys: " + keys);
        
        // Create new context map
        Map<String, String> newContext = new HashMap<>();
        newContext.put("service", "authentication");
        newContext.put("version", "1.0");
        
        // Replace entire context
        MDC.setContextMap(newContext);
        
        // Verify change
        System.out.println("New context: " + MDC.getCopyOfContextMap());
        
        // Clear all
        MDC.clear();
    }
}

NDC Usage Patterns

Basic NDC Operations

import org.apache.log4j.NDC;
import org.apache.log4j.Logger;

public class NDCExample {
    private static final Logger logger = Logger.getLogger(NDCExample.class);
    
    public void processOrder(String orderId) {
        NDC.push("OrderService");
        NDC.push("orderId=" + orderId);
        
        try {
            logger.info("Starting order processing");
            
            validateOrder();
            processPayment();
            fulfillOrder();
            
            logger.info("Order processing completed");
        } catch (Exception e) {
            logger.error("Order processing failed", e);
        } finally {
            // Pop all contexts for this operation
            NDC.pop(); // Remove orderId
            NDC.pop(); // Remove OrderService
        }
    }
    
    private void validateOrder() {
        NDC.push("validation");
        try {
            logger.debug("Validating order details");
            // Validation logic
        } finally {
            NDC.pop();
        }
    }
    
    private void processPayment() {
        NDC.push("payment");
        try {
            logger.debug("Processing payment");
            // Payment logic
        } finally {
            NDC.pop();
        }
    }
    
    private void fulfillOrder() {
        NDC.push("fulfillment");
        try {
            logger.debug("Fulfilling order");
            // Fulfillment logic
        } finally {
            NDC.pop();
        }
    }
}

NDC Stack Management

import org.apache.log4j.NDC;
import org.apache.log4j.Logger;
import java.util.Stack;

public class NDCStackExample {
    private static final Logger logger = Logger.getLogger(NDCStackExample.class);
    
    public void demonstrateStackOperations() {
        // Build up context stack
        NDC.push("Application");
        NDC.push("UserService");
        NDC.push("createUser");
        
        // Check stack depth
        int depth = NDC.getDepth();
        logger.info("Current NDC depth: " + depth);
        
        // Peek at top without removing
        String top = NDC.peek();
        logger.info("Top of stack: " + top);
        
        // Get full NDC string
        String fullContext = NDC.get();
        logger.info("Full NDC context: " + fullContext);
        
        // Clone stack for another thread
        Stack<String> stackCopy = NDC.cloneStack();
        
        // Pop one level
        String popped = NDC.pop();
        logger.info("Popped: " + popped);
        logger.info("Remaining context: " + NDC.get());
        
        // Clear all
        NDC.clear();
        logger.info("After clear, depth: " + NDC.getDepth());
        
        // Restore from clone
        NDC.inherit(stackCopy);
        logger.info("After inherit: " + NDC.get());
        
        // Final cleanup
        NDC.remove();
    }
}

Thread Context Inheritance

import org.apache.log4j.MDC;
import org.apache.log4j.NDC;
import org.apache.log4j.Logger;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadContextInheritance {
    private static final Logger logger = Logger.getLogger(ThreadContextInheritance.class);
    
    public void processWithThreads() {
        // Set up context in main thread
        MDC.put("mainThread", "true");
        MDC.put("operation", "multiThreadProcess");
        NDC.push("MainProcessor");
        
        // Capture context for inheritance
        Map<String, String> mdcContext = MDC.getCopyOfContextMap();
        Stack ndcStack = NDC.cloneStack();
        
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        for (int i = 0; i < 3; i++) {
            final int taskId = i;
            executor.submit(() -> {
                try {
                    // Inherit context from parent thread
                    MDC.setContextMap(mdcContext);
                    NDC.inherit(ndcStack);
                    
                    // Add thread-specific context
                    MDC.put("threadId", String.valueOf(taskId));
                    NDC.push("Worker-" + taskId);
                    
                    logger.info("Processing task in worker thread");
                    
                    // Simulate work
                    Thread.sleep(1000);
                    
                    logger.info("Task completed in worker thread");
                    
                } catch (InterruptedException e) {
                    logger.warn("Thread interrupted", e);
                } finally {
                    // Clean up thread context
                    MDC.clear();
                    NDC.remove();
                }
            });
        }
        
        executor.shutdown();
        
        // Clean up main thread context
        MDC.clear();
        NDC.clear();
    }
}

Pattern Layout Integration

Using MDC in Pattern Layouts

import org.apache.log4j.*;

public class ContextPatternExample {
    
    public void setupContextLogging() {
        // Pattern that includes MDC values
        PatternLayout mdcPattern = new PatternLayout(
            "%d{ISO8601} [%t] %-5p %c - [%X{userId}:%X{sessionId}] %m%n"
        );
        
        // Pattern that includes specific MDC keys
        PatternLayout specificMDC = new PatternLayout(
            "%d %-5p %c - User:%X{userId} Session:%X{sessionId} - %m%n"
        );
        
        // Pattern that includes NDC
        PatternLayout ndcPattern = new PatternLayout(
            "%d %-5p %c %x - %m%n"
        );
        
        // Pattern with both MDC and NDC
        PatternLayout combinedPattern = new PatternLayout(
            "%d [%t] %-5p %c - %X{userId} %x - %m%n"
        );
        
        // Create appenders
        ConsoleAppender mdcAppender = new ConsoleAppender(mdcPattern);
        ConsoleAppender ndcAppender = new ConsoleAppender(ndcPattern);
        
        // Configure loggers
        Logger mdcLogger = Logger.getLogger("mdc-logger");
        mdcLogger.addAppender(mdcAppender);
        
        Logger ndcLogger = Logger.getLogger("ndc-logger");  
        ndcLogger.addAppender(ndcAppender);
    }
}

Best Practices

Context Cleanup Patterns

import org.apache.log4j.MDC;
import org.apache.log4j.NDC;
import org.apache.log4j.Logger;

public class ContextCleanupExample {
    private static final Logger logger = Logger.getLogger(ContextCleanupExample.class);
    
    // Using try-with-resources pattern for MDC
    public static class MDCCloseable implements AutoCloseable {
        public MDCCloseable(String key, String value) {
            MDC.put(key, value);
        }
        
        @Override
        public void close() {
            MDC.clear();
        }
    }
    
    // Using try-with-resources pattern for NDC
    public static class NDCCloseable implements AutoCloseable {
        public NDCCloseable(String context) {
            NDC.push(context);
        }
        
        @Override
        public void close() {
            NDC.pop();
        }
    }
    
    public void processWithAutoCleanup(String userId, String operation) {
        // MDC with automatic cleanup
        try (MDCCloseable mdcContext = new MDCCloseable("userId", userId)) {
            MDC.put("operation", operation);
            
            // NDC with automatic cleanup
            try (NDCCloseable ndcContext = new NDCCloseable("ProcessorService")) {
                
                logger.info("Starting processing with auto-cleanup");
                
                // Business logic here
                performBusinessLogic();
                
                logger.info("Processing completed");
                
            } // NDC automatically popped here
        } // MDC automatically cleared here
    }
    
    // Manual cleanup with finally blocks
    public void processWithManualCleanup(String userId, String operation) {
        // Set up MDC
        MDC.put("userId", userId);
        MDC.put("operation", operation);
        
        // Set up NDC
        NDC.push("ManualService");
        
        try {
            logger.info("Starting processing with manual cleanup");
            
            performBusinessLogic();
            
            logger.info("Processing completed");
            
        } catch (Exception e) {
            logger.error("Processing failed", e);
            throw e;
        } finally {
            // Always clean up in reverse order
            NDC.pop(); // Remove ManualService
            MDC.clear(); // Clear all MDC values
        }
    }
    
    private void performBusinessLogic() {
        // This method inherits the context
        logger.debug("Performing business logic");
        
        // Can add temporary context
        MDC.put("step", "validation");
        NDC.push("validator");
        
        try {
            logger.debug("Validating input");
            // Validation logic
        } finally {
            // Clean up temporary context
            NDC.pop();
            MDC.remove("step");
        }
    }
}

Context Performance Considerations

import org.apache.log4j.MDC;
import org.apache.log4j.Logger;

public class ContextPerformanceExample {
    private static final Logger logger = Logger.getLogger(ContextPerformanceExample.class);
    
    public void efficientContextUsage() {
        // Avoid expensive operations in context values
        String userId = getCurrentUserId(); // Expensive call
        MDC.put("userId", userId); // Store result, don't call repeatedly
        
        // Use conditional logging to avoid context lookups
        if (logger.isDebugEnabled()) {
            String contextInfo = buildContextInfo(); // Only when needed
            logger.debug("Context info: " + contextInfo);
        }
        
        // Prefer specific key access over full context maps
        String user = (String) MDC.get("userId"); // Efficient
        // Map<String, String> fullContext = MDC.getCopyOfContextMap(); // Less efficient
        
        // Clean up promptly to avoid memory leaks
        MDC.clear();
    }
    
    private String getCurrentUserId() {
        // Simulate expensive operation
        return "user123";
    }
    
    private String buildContextInfo() {
        // Build debug info only when needed
        return "User: " + MDC.get("userId") + ", Session: " + MDC.get("sessionId");
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-logging-log4j--log4j-1-2-api

docs

appenders.md

builders.md

configuration.md

context.md

index.md

layouts.md

logging.md

spi.md

tile.json