CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-logging-log4j--log4j-slf4j2-impl

SLF4J 2 provider that bridges SLF4J 2 logging calls to the Apache Log4j API

Pending
Overview
Eval results
Files

mdc-support.mddocs/

MDC Support

Mapped Diagnostic Context (MDC) provides thread-local context management for adding contextual information to log events. The implementation uses Log4j's ThreadContext as the backing store, providing both map-based and stack-based context storage.

Capabilities

Basic MDC Operations

Core MDC functionality for managing key-value pairs in the current thread's context.

/**
 * Put a key-value pair into the MDC
 * @param key The key
 * @param val The value
 */
void put(String key, String val);

/**
 * Get a value from the MDC by key
 * @param key The key
 * @return The value or null if not found
 */
String get(String key);

/**
 * Remove a key from the MDC
 * @param key The key to remove
 */
void remove(String key);

/**
 * Clear all entries from the MDC
 */
void clear();

Usage Examples:

import org.slf4j.MDC;

// Basic MDC usage
MDC.put("userId", "12345");
MDC.put("requestId", "req-abc-123");
MDC.put("sessionId", "sess-xyz-789");

// Use in logging - values automatically included in log output
logger.info("Processing user request");

// Retrieve values
String userId = MDC.get("userId");
String requestId = MDC.get("requestId");

// Remove specific key
MDC.remove("sessionId");

// Clear all MDC data for current thread
MDC.clear();

MDC Context Management

Manage entire MDC context maps for bulk operations and context preservation.

/**
 * Get a copy of the current MDC context map
 * @return Copy of the context map (null if empty)
 */
Map<String, String> getCopyOfContextMap();

/**
 * Set the entire MDC context map
 * @param contextMap The context map to set (clears existing first)
 */
void setContextMap(Map<String, String> contextMap);

Usage Examples:

// Save current context
Map<String, String> savedContext = MDC.getCopyOfContextMap();

// Set new context
Map<String, String> newContext = new HashMap<>();
newContext.put("operation", "batch-processing");
newContext.put("batchId", "batch-001");
newContext.put("worker", "worker-thread-1");
MDC.setContextMap(newContext);

// Perform operations with new context
logger.info("Starting batch processing");
processBatch();

// Restore previous context
if (savedContext != null) {
    MDC.setContextMap(savedContext);
} else {
    MDC.clear();
}

Stack-Based MDC Operations

Advanced MDC functionality supporting stack-based context management for nested operations.

/**
 * Push a value onto a keyed stack in the MDC
 * @param key The stack key (null for default stack)
 * @param value The value to push
 */
void pushByKey(String key, String value);

/**
 * Pop a value from a keyed stack in the MDC
 * @param key The stack key (null for default stack)
 * @return The popped value or null if stack is empty
 */
String popByKey(String key);

/**
 * Get a copy of the deque for a specific key
 * @param key The stack key (null for default stack)
 * @return Copy of the deque or null if not found
 */
Deque<String> getCopyOfDequeByKey(String key);

/**
 * Clear the deque for a specific key
 * @param key The stack key (null for default stack)
 */
void clearDequeByKey(String key);

Usage Examples:

// Stack-based context for nested operations
MDC.pushByKey("operation", "user-service");
MDC.pushByKey("operation", "authenticate");
MDC.pushByKey("operation", "validate-token");

logger.info("Validating authentication token");

// Pop back through the operation stack
MDC.popByKey("operation"); // removes "validate-token"
logger.info("Token validated, checking permissions");

MDC.popByKey("operation"); // removes "authenticate"
logger.info("Authentication completed");

MDC.popByKey("operation"); // removes "user-service"

// Default stack operations (key = null)
MDC.pushByKey(null, "context1");
MDC.pushByKey(null, "context2");
String current = MDC.popByKey(null); // returns "context2"

// Inspect stack contents
Deque<String> operationStack = MDC.getCopyOfDequeByKey("operation");
if (operationStack != null) {
    logger.debug("Current operation stack depth: {}", operationStack.size());
}

// Clear specific stack
MDC.clearDequeByKey("operation");

Common MDC Patterns

Request Context Pattern

// Web request processing
public void processRequest(HttpServletRequest request) {
    try {
        // Set request context
        MDC.put("requestId", generateRequestId());
        MDC.put("userId", extractUserId(request));
        MDC.put("userAgent", request.getHeader("User-Agent"));
        MDC.put("remoteAddr", request.getRemoteAddr());
        MDC.put("method", request.getMethod());
        MDC.put("uri", request.getRequestURI());
        
        logger.info("Processing request");
        
        // All subsequent logging in this thread includes context
        handleRequest(request);
        
        logger.info("Request completed successfully");
        
    } catch (Exception e) {
        logger.error("Request failed", e);
    } finally {
        // Always clean up MDC
        MDC.clear();
    }
}

Transaction Context Pattern

// Database transaction context
public void executeInTransaction(String transactionType, Runnable operation) {
    String transactionId = generateTransactionId();
    
    try {
        MDC.put("transactionId", transactionId);
        MDC.put("transactionType", transactionType);
        MDC.put("threadName", Thread.currentThread().getName());
        
        logger.info("Starting transaction");
        
        operation.run();
        
        logger.info("Transaction completed");
        
    } catch (Exception e) {
        logger.error("Transaction failed", e);
        throw e;
    } finally {
        MDC.remove("transactionId");
        MDC.remove("transactionType");
        MDC.remove("threadName");
    }
}

Nested Operation Context

// Service layer with nested operations
public class UserService {
    
    public void createUser(User user) {
        MDC.put("operation", "createUser");
        MDC.put("userId", user.getId());
        
        try {
            logger.info("Creating user");
            
            validateUser(user);
            saveUser(user);
            sendWelcomeEmail(user);
            
            logger.info("User created successfully");
            
        } finally {
            MDC.remove("operation");
            MDC.remove("userId");
        }
    }
    
    private void validateUser(User user) {
        // Push nested operation context
        MDC.pushByKey("subOperation", "validation");
        
        try {
            logger.debug("Validating user data");
            // validation logic
        } finally {
            MDC.popByKey("subOperation");
        }
    }
    
    private void saveUser(User user) {
        MDC.pushByKey("subOperation", "database-save");
        
        try {
            logger.debug("Saving user to database");
            // save logic
        } finally {
            MDC.popByKey("subOperation");
        }
    }
}

Async Processing Context

// Preserving context across async boundaries
public CompletableFuture<String> processAsync(String data) {
    // Capture current MDC context
    Map<String, String> currentContext = MDC.getCopyOfContextMap();
    
    return CompletableFuture.supplyAsync(() -> {
        try {
            // Restore context in async thread
            if (currentContext != null) {
                MDC.setContextMap(currentContext);
            }
            
            MDC.put("asyncOperation", "data-processing");
            
            logger.info("Processing data asynchronously");
            
            // Process data
            String result = performDataProcessing(data);
            
            logger.info("Async processing completed");
            
            return result;
            
        } finally {
            // Clean up context in async thread
            MDC.clear();
        }
    });
}

Context Inheritance Pattern

// Parent-child context inheritance
public void parentOperation() {
    MDC.put("parentOperation", "batch-job");
    MDC.put("batchId", "batch-12345");
    
    try {
        logger.info("Starting batch job");
        
        for (int i = 0; i < items.size(); i++) {
            processItem(items.get(i), i);
        }
        
        logger.info("Batch job completed");
        
    } finally {
        MDC.clear();
    }
}

private void processItem(Item item, int index) {
    // Inherit parent context and add item-specific context
    MDC.put("itemIndex", String.valueOf(index));
    MDC.put("itemId", item.getId());
    
    try {
        logger.debug("Processing item");
        
        // Item processing logic
        performItemProcessing(item);
        
        logger.debug("Item processed successfully");
        
    } catch (Exception e) {
        logger.error("Item processing failed", e);
    } finally {
        // Remove item-specific context but keep parent context
        MDC.remove("itemIndex");
        MDC.remove("itemId");
    }
}

Integration with Log4j Configuration

MDC values can be referenced in Log4j configuration patterns:

<!-- log4j2.xml pattern configuration -->
<Configuration>
    <Appenders>
        <Console name="Console">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level [%X{requestId}] [%X{userId}] %logger{36} - %msg%n"/>
        </Console>
        <File name="FileAppender" fileName="app.log">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%X] %logger{36} - %msg%n"/>
        </File>
    </Appenders>
</Configuration>

Performance Considerations

  • MDC operations are thread-local and generally very fast
  • Consider the overhead of frequent put/remove operations in tight loops
  • Use try-finally blocks to ensure cleanup
  • Be mindful of memory usage with long-running threads
// Efficient MDC usage
public void efficientLogging() {
    // Set context once for multiple operations
    MDC.put("operation", "bulk-processing");
    
    try {
        for (Item item : items) {
            // Only update changing context
            MDC.put("itemId", item.getId());
            
            processItem(item);
            
            // Remove only the changing context
            MDC.remove("itemId");
        }
    } finally {
        // Clean up operation context
        MDC.remove("operation");
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-logging-log4j--log4j-slf4j2-impl

docs

fluent-logging.md

index.md

marker-logging.md

marker-management.md

mdc-support.md

standard-logging.md

tile.json