CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-slf4j--slf4j-api

Simple Logging Facade for Java (SLF4J) API - a facade/abstraction layer for various logging frameworks.

Overview
Eval results
Files

fluent-logging.mddocs/

Fluent Logging API

SLF4J 2.0 introduces a modern fluent API that provides a chainable interface for building complex log statements. This API supports structured logging with key-value pairs, lazy evaluation, and builder pattern for enhanced logging capabilities.

Capabilities

Fluent Entry Points

Logger methods that return LoggingEventBuilder instances for chainable operations.

/**
 * Entry point for fluent-logging for TRACE level
 * @return LoggingEventBuilder instance as appropriate for level TRACE
 */
LoggingEventBuilder atTrace();

/**
 * Entry point for fluent-logging for DEBUG level
 * @return LoggingEventBuilder instance as appropriate for level DEBUG
 */
LoggingEventBuilder atDebug();

/**
 * Entry point for fluent-logging for INFO level
 * @return LoggingEventBuilder instance as appropriate for level INFO
 */
LoggingEventBuilder atInfo();

/**
 * Entry point for fluent-logging for WARN level
 * @return LoggingEventBuilder instance as appropriate for level WARN
 */
LoggingEventBuilder atWarn();

/**
 * Entry point for fluent-logging for ERROR level
 * @return LoggingEventBuilder instance as appropriate for level ERROR
 */
LoggingEventBuilder atError();

/**
 * Entry point for fluent-logging for any level
 * @param level desired level for the event builder
 * @return LoggingEventBuilder instance as appropriate for the specified level
 */
LoggingEventBuilder atLevel(Level level);

/**
 * Check if logger is enabled for the specified level
 * @param level the level to check
 * @return true if enabled, false otherwise
 */
boolean isEnabledForLevel(Level level);

LoggingEventBuilder Interface

Main interface for building structured log events with method chaining.

/**
 * Main interface for creating logging events with fluent API
 */
public interface LoggingEventBuilder {
    /**
     * Set the cause for the logging event being built
     * @param cause a throwable
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder setCause(Throwable cause);
    
    /**
     * Add a Marker to the event being built
     * @param marker a Marker instance to add
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder addMarker(Marker marker);
    
    /**
     * Add an argument to the event being built
     * @param p an Object to add
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder addArgument(Object p);
    
    /**
     * Add an argument supplier to the event being built
     * @param objectSupplier an Object supplier to add
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder addArgument(Supplier<?> objectSupplier);
    
    /**
     * Add a key value pair to the event being built
     * @param key the key of the key value pair
     * @param value the value of the key value pair
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder addKeyValue(String key, Object value);
    
    /**
     * Add a key value pair to the event being built
     * @param key the key of the key value pair
     * @param valueSupplier a supplier of a value for the key value pair
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder addKeyValue(String key, Supplier<Object> valueSupplier);
    
    /**
     * Sets the message of the logging event
     * @param message the message string
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder setMessage(String message);
    
    /**
     * Sets the message of the event via a message supplier
     * @param messageSupplier supplies a String to be used as the message
     * @return a LoggingEventBuilder, usually this
     */
    LoggingEventBuilder setMessage(Supplier<String> messageSupplier);
    
    /**
     * After the logging event is built, performs actual logging
     */
    void log();
    
    /**
     * Equivalent to calling setMessage(String) followed by log()
     * @param message the message to log
     */
    void log(String message);
    
    /**
     * Equivalent to calling setMessage(String) followed by addArgument(Object) and then log()
     * @param message the message to log
     * @param arg an argument to be used with the message to log
     */
    void log(String message, Object arg);
    
    /**
     * Equivalent to calling setMessage(String) followed by two calls to addArgument(Object) and then log()
     * @param message the message to log
     * @param arg0 first argument to be used with the message to log
     * @param arg1 second argument to be used with the message to log
     */
    void log(String message, Object arg0, Object arg1);
    
    /**
     * Equivalent to calling setMessage(String) followed by zero or more calls to addArgument(Object) and then log()
     * @param message the message to log
     * @param args a list (actually an array) of arguments to be used with the message to log
     */
    void log(String message, Object... args);
    
    /**
     * Equivalent to calling setMessage(Supplier) followed by log()
     * @param messageSupplier a Supplier returning a message of type String
     */
    void log(Supplier<String> messageSupplier);
}

Level Enumeration

Enumeration representing logging levels.

/**
 * SLF4J's internal representation of Level
 */
public enum Level {
    ERROR, WARN, INFO, DEBUG, TRACE;
    
    /**
     * Get integer representation of the level
     * @return the integer value
     */
    int toInt();
    
    /**
     * Convert integer to Level
     * @param levelInt the integer representation
     * @return the corresponding Level
     */
    static Level intToLevel(int levelInt);
}

Usage Examples:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import java.util.function.Supplier;

public class FluentLoggingExample {
    private static final Logger logger = LoggerFactory.getLogger(FluentLoggingExample.class);
    
    public void basicFluentLogging() {
        // Simple fluent logging
        logger.atInfo().log("Application started");
        
        // With arguments
        logger.atDebug()
            .addArgument("user123")
            .addArgument(42)
            .log("User {} has {} active sessions");
            
        // With key-value pairs for structured logging
        logger.atInfo()
            .addKeyValue("userId", "user123")
            .addKeyValue("action", "login")
            .addKeyValue("timestamp", System.currentTimeMillis())
            .log("User login event");
    }
    
    public void advancedFluentLogging() {
        // Complex event building
        try {
            processOrder();
        } catch (Exception e) {
            logger.atError()
                .addKeyValue("orderId", "ORD-12345")
                .addKeyValue("customerId", "CUST-67890")
                .addKeyValue("errorType", e.getClass().getSimpleName())
                .setCause(e)
                .log("Failed to process order");
        }
        
        // Conditional logging with level checking
        if (logger.isEnabledForLevel(Level.TRACE)) {
            logger.atTrace()
                .setMessage(() -> buildExpensiveDebugMessage())
                .log();
        }
        
        // Using suppliers for lazy evaluation
        logger.atDebug()
            .addArgument(() -> getCurrentUser().getName())
            .addKeyValue("memoryUsage", () -> getMemoryUsage())
            .log("Processing request for user {}");
    }
    
    public void markerBasedFluentLogging() {
        Marker securityMarker = MarkerFactory.getMarker("SECURITY");
        Marker auditMarker = MarkerFactory.getMarker("AUDIT");
        
        // Multiple markers with fluent API
        logger.atWarn()
            .addMarker(securityMarker)
            .addMarker(auditMarker)
            .addKeyValue("userId", "user123")
            .addKeyValue("attemptedAction", "admin_access")
            .log("Unauthorized access attempt");
    }
    
    private String buildExpensiveDebugMessage() {
        // Expensive operation only executed if TRACE is enabled
        return "Complex debug info: " + performExpensiveCalculation();
    }
    
    private long getMemoryUsage() {
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }
}

Structured Logging with Key-Value Pairs

The fluent API enables structured logging through key-value pairs:

// Traditional logging - unstructured
logger.info("User john.doe logged in from IP 192.168.1.100 at 2023-12-01T10:30:00Z");

// Fluent API - structured logging
logger.atInfo()
    .addKeyValue("event", "user_login")
    .addKeyValue("username", "john.doe")
    .addKeyValue("sourceIp", "192.168.1.100")
    .addKeyValue("timestamp", "2023-12-01T10:30:00Z")
    .log("User login event");

Lazy Evaluation

The fluent API supports lazy evaluation using Supplier interfaces:

// Expensive operation only executed if logging level is enabled
logger.atTrace()
    .addArgument(() -> performExpensiveDatabaseQuery())
    .addKeyValue("metrics", () -> calculateComplexMetrics())
    .setMessage(() -> generateDetailedReport())
    .log();

// Conditional logging is handled automatically
logger.atDebug()
    .addArgument(() -> {
        // This lambda is only executed if DEBUG level is enabled
        return performExpensiveFormatting(data);
    })
    .log("Processed data: {}");

Performance Benefits

The fluent API provides several performance advantages:

  1. Level Checking: If the logging level is disabled, a no-operation LoggingEventBuilder is returned, avoiding any parameter evaluation
  2. Lazy Evaluation: Suppliers are only invoked if logging will actually occur
  3. Efficient Builder: The builder pattern minimizes object creation compared to traditional string concatenation
  4. Structured Data: Key-value pairs enable efficient processing by logging backends without string parsing

Migration from Traditional API

The fluent API can be gradually adopted alongside traditional logging:

// Traditional approach
if (logger.isDebugEnabled()) {
    logger.debug("Processing order {} for customer {} with total {}", 
        order.getId(), customer.getName(), order.getTotal());
}

// Fluent approach - level checking is automatic
logger.atDebug()
    .addArgument(order.getId())
    .addArgument(customer.getName())
    .addArgument(order.getTotal())
    .log("Processing order {} for customer {} with total {}");

// Or more structured
logger.atDebug()
    .addKeyValue("orderId", order.getId())
    .addKeyValue("customerId", customer.getId())
    .addKeyValue("customerName", customer.getName())
    .addKeyValue("orderTotal", order.getTotal())
    .log("Processing order");

Types

Key-Value Pair Support

/**
 * Key-value pair for structured logging
 */
public class KeyValuePair {
    public final String key;
    public final Object value;
    
    /**
     * Create a key-value pair
     * @param key the key
     * @param value the value
     */
    public KeyValuePair(String key, Object value);
}

Event Constants

/**
 * Integer constants for log levels
 */
public class EventConstants {
    public static final int ERROR_INT = 40;
    public static final int WARN_INT = 30;
    public static final int INFO_INT = 20;
    public static final int DEBUG_INT = 10;
    public static final int TRACE_INT = 0;
}

Install with Tessl CLI

npx tessl i tessl/maven-org-slf4j--slf4j-api

docs

basic-logging.md

fluent-logging.md

index.md

markers.md

mdc.md

service-providers.md

tile.json