Simple Logging Facade for Java (SLF4J) API - a facade/abstraction layer for various logging frameworks.
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.
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();
}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();
}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);
}
}
}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);
}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");// 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);
}// 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-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);
}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);
}
}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 instancespublic 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