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

markers.mddocs/

Markers

Markers are named objects used to enrich log statements with categorical information. They enable logging frameworks to filter, route, or specially handle log messages based on marker content. Markers can contain references to other markers and are fully supported in both traditional and fluent logging APIs.

Capabilities

Marker Factory

Static factory for creating and retrieving Marker instances.

/**
 * MarkerFactory is a utility class producing Marker instances
 */
public class MarkerFactory {
    /**
     * Return a Marker instance as specified by the name parameter
     * @param name The name of the Marker object to return
     * @return marker instance
     */
    public static Marker getMarker(String name);
    
    /**
     * Create a marker which is detached (even at birth) from the MarkerFactory
     * @param name the name of the marker
     * @return a dangling marker
     */
    public static Marker getDetachedMarker(String name);
    
    /**
     * Return the IMarkerFactory instance in use
     * @return the IMarkerFactory instance in use
     */
    public static IMarkerFactory getIMarkerFactory();
}

Marker Interface

Core marker interface for creating named categorical objects.

/**
 * Markers are named objects used to enrich log statements
 */
public interface Marker extends Serializable {
    /**
     * This constant represents any marker, including a null marker
     */
    String ANY_MARKER = "*";
    
    /**
     * This constant represents any non-null marker
     */
    String ANY_NON_NULL_MARKER = "+";
    
    /**
     * Get the name of this Marker
     * @return name of marker
     */
    String getName();
    
    /**
     * Add a reference to another Marker
     * @param reference a reference to another marker
     * @throws IllegalArgumentException if 'reference' is null
     */
    void add(Marker reference);
    
    /**
     * Remove a marker reference
     * @param reference the marker reference to remove
     * @return true if reference could be found and removed, false otherwise
     */
    boolean remove(Marker reference);
    
    /**
     * Does this marker have any references?
     * @return true if this marker has one or more references, false otherwise
     */
    boolean hasReferences();
    
    /**
     * Returns an Iterator which can be used to iterate over the references of this marker
     * @return Iterator over the references of this marker
     */
    Iterator<Marker> iterator();
    
    /**
     * Does this marker contain a reference to the 'other' marker?
     * @param other The marker to test for inclusion
     * @return Whether this marker contains the other marker
     * @throws IllegalArgumentException if 'other' is null
     */
    boolean contains(Marker other);
    
    /**
     * Does this marker contain the marker named 'name'?
     * @param name The marker name to test for inclusion
     * @return Whether this marker contains the other marker
     */
    boolean contains(String name);
    
    /**
     * Markers are considered equal if they have the same name
     * @param o object to compare
     * @return true, if this.name equals o.name
     */
    boolean equals(Object o);
    
    /**
     * Compute the hash code based on the name of this marker
     * @return the computed hashCode
     */
    int hashCode();
}

Marker Factory Interface

Factory interface for creating and managing Marker instances.

/**
 * Factory interface for Marker instances
 */
public interface IMarkerFactory {
    /**
     * Manufacture a Marker instance by name. If the instance has been created earlier, return the previously created instance
     * @param name the name of the marker to be created, null value is not allowed
     * @return a Marker instance
     */
    Marker getMarker(String name);
    
    /**
     * Checks if the marker with the name already exists
     * @param name marker name
     * @return true if the marker exists, false otherwise
     */
    boolean exists(String name);
    
    /**
     * Detach an existing marker
     * @param name The name of the marker to detach
     * @return whether the marker could be detached or not
     */
    boolean detachMarker(String name);
    
    /**
     * Create a marker which is detached from this IMarkerFactory
     * @param name marker name
     * @return a marker detached from this factory
     */
    Marker getDetachedMarker(String name);
}

Usage Examples:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class MarkerExample {
    private static final Logger logger = LoggerFactory.getLogger(MarkerExample.class);
    
    // Create markers for different categories
    private static final Marker SECURITY_MARKER = MarkerFactory.getMarker("SECURITY");
    private static final Marker AUDIT_MARKER = MarkerFactory.getMarker("AUDIT");
    private static final Marker PERFORMANCE_MARKER = MarkerFactory.getMarker("PERFORMANCE");
    
    public void basicMarkerUsage() {
        // Simple marker usage
        logger.info(SECURITY_MARKER, "User authentication successful");
        logger.warn(AUDIT_MARKER, "Configuration changed by admin user");
        logger.debug(PERFORMANCE_MARKER, "Query execution time: {} ms", 150);
    }
    
    public void markerHierarchy() {
        // Create nested markers
        Marker securityMarker = MarkerFactory.getMarker("SECURITY");
        Marker authMarker = MarkerFactory.getMarker("AUTH");
        Marker loginMarker = MarkerFactory.getMarker("LOGIN");
        
        // Build marker hierarchy: SECURITY -> AUTH -> LOGIN
        authMarker.add(securityMarker);
        loginMarker.add(authMarker);
        
        // This log statement will match filters for LOGIN, AUTH, or SECURITY
        logger.info(loginMarker, "User login attempt from IP: {}", "192.168.1.100");
        
        // Check marker relationships
        if (loginMarker.contains(securityMarker)) {
            logger.debug("Login marker contains security marker");
        }
    }
    
    public void conditionalLogging() {
        // Check if marker-specific logging is enabled
        if (logger.isInfoEnabled(AUDIT_MARKER)) {
            // Perform expensive audit data collection only if needed
            String auditData = collectAuditInformation();
            logger.info(AUDIT_MARKER, "Audit event: {}", auditData);
        }
    }
}

Traditional API with Markers

All traditional logging methods have marker-aware equivalents:

// Marker-aware logging methods for each level
public interface Logger {
    // TRACE level with markers
    boolean isTraceEnabled(Marker marker);
    void trace(Marker marker, String msg);
    void trace(Marker marker, String format, Object arg);
    void trace(Marker marker, String format, Object arg1, Object arg2);
    void trace(Marker marker, String format, Object... arguments);
    void trace(Marker marker, String msg, Throwable t);
    
    // DEBUG level with markers
    boolean isDebugEnabled(Marker marker);
    void debug(Marker marker, String msg);
    void debug(Marker marker, String format, Object arg);
    void debug(Marker marker, String format, Object arg1, Object arg2);
    void debug(Marker marker, String format, Object... arguments);
    void debug(Marker marker, String msg, Throwable t);
    
    // INFO level with markers
    boolean isInfoEnabled(Marker marker);
    void info(Marker marker, String msg);
    void info(Marker marker, String format, Object arg);
    void info(Marker marker, String format, Object arg1, Object arg2);
    void info(Marker marker, String format, Object... arguments);
    void info(Marker marker, String msg, Throwable t);
    
    // WARN level with markers
    boolean isWarnEnabled(Marker marker);
    void warn(Marker marker, String msg);
    void warn(Marker marker, String format, Object arg);
    void warn(Marker marker, String format, Object arg1, Object arg2);
    void warn(Marker marker, String format, Object... arguments);
    void warn(Marker marker, String msg, Throwable t);
    
    // ERROR level with markers
    boolean isErrorEnabled(Marker marker);
    void error(Marker marker, String msg);
    void error(Marker marker, String format, Object arg);
    void error(Marker marker, String format, Object arg1, Object arg2);
    void error(Marker marker, String format, Object... arguments);
    void error(Marker marker, String msg, Throwable t);
}

Fluent API with Markers

The fluent API supports multiple markers on a single log statement:

// Multiple markers with fluent API
logger.atWarn()
    .addMarker(SECURITY_MARKER)
    .addMarker(AUDIT_MARKER)
    .addKeyValue("userId", "user123")
    .addKeyValue("action", "sensitive_operation")
    .log("Security violation detected");

// Conditional marker addition
LoggingEventBuilder builder = logger.atInfo();
if (isSecurityEvent) {
    builder.addMarker(SECURITY_MARKER);
}
if (isAuditRequired) {
    builder.addMarker(AUDIT_MARKER);
}
builder.log("Event processed successfully");

Common Marker Patterns

Categorization Markers

// Functional category markers
private static final Marker DATABASE = MarkerFactory.getMarker("DATABASE");
private static final Marker HTTP = MarkerFactory.getMarker("HTTP");
private static final Marker CACHE = MarkerFactory.getMarker("CACHE");

// Operational category markers
private static final Marker STARTUP = MarkerFactory.getMarker("STARTUP");
private static final Marker SHUTDOWN = MarkerFactory.getMarker("SHUTDOWN");
private static final Marker HEALTH_CHECK = MarkerFactory.getMarker("HEALTH_CHECK");

public void databaseOperation() {
    logger.debug(DATABASE, "Executing query: {}", sql);
    logger.info(DATABASE, "Query completed in {} ms", duration);
}

public void httpRequest() {
    logger.info(HTTP, "Incoming request: {} {}", method, path);
    logger.debug(HTTP, "Request headers: {}", headers);
}

Hierarchical Markers

// Create marker hierarchy for better filtering
Marker applicationMarker = MarkerFactory.getMarker("APP");
Marker businessMarker = MarkerFactory.getMarker("BUSINESS");
Marker orderMarker = MarkerFactory.getMarker("ORDER");
Marker paymentMarker = MarkerFactory.getMarker("PAYMENT");

// Build hierarchy: APP -> BUSINESS -> ORDER/PAYMENT
businessMarker.add(applicationMarker);
orderMarker.add(businessMarker);
paymentMarker.add(businessMarker);

// Usage allows filtering at any level
logger.info(orderMarker, "Order {} created", orderId);
logger.warn(paymentMarker, "Payment {} failed", paymentId, exception);

// Filters can match:
// - Specific: only ORDER events
// - Category: all BUSINESS events (includes ORDER and PAYMENT)  
// - Application: all APP events (includes everything)

Security and Audit Markers

// Security-related markers
private static final Marker SECURITY = MarkerFactory.getMarker("SECURITY");
private static final Marker AUTHENTICATION = MarkerFactory.getMarker("AUTH");
private static final Marker AUTHORIZATION = MarkerFactory.getMarker("AUTHZ");
private static final Marker SENSITIVE_DATA = MarkerFactory.getMarker("SENSITIVE");

// Create relationships
AUTHENTICATION.add(SECURITY);
AUTHORIZATION.add(SECURITY);

public void authenticateUser(String username, String password) {
    logger.info(AUTHENTICATION, "Authentication attempt for user: {}", username);
    
    try {
        User user = authService.authenticate(username, password);
        logger.info(AUTHENTICATION, "Authentication successful for user: {}", username);
    } catch (AuthenticationException e) {
        logger.warn(AUTHENTICATION, "Authentication failed for user: {}", username, e);
    }
}

public void accessSensitiveData(String userId, String resource) {
    if (!authService.hasPermission(userId, resource)) {
        logger.warn(AUTHORIZATION, "Access denied: user {} attempted to access {}", userId, resource);
        return;
    }
    
    logger.info(SENSITIVE_DATA, "Sensitive data accessed: user={}, resource={}", userId, resource);
}

Performance Monitoring Markers

private static final Marker PERFORMANCE = MarkerFactory.getMarker("PERFORMANCE");
private static final Marker SLOW_QUERY = MarkerFactory.getMarker("SLOW_QUERY");
private static final Marker MEMORY_WARNING = MarkerFactory.getMarker("MEMORY_WARNING");

SLOW_QUERY.add(PERFORMANCE);
MEMORY_WARNING.add(PERFORMANCE);

public void monitorQueryPerformance(String query, long executionTime) {
    if (executionTime > SLOW_QUERY_THRESHOLD) {
        logger.warn(SLOW_QUERY, "Slow query detected: {} ms - {}", executionTime, query);
    } else {
        logger.debug(PERFORMANCE, "Query executed in {} ms", executionTime);
    }
}

public void checkMemoryUsage() {
    long freeMemory = Runtime.getRuntime().freeMemory();
    long totalMemory = Runtime.getRuntime().totalMemory();
    double usagePercent = (double) (totalMemory - freeMemory) / totalMemory * 100;
    
    if (usagePercent > 90) {
        logger.warn(MEMORY_WARNING, "High memory usage: {:.1f}%", usagePercent);
    } else {
        logger.debug(PERFORMANCE, "Memory usage: {:.1f}%", usagePercent);
    }
}

Marker Management

Singleton Pattern

Markers are typically managed as singletons within the MarkerFactory:

// Multiple calls return the same instance
Marker marker1 = MarkerFactory.getMarker("TEST");
Marker marker2 = MarkerFactory.getMarker("TEST");
assert marker1 == marker2; // Same instance

// Detached markers are independent
Marker detached1 = MarkerFactory.getDetachedMarker("TEST");  
Marker detached2 = MarkerFactory.getDetachedMarker("TEST");
assert detached1 != detached2; // Different instances

Best Practices

  1. Static Final Constants: Define markers as static final constants for reuse
  2. Descriptive Names: Use clear, descriptive names that indicate purpose
  3. Hierarchical Organization: Build marker hierarchies for flexible filtering
  4. Documentation: Document marker semantics and intended use
  5. Consistent Naming: Use consistent naming conventions across the application
public class ApplicationMarkers {
    // Base application marker
    public static final Marker APP = MarkerFactory.getMarker("APP");
    
    // Functional area markers
    public static final Marker SECURITY = MarkerFactory.getMarker("SECURITY");
    public static final Marker BUSINESS = MarkerFactory.getMarker("BUSINESS");
    public static final Marker INTEGRATION = MarkerFactory.getMarker("INTEGRATION");
    
    // Specific operation markers
    public static final Marker USER_MANAGEMENT = MarkerFactory.getMarker("USER_MGMT");
    public static final Marker ORDER_PROCESSING = MarkerFactory.getMarker("ORDER_PROC");
    public static final Marker EXTERNAL_API = MarkerFactory.getMarker("EXT_API");
    
    static {
        // Build hierarchy
        SECURITY.add(APP);
        BUSINESS.add(APP);
        INTEGRATION.add(APP);
        
        USER_MANAGEMENT.add(SECURITY);
        ORDER_PROCESSING.add(BUSINESS);
        EXTERNAL_API.add(INTEGRATION);
    }
}

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