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

fluent-logging.mddocs/

Fluent Logging API

SLF4J 2.x fluent interface for building complex log events with structured data, lazy evaluation, and method chaining. This API enables modern logging patterns with key-value pairs, conditional logging, and deferred message construction.

Capabilities

Event Builder Creation

Create fluent logging event builders for each log level.

/**
 * Create a fluent logging event builder at TRACE level
 * @return LoggingEventBuilder for TRACE level
 */
LoggingEventBuilder atTrace();

/**
 * Create a fluent logging event builder at DEBUG level
 * @return LoggingEventBuilder for DEBUG level
 */
LoggingEventBuilder atDebug();

/**
 * Create a fluent logging event builder at INFO level
 * @return LoggingEventBuilder for INFO level
 */
LoggingEventBuilder atInfo();

/**
 * Create a fluent logging event builder at WARN level
 * @return LoggingEventBuilder for WARN level
 */
LoggingEventBuilder atWarn();

/**
 * Create a fluent logging event builder at ERROR level
 * @return LoggingEventBuilder for ERROR level
 */
LoggingEventBuilder atError();

Usage Examples:

// Create event builders
LoggingEventBuilder infoEvent = logger.atInfo();
LoggingEventBuilder errorEvent = logger.atError();

// Builders are only created if the level is enabled
if (logger.isDebugEnabled()) {
    LoggingEventBuilder debugEvent = logger.atDebug();
}

Basic Event Configuration

Configure basic properties of the log event.

/**
 * Set the exception cause for this log event
 * @param cause The throwable cause
 * @return This event builder for chaining
 */
LoggingEventBuilder setCause(Throwable cause);

/**
 * Add a marker to this log event
 * @param marker The marker to add
 * @return This event builder for chaining
 */
LoggingEventBuilder addMarker(Marker marker);

/**
 * Set the log message
 * @param message The message string
 * @return This event builder for chaining
 */
LoggingEventBuilder setMessage(String message);

/**
 * Set the log message using a supplier (lazy evaluation)
 * @param messageSupplier Supplier that provides the message
 * @return This event builder for chaining
 */
LoggingEventBuilder setMessage(Supplier<String> messageSupplier);

Usage Examples:

// Basic event configuration
logger.atInfo()
    .setMessage("User login successful")
    .log();

// With marker and exception
Marker securityMarker = MarkerFactory.getMarker("SECURITY");
logger.atError()
    .addMarker(securityMarker)
    .setCause(exception)
    .setMessage("Authentication failed")
    .log();

// Lazy message evaluation
logger.atDebug()
    .setMessage(() -> "Expensive computation result: " + computeExpensiveValue())
    .log();

Parameterized Messages

Add arguments for parameterized messages with type safety.

/**
 * Add an argument for parameterized message
 * @param p The argument object
 * @return This event builder for chaining
 */
LoggingEventBuilder addArgument(Object p);

/**
 * Add a lazy-evaluated argument using a supplier
 * @param objectSupplier Supplier that provides the argument
 * @return This event builder for chaining
 */
LoggingEventBuilder addArgument(Supplier<?> objectSupplier);

Usage Examples:

// Parameterized message with arguments
logger.atInfo()
    .setMessage("User {} logged in from {}")
    .addArgument(username)
    .addArgument(ipAddress)
    .log();

// Lazy argument evaluation
logger.atDebug()
    .setMessage("Processing item {} with result {}")
    .addArgument(itemId)
    .addArgument(() -> performExpensiveCalculation(itemId))
    .log();

// Multiple arguments
logger.atInfo()
    .setMessage("Transfer of ${} from {} to {} completed")
    .addArgument(amount)
    .addArgument(fromAccount)
    .addArgument(toAccount)
    .log();

Structured Data (Key-Value Pairs)

Add structured data as key-value pairs for modern observability platforms.

/**
 * Add a key-value pair to the log event
 * @param key The key name
 * @param value The value object
 * @return This event builder for chaining
 */
LoggingEventBuilder addKeyValue(String key, Object value);

/**
 * Add a key-value pair with lazy-evaluated value
 * @param key The key name
 * @param valueSupplier Supplier that provides the value
 * @return This event builder for chaining
 */
LoggingEventBuilder addKeyValue(String key, Supplier<Object> valueSupplier);

Usage Examples:

// Structured logging with key-value pairs
logger.atInfo()
    .setMessage("API request processed")
    .addKeyValue("userId", userId)
    .addKeyValue("endpoint", "/api/users")
    .addKeyValue("method", "GET")
    .addKeyValue("responseTime", responseTime)
    .addKeyValue("statusCode", 200)
    .log();

// Lazy key-value evaluation
logger.atDebug()
    .setMessage("Cache operation completed")
    .addKeyValue("operation", "get")
    .addKeyValue("key", cacheKey)
    .addKeyValue("hit", () -> cache.containsKey(cacheKey))
    .addKeyValue("size", () -> cache.size())
    .log();

// Complex structured data
logger.atWarn()
    .setMessage("Rate limit exceeded")
    .addKeyValue("clientId", clientId)
    .addKeyValue("requestsPerMinute", requestCount)
    .addKeyValue("limit", rateLimitThreshold)
    .addKeyValue("windowStart", windowStart.toString())
    .addKeyValue("action", "throttle")
    .log();

Event Execution

Execute the configured log event.

/**
 * Execute the log event with configured settings
 */
void log();

/**
 * Set message and execute the log event
 * @param message The log message
 */
void log(String message);

/**
 * Set message with one argument and execute
 * @param message The log message with placeholder
 * @param arg The argument
 */
void log(String message, Object arg);

/**
 * Set message with two arguments and execute
 * @param message The log message with placeholders
 * @param arg0 The first argument
 * @param arg1 The second argument
 */
void log(String message, Object arg0, Object arg1);

/**
 * Set message with multiple arguments and execute
 * @param message The log message with placeholders
 * @param args The arguments
 */
void log(String message, Object... args);

/**
 * Set lazy message and execute
 * @param messageSupplier Supplier that provides the message
 */
void log(Supplier<String> messageSupplier);

Usage Examples:

// Build and execute separately
LoggingEventBuilder event = logger.atInfo()
    .addKeyValue("operation", "user_creation")
    .addKeyValue("userId", newUserId);

if (isSuccessful) {
    event.setMessage("User created successfully").log();
} else {
    event.setMessage("User creation failed").log();
}

// Set message and execute in one call
logger.atInfo()
    .addKeyValue("requestId", requestId)
    .addKeyValue("duration", duration)
    .log("Request completed");

// Multiple arguments in log call
logger.atInfo()
    .addKeyValue("operation", "data_sync")
    .log("Synchronized {} records in {} ms", recordCount, duration);

Advanced Fluent Logging Patterns

Conditional Logging with Context

// Only log if specific conditions are met
if (logger.isDebugEnabled()) {
    logger.atDebug()
        .addKeyValue("threadName", Thread.currentThread().getName())
        .addKeyValue("memoryUsage", Runtime.getRuntime().totalMemory())
        .addKeyValue("activeConnections", connectionPool.getActiveCount())
        .setMessage("System state snapshot")
        .log();
}

Business Event Logging

// Order processing event
logger.atInfo()
    .addMarker(MarkerFactory.getMarker("BUSINESS_EVENT"))
    .setMessage("Order processed")
    .addKeyValue("orderId", order.getId())
    .addKeyValue("customerId", order.getCustomerId())
    .addKeyValue("amount", order.getTotalAmount())
    .addKeyValue("currency", order.getCurrency())
    .addKeyValue("items", order.getItems().size())
    .addKeyValue("processingTime", processingTime)
    .addKeyValue("paymentMethod", order.getPaymentMethod())
    .log();

Error Context Enrichment

// Rich error context
logger.atError()
    .addMarker(MarkerFactory.getMarker("PAYMENT_ERROR"))
    .setCause(paymentException)
    .setMessage("Payment processing failed")
    .addKeyValue("transactionId", transactionId)
    .addKeyValue("amount", paymentAmount)
    .addKeyValue("currency", currency)
    .addKeyValue("paymentProvider", provider)
    .addKeyValue("customerId", customerId)
    .addKeyValue("retryAttempt", retryCount)
    .addKeyValue("errorCode", paymentException.getErrorCode())
    .log();

Performance Monitoring

// Performance event with timing
long startTime = System.currentTimeMillis();
try {
    // perform operation
    performDatabaseOperation();
    
    logger.atInfo()
        .addMarker(MarkerFactory.getMarker("PERFORMANCE"))
        .setMessage("Database operation completed")
        .addKeyValue("operation", "select")
        .addKeyValue("table", "users")
        .addKeyValue("duration", System.currentTimeMillis() - startTime)
        .addKeyValue("recordCount", resultCount)
        .log();
} catch (Exception e) {
    logger.atError()
        .addMarker(MarkerFactory.getMarker("PERFORMANCE"))
        .setCause(e)
        .setMessage("Database operation failed")
        .addKeyValue("operation", "select")
        .addKeyValue("table", "users")
        .addKeyValue("duration", System.currentTimeMillis() - startTime)
        .log();
}

Lazy Evaluation Benefits

// Expensive operations only executed if logging level is enabled
logger.atDebug()
    .setMessage(() -> "Complex state: " + generateComplexStateDescription())
    .addKeyValue("timestamp", () -> Instant.now().toString())
    .addKeyValue("threadDump", () -> generateThreadDump())
    .addKeyValue("memoryStats", () -> getDetailedMemoryStats())
    .log();

Caller Boundary Control

For advanced framework integration, control the caller boundary for accurate location information.

/**
 * Set the caller boundary for accurate location information
 * @param fqcn Fully qualified class name of the caller boundary
 */
void setCallerBoundary(String fqcn);

Usage Example:

import org.slf4j.Logger;
import org.slf4j.spi.CallerBoundaryAware;
import org.slf4j.spi.LoggingEventBuilder;
import java.util.Map;

// Framework wrapper example
public class LoggingWrapper {
    private static final String FQCN = LoggingWrapper.class.getName();
    private final Logger logger;
    
    public void logBusinessEvent(String event, Map<String, Object> context) {
        LoggingEventBuilder builder = logger.atInfo();
        
        if (builder instanceof CallerBoundaryAware) {
            ((CallerBoundaryAware) builder).setCallerBoundary(FQCN);
        }
        
        builder.setMessage(event);
        context.forEach(builder::addKeyValue);
        builder.log();
    }
}

Integration with Observability Platforms

The structured key-value pairs integrate seamlessly with modern observability platforms:

// APM/Observability friendly logging
logger.atInfo()
    .addKeyValue("trace.id", traceId)
    .addKeyValue("span.id", spanId)
    .addKeyValue("service.name", "user-service")
    .addKeyValue("service.version", "1.2.3")
    .addKeyValue("environment", "production")
    .setMessage("Service operation completed")
    .log();

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