CtrlK
BlogDocsLog inGet started
Tessl Logo

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

The logging API of the Log4j project providing a comprehensive and flexible logging framework for Java applications.

Pending
Overview
Eval results
Files

message-system.mddocs/

Message System & Formatting

Comprehensive message creation system supporting multiple formatting syntaxes, structured data, flow tracing, and custom message factories for specialized use cases.

Capabilities

Message Interface

Base interface for all log message types providing formatted output and metadata access.

/**
 * Base interface for all log message types
 */
public interface Message extends Serializable {
    /** Get the formatted message string */
    String getFormattedMessage();
    
    /** Get message parameters array */
    Object[] getParameters();
    
    /** Get associated throwable if any */
    Throwable getThrowable();
    
    /** @Deprecated Get message format string */
    @Deprecated
    String getFormat();
}

Usage Examples:

private static final Logger logger = LogManager.getLogger();

public void demonstrateMessageInterface() {
    // Messages are typically created internally by the logging framework
    // but can be created explicitly for advanced use cases
    
    Message simpleMsg = new SimpleMessage("Hello World");
    logger.info(simpleMsg);
    
    Message paramMsg = new ParameterizedMessage("User {} has {} items", "alice", 5);
    logger.info(paramMsg);
    
    // Access message components
    String formatted = paramMsg.getFormattedMessage(); // "User alice has 5 items"
    Object[] params = paramMsg.getParameters(); // ["alice", 5]
}

MessageFactory Interface

Factory for creating Message instances with different formatting syntaxes.

/**
 * Factory interface for creating Message instances
 */
public interface MessageFactory {
    /** Create message from object */
    Message newMessage(Object message);
    
    /** Create message from string */
    Message newMessage(String message);
    
    /** Create parameterized message */
    Message newMessage(String message, Object... params);
}

/**
 * Extended message factory with additional methods
 */
public interface MessageFactory2 extends MessageFactory {
    /** Create message from string with single parameter */
    Message newMessage(String message, Object p0);
    
    /** Create message from string with two parameters */
    Message newMessage(String message, Object p0, Object p1);
    
    // Additional overloads for up to 10 parameters for performance
    Message newMessage(String message, Object p0, Object p1, Object p2);
    // ... more overloads
}

Usage Examples:

public void demonstrateMessageFactories() {
    // Different message factories create different message types
    
    // Parameterized message factory (default, uses {} placeholders)
    MessageFactory paramFactory = ParameterizedMessageFactory.INSTANCE;
    Message msg1 = paramFactory.newMessage("User {} logged in", "alice");
    
    // String formatter message factory (uses String.format style)
    MessageFactory stringFactory = StringFormatterMessageFactory.INSTANCE;
    Message msg2 = stringFactory.newMessage("User %s has %d items", "alice", 5);
    
    // Simple message factory (no parameter substitution)
    MessageFactory simpleFactory = SimpleMessageFactory.INSTANCE;
    Message msg3 = simpleFactory.newMessage("Simple message");
    
    // Reusable message factory (for high-performance scenarios)
    MessageFactory reusableFactory = ReusableMessageFactory.INSTANCE;
    Message msg4 = reusableFactory.newMessage("Reusable: {}", value);
}

// Custom message factory
public class CustomMessageFactory implements MessageFactory {
    
    @Override
    public Message newMessage(Object message) {
        return new CustomMessage(message);
    }
    
    @Override
    public Message newMessage(String message) {
        return new CustomMessage(message);
    }
    
    @Override
    public Message newMessage(String message, Object... params) {
        return new CustomParameterizedMessage(message, params);
    }
}

Core Message Types

Built-in message implementations for different formatting and data representation needs.

/**
 * Simple string message without parameter substitution
 */
public class SimpleMessage implements CharSequence, Message {
    public SimpleMessage(CharSequence message);
    public SimpleMessage(Object message);
}

/**
 * Message with {} parameter placeholders (most commonly used)
 */
public class ParameterizedMessage implements Message {
    public ParameterizedMessage(String messagePattern, Object[] arguments);
    public ParameterizedMessage(String messagePattern, Object... arguments);
    public ParameterizedMessage(String messagePattern, Object arg);
    public ParameterizedMessage(String messagePattern, Object arg1, Object arg2);
    
    /** Get count of parameters */
    public int getParameterCount();
    
    /** Get the message pattern */
    public String getFormat();
    
    /** Get throwable if last parameter is Throwable */
    @Override
    public Throwable getThrowable();
}

/**
 * Message wrapping arbitrary objects
 */
public class ObjectMessage implements Message {
    public ObjectMessage(Object obj);
    
    /** Get the wrapped object */
    public Object getParameter();
}

/**
 * Message using String.format() style formatting
 */
public class StringFormattedMessage implements Message {
    public StringFormattedMessage(String messagePattern, Object... arguments);
}

/**
 * @Deprecated Message using java.text.MessageFormat
 */
@Deprecated
public class FormattedMessage implements Message {
    public FormattedMessage(String messagePattern, Object... arguments);
}

Usage Examples:

private static final Logger logger = LogManager.getLogger();

public void demonstrateMessageTypes() {
    // Simple message - no parameter substitution
    SimpleMessage simple = new SimpleMessage("Simple log message");
    logger.info(simple);
    
    // Parameterized message - {} placeholders (most efficient)
    ParameterizedMessage param = new ParameterizedMessage(
        "User {} performed {} action at {}", "alice", "login", new Date());
    logger.info(param);
    
    // Object message - wraps any object
    ObjectMessage objMsg = new ObjectMessage(new UserProfile("alice", 25));
    logger.info(objMsg); // Uses object's toString()
    
    // String formatted message - String.format() style
    StringFormattedMessage formatted = new StringFormattedMessage(
        "User %s has %d items (%.2f%% complete)", "alice", 5, 75.5);
    logger.info(formatted);
    
    // Automatic throwable detection in parameterized messages
    Exception ex = new RuntimeException("test");
    ParameterizedMessage withEx = new ParameterizedMessage(
        "Error processing user {}", "alice", ex); // Exception automatically extracted
    logger.error(withEx); // Exception will be logged separately
    
    // Access message properties
    String pattern = param.getFormat(); // Original pattern: "User {} performed {} action at {}"
    Object[] params = param.getParameters(); // ["alice", "login", Date]
    int paramCount = param.getParameterCount(); // 3
}

// Custom object message usage
public class UserProfile {
    private String name;
    private int age;
    
    public UserProfile(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return String.format("UserProfile{name='%s', age=%d}", name, age);
    }
}

public void logUserProfile() {
    UserProfile profile = new UserProfile("alice", 25);
    
    // Object message will use toString()
    logger.info(new ObjectMessage(profile)); 
    // Output: UserProfile{name='alice', age=25}
    
    // Parameterized message with object
    logger.info("User profile: {}", profile);
    // Output: User profile: UserProfile{name='alice', age=25}
}

Structured Data Messages

Messages that represent structured key-value data, particularly useful for logging events and metrics.

/**
 * Message representing key-value pairs
 */
public class MapMessage implements Message {
    public MapMessage();
    public MapMessage(Map<String, Object> map);
    
    /** Put a key-value pair */
    public MapMessage with(String key, Object value);
    
    /** Put a key-value pair (fluent API) */
    public MapMessage put(String key, Object value);
    
    /** Get value by key */
    public Object get(String key);
    
    /** Remove key */
    public Object remove(String key);
    
    /** Get all keys */
    public String[] getKeys();
    
    /** Check if key exists */
    public boolean containsKey(String key);
    
    /** Get as Map */
    public Map<String, Object> getData();
    
    /** Clear all data */
    public void clear();
}

/**
 * RFC 5424 Structured Data message
 */
public class StructuredDataMessage extends MapMessage {
    public StructuredDataMessage(String id, Map<String, String> data, String message);
    public StructuredDataMessage(String id, Map<String, String> data, String message, Object... args);
    
    /** Get structured data ID */
    public String getId();
    
    /** Get structured data as RFC 5424 format */
    public String asString();
    
    /** Get structured data as RFC 5424 format with specified format */
    public String asString(String format);
}

Usage Examples:

private static final Logger logger = LogManager.getLogger();

public void demonstrateStructuredMessages() {
    // Map message for structured logging
    MapMessage mapMsg = new MapMessage()
        .with("userId", "12345")
        .with("action", "login")
        .with("timestamp", System.currentTimeMillis())
        .with("success", true)
        .with("duration", 150);
    
    logger.info(mapMsg);
    // Output: userId="12345" action="login" timestamp="1634567890123" success="true" duration="150"
    
    // Structured data message (RFC 5424 compliant)
    Map<String, String> eventData = new HashMap<>();
    eventData.put("userId", "12345");
    eventData.put("sessionId", "abc-def-ghi");
    eventData.put("remoteAddr", "192.168.1.100");
    
    StructuredDataMessage sdMsg = new StructuredDataMessage(
        "loginEvent", eventData, "User {} logged in successfully", "alice");
    
    logger.info(sdMsg);
    // Output: [loginEvent userId="12345" sessionId="abc-def-ghi" remoteAddr="192.168.1.100"] User alice logged in successfully
    
    // Building map messages fluently
    MapMessage auditMsg = new MapMessage()
        .put("event", "fileAccess")
        .put("file", "/etc/passwd")
        .put("user", "admin")
        .put("result", "denied");
    
    logger.warn(auditMsg);
}

// Business event logging with structured data
public class EventLogger {
    private static final Logger logger = LogManager.getLogger();
    
    public void logUserAction(String userId, String action, boolean successful, long duration) {
        MapMessage event = new MapMessage()
            .with("userId", userId)
            .with("action", action)
            .with("successful", successful)
            .with("duration", duration)
            .with("timestamp", Instant.now().toString());
        
        if (successful) {
            logger.info(event);
        } else {
            logger.warn(event);
        }
    }
    
    public void logOrderEvent(Order order, String event) {
        StructuredDataMessage sdMsg = new StructuredDataMessage(
            "orderEvent",
            Map.of(
                "orderId", order.getId(),
                "customerId", order.getCustomerId(),
                "amount", order.getAmount().toString(),
                "currency", order.getCurrency()
            ),
            "Order {} event: {}", order.getId(), event);
        
        logger.info(sdMsg);
    }
}

Flow Messages

Specialized messages for method entry/exit tracing and flow control logging.

/**
 * Message for method entry logging
 */
public class EntryMessage implements Message {
    public EntryMessage(String format, Object... params);
    
    /** Get the message for entry */
    public Message getMessage();
}

/**
 * Message for method exit logging
 */
public class ExitMessage implements Message {
    public ExitMessage(EntryMessage message, Object result, long durationNanos);
    public ExitMessage(String format, Object result, long durationNanos);
    
    /** Get the result object */
    public Object getResult();
    
    /** Get execution duration in nanoseconds */
    public long getDurationNanos();
    
    /** Get the entry message */
    public EntryMessage getEntryMessage();
}

/**
 * Factory for creating flow messages
 */
public interface FlowMessageFactory {
    EntryMessage newEntryMessage(Message message);
    ExitMessage newExitMessage(EntryMessage message, Object result, long durationNanos);
    ExitMessage newExitMessage(Object result, Message message);
}

/**
 * Default flow message factory implementation
 */
public class DefaultFlowMessageFactory implements FlowMessageFactory {
    public static final DefaultFlowMessageFactory INSTANCE = new DefaultFlowMessageFactory();
}

Usage Examples:

private static final Logger logger = LogManager.getLogger();

public class FlowTrackingService {
    
    // Manual flow message creation
    public String processUser(String userId) {
        EntryMessage entryMsg = new EntryMessage("processUser(userId={})", userId);
        logger.traceEntry(entryMsg);
        
        long startTime = System.nanoTime();
        try {
            // Process user
            String result = "processed-" + userId;
            
            long duration = System.nanoTime() - startTime;
            ExitMessage exitMsg = new ExitMessage(entryMsg, result, duration);
            logger.traceExit(exitMsg);
            
            return result;
            
        } catch (Exception e) {
            logger.throwing(e);
            throw e;
        }
    }
    
    // Using Logger's built-in flow methods (preferred)
    public User findUser(Long id) {
        logger.traceEntry("findUser(id={})", id);
        
        try {
            User user = userRepository.findById(id);
            return logger.traceExit(user);
        } catch (Exception e) {
            throw logger.throwing(e);
        }
    }
    
    // Complex flow with multiple parameters
    public Order createOrder(String customerId, List<OrderItem> items, PaymentInfo payment) {
        logger.traceEntry("customerId={}, itemCount={}, paymentMethod={}", 
                         customerId, items.size(), payment.getMethod());
        
        try {
            validateCustomer(customerId);
            validateItems(items);
            validatePayment(payment);
            
            Order order = new Order(customerId, items, payment);
            Order savedOrder = orderRepository.save(order);
            
            return logger.traceExit(savedOrder);
            
        } catch (Exception e) {
            throw logger.throwing(e);
        }
    }
    
    // Flow tracking with custom flow message factory
    private static final FlowMessageFactory flowFactory = DefaultFlowMessageFactory.INSTANCE;
    
    public void customFlowTracking() {
        Message entryMessage = new SimpleMessage("Starting custom operation");
        EntryMessage entry = flowFactory.newEntryMessage(entryMessage);
        logger.trace(entry);
        
        long startTime = System.nanoTime();
        try {
            String result = performOperation();
            
            long duration = System.nanoTime() - startTime;
            ExitMessage exit = flowFactory.newExitMessage(entry, result, duration);
            logger.trace(exit);
            
        } catch (Exception e) {
            logger.error("Operation failed", e);
            throw e;
        }
    }
}

Advanced Message Features

Specialized message interfaces for performance optimization and async-safe formatting.

/**
 * Messages supporting multiple output formats
 */
public interface MultiformatMessage {
    /** Get formatted message for specific format */
    String getFormattedMessage(String[] formats);
}

/**
 * Messages that can be reused to avoid object allocation
 */
public interface ReusableMessage extends Message, Clearable {
    /** Set new message content */
    ReusableMessage set(String message);
    
    /** Set new parameterized message content */
    ReusableMessage set(String message, Object... params);
    
    /** Swap contents with another reusable message */
    void swapParameters(ReusableMessage other);
}

/**
 * Messages safe for asynchronous formatting
 */
public interface AsynchronouslyFormattable {
    /** Format message asynchronously without blocking */
    String[] formatTo(StringBuilder[] buffers);
}

/**
 * Messages that can be cleared/reset
 */
public interface Clearable {
    /** Clear message content */
    void clear();
}

/**
 * Messages with embedded timestamps
 */
public interface TimestampMessage {
    /** Get message timestamp */
    long getTimestamp();
}

/**
 * Messages aware of the logger name
 */
public interface LoggerNameAwareMessage {
    /** Set logger name */
    void setLoggerName(String name);
    
    /** Get logger name */
    String getLoggerName();
}

Usage Examples:

public void demonstrateAdvancedMessageFeatures() {
    // Reusable messages for high-performance scenarios
    ReusableMessage reusableMsg = new ReusableParameterizedMessage();
    
    for (int i = 0; i < 1000; i++) {
        reusableMsg.set("Processing item {}", i);
        logger.debug(reusableMsg);
        reusableMsg.clear(); // Reset for reuse
    }
    
    // Multiformat messages
    MultiformatMessage multiMsg = new CustomMultiFormatMessage("base message");
    String xmlFormat = multiMsg.getFormattedMessage(new String[]{"xml"});
    String jsonFormat = multiMsg.getFormattedMessage(new String[]{"json"});
    
    // Timestamp-aware messages
    TimestampMessage timestampMsg = new CustomTimestampMessage("Event occurred");
    long eventTime = timestampMsg.getTimestamp();
    
    // Logger-name-aware messages
    LoggerNameAwareMessage loggerAwareMsg = new CustomLoggerAwareMessage("message");
    loggerAwareMsg.setLoggerName("com.example.MyClass");
}

// Custom async-safe message for high-throughput scenarios
public class AsyncSafeMessage implements Message, AsynchronouslyFormattable {
    private final String pattern;
    private final Object[] parameters;
    
    public AsyncSafeMessage(String pattern, Object... parameters) {
        this.pattern = pattern;
        this.parameters = parameters.clone(); // Safe copy for async access
    }
    
    @Override
    public String getFormattedMessage() {
        return ParameterizedMessage.format(pattern, parameters);
    }
    
    @Override
    public String[] formatTo(StringBuilder[] buffers) {
        // Format to provided buffers for async processing
        String formatted = getFormattedMessage();
        buffers[0].append(formatted);
        return new String[]{formatted};
    }
    
    @Override
    public Object[] getParameters() {
        return parameters.clone(); // Return safe copy
    }
    
    @Override
    public Throwable getThrowable() {
        // Check if last parameter is throwable
        if (parameters.length > 0 && parameters[parameters.length - 1] instanceof Throwable) {
            return (Throwable) parameters[parameters.length - 1];
        }
        return null;
    }
}

Install with Tessl CLI

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

docs

core-logging.md

index.md

markers.md

message-system.md

performance-features.md

spi.md

status-system.md

thread-context.md

tile.json