The logging API of the Log4j project providing a comprehensive and flexible logging framework for Java applications.
—
High-performance logging features including parameterized messages with {} placeholders, supplier-based lazy evaluation, and fluent LogBuilder API for complex log events.
Efficient logging using {} placeholders that avoid string concatenation when logging is disabled.
public interface Logger {
// Parameterized logging for all levels
void trace(String message, Object... params);
void debug(String message, Object... params);
void info(String message, Object... params);
void warn(String message, Object... params);
void error(String message, Object... params);
void fatal(String message, Object... params);
// Parameterized with throwable
void trace(String message, Throwable throwable, Object... params);
void debug(String message, Throwable throwable, Object... params);
void info(String message, Throwable throwable, Object... params);
void warn(String message, Throwable throwable, Object... params);
void error(String message, Throwable throwable, Object... params);
void fatal(String message, Throwable throwable, Object... params);
// Generic parameterized logging
void log(Level level, String message, Object... params);
void log(Level level, String message, Throwable throwable, Object... params);
}Usage Examples:
private static final Logger logger = LogManager.getLogger();
public void demonstrateParameterizedLogging() {
String username = "alice";
int userId = 12345;
long processingTime = 150;
// Efficient - no string concatenation if INFO is disabled
logger.info("User {} (ID: {}) logged in", username, userId);
// Multiple parameters
logger.debug("Processing completed for user {} in {}ms with {} items",
username, processingTime, getItemCount());
// With exception
try {
processUser(userId);
} catch (Exception e) {
logger.error("Failed to process user {} ({})", username, userId, e);
}
// Arrays and objects are automatically formatted
String[] roles = {"admin", "user"};
logger.info("User {} has roles: {}", username, roles);
// Complex objects use toString()
UserProfile profile = getUserProfile(userId);
logger.debug("Loaded profile: {}", profile);
}
// Performance comparison
public void performanceExample() {
String data = "expensive data";
// BAD - string concatenation always happens
logger.debug("Processing data: " + expensiveCalculation() + " for user " + data);
// GOOD - parameters only evaluated if DEBUG is enabled
logger.debug("Processing data: {} for user {}", expensiveCalculation(), data);
// EVEN BETTER - explicit level check for very expensive operations
if (logger.isDebugEnabled()) {
logger.debug("Very expensive debug: {}", veryExpensiveOperation());
}
}Use suppliers for expensive message generation that should only occur when logging is enabled.
public interface Logger {
// Supplier-based logging for all levels
void trace(Supplier<?> messageSupplier);
void debug(Supplier<?> messageSupplier);
void info(Supplier<?> messageSupplier);
void warn(Supplier<?> messageSupplier);
void error(Supplier<?> messageSupplier);
void fatal(Supplier<?> messageSupplier);
// Supplier with throwable
void trace(Supplier<?> messageSupplier, Throwable throwable);
void debug(Supplier<?> messageSupplier, Throwable throwable);
void info(Supplier<?> messageSupplier, Throwable throwable);
void warn(Supplier<?> messageSupplier, Throwable throwable);
void error(Supplier<?> messageSupplier, Throwable throwable);
void fatal(Supplier<?> messageSupplier, Throwable throwable);
// Generic supplier logging
void log(Level level, Supplier<?> messageSupplier);
void log(Level level, Supplier<?> messageSupplier, Throwable throwable);
}
/**
* Functional interface for lazy message evaluation
*/
public interface Supplier<T> {
T get();
}
/**
* Supplier specifically for Message objects
*/
public interface MessageSupplier extends Supplier<Message> {
Message get();
}Usage Examples:
private static final Logger logger = LogManager.getLogger();
public void demonstrateSupplierLogging() {
// Lambda supplier - only executed if DEBUG is enabled
logger.debug(() -> "Expensive calculation result: " + performExpensiveCalculation());
// Method reference supplier
logger.trace(this::generateDetailedDiagnostics);
// Complex supplier with multiple operations
logger.debug(() -> {
Map<String, Object> context = gatherContextData();
return "Context: " + formatContext(context);
});
// Supplier with exception
Exception ex = new RuntimeException("test");
logger.error(() -> "Error processing request: " + getCurrentRequest(), ex);
// MessageSupplier for custom messages
logger.info(() -> new ObjectMessage(createStatusReport()));
}
private String performExpensiveCalculation() {
// Simulate expensive operation
return "calculated value";
}
private String generateDetailedDiagnostics() {
// Complex diagnostic generation
return "detailed diagnostics";
}Fluent interface for constructing complex log events with multiple attributes.
/**
* Fluent API for constructing log events
*/
public interface LogBuilder {
/** Add a marker to the log event */
LogBuilder withMarker(Marker marker);
/** Add a throwable to the log event */
LogBuilder withThrowable(Throwable throwable);
/** Calculate and include caller location information */
LogBuilder withLocation();
/** Set explicit caller location */
LogBuilder withLocation(StackTraceElement location);
// Log methods with various parameter combinations
void log(String message);
void log(String message, Object p0);
void log(String message, Object p0, Object p1);
void log(String message, Object p0, Object p1, Object p2);
// ... overloads for up to 10 parameters
void log(String message, Object... params);
void log(Message message);
void log(Object message);
void log(Supplier<Message> messageSupplier);
/** No-operation LogBuilder for disabled levels */
LogBuilder NOOP = new NoOpLogBuilder();
}
public interface Logger {
/** Get LogBuilders for each level */
LogBuilder atTrace();
LogBuilder atDebug();
LogBuilder atInfo();
LogBuilder atWarn();
LogBuilder atError();
LogBuilder atFatal();
LogBuilder atLevel(Level level);
}Usage Examples:
private static final Logger logger = LogManager.getLogger();
private static final Marker SECURITY_MARKER = MarkerManager.getMarker("SECURITY");
public void demonstrateLogBuilder() {
// Simple fluent logging
logger.atInfo()
.log("User logged in successfully");
// Complex log event with multiple attributes
logger.atError()
.withMarker(SECURITY_MARKER)
.withThrowable(exception)
.withLocation()
.log("Security violation detected for user {}", username);
// Conditional building
LogBuilder builder = logger.atDebug();
if (includeLocation) {
builder = builder.withLocation();
}
if (marker != null) {
builder = builder.withMarker(marker);
}
builder.log("Debug message with conditional attributes");
// Method chaining with different message types
logger.atWarn()
.withMarker(performanceMarker)
.log(() -> new ObjectMessage(performanceMetrics));
// Using with try-catch
try {
processRequest();
} catch (Exception e) {
logger.atError()
.withThrowable(e)
.withMarker(SECURITY_MARKER)
.log("Request processing failed for user {}", getCurrentUser());
}
}
// Performance note: LogBuilder for disabled levels returns NOOP
public void performanceNote() {
// If TRACE is disabled, this returns LogBuilder.NOOP which ignores all operations
LogBuilder builder = logger.atTrace(); // Returns NOOP if TRACE disabled
builder.withMarker(marker) // No-op
.withLocation() // No-op
.log("Expensive trace message"); // No-op
}Methods for tracing method entry and exit points with automatic parameter capture.
public interface Logger {
/** Trace method entry */
void traceEntry();
/** Trace method entry with parameters */
void traceEntry(String format, Object... params);
/** Trace method entry with message */
void traceEntry(Message message);
/** Trace method exit */
void traceExit();
/** Trace method exit with return value */
<T> T traceExit(T result);
/** Trace method exit with message */
void traceExit(Message message);
/** Trace method exit with entry message and return value */
<T> T traceExit(Message message, T result);
/** Log and return caught exception */
<T extends Throwable> T catching(T throwable);
/** Log and throw exception */
<T extends Throwable> T throwing(T throwable);
}Usage Examples:
private static final Logger logger = LogManager.getLogger();
public String processUser(String userId, String action) {
// Trace entry with parameters
logger.traceEntry("userId={}, action={}", userId, action);
try {
// Method implementation
String result = performAction(userId, action);
// Trace exit with return value
return logger.traceExit(result);
} catch (Exception e) {
// Log and re-throw exception
throw logger.throwing(e);
}
}
public void handleException() {
try {
riskyOperation();
} catch (Exception e) {
// Log caught exception and continue
logger.catching(e);
// Handle exception...
}
}
// Automatic method tracing pattern
public User findUser(Long id) {
logger.traceEntry("id={}", id);
try {
User user = userRepository.findById(id);
if (user == null) {
throw new UserNotFoundException("User not found: " + id);
}
return logger.traceExit(user);
} catch (Exception e) {
throw logger.throwing(e);
}
}Efficient level checking to avoid expensive operations when logging is disabled.
public interface Logger {
// Level checking methods
boolean isTraceEnabled();
boolean isDebugEnabled();
boolean isInfoEnabled();
boolean isWarnEnabled();
boolean isErrorEnabled();
boolean isFatalEnabled();
boolean isEnabled(Level level);
// Level checking with markers
boolean isTraceEnabled(Marker marker);
boolean isDebugEnabled(Marker marker);
boolean isInfoEnabled(Marker marker);
boolean isWarnEnabled(Marker marker);
boolean isErrorEnabled(Marker marker);
boolean isFatalEnabled(Marker marker);
boolean isEnabled(Level level, Marker marker);
}Usage Examples:
private static final Logger logger = LogManager.getLogger();
public void efficientLogging() {
// Guard expensive operations
if (logger.isDebugEnabled()) {
String expensiveData = generateExpensiveDebugData();
logger.debug("Debug data: {}", expensiveData);
}
// Multiple expensive parameters
if (logger.isTraceEnabled()) {
logger.trace("Trace: {} {} {}",
expensiveOp1(), expensiveOp2(), expensiveOp3());
}
// Level checking with markers
Marker performanceMarker = MarkerManager.getMarker("PERFORMANCE");
if (logger.isInfoEnabled(performanceMarker)) {
logger.info(performanceMarker, "Performance metrics: {}",
collectPerformanceMetrics());
}
// Dynamic level checking
Level dynamicLevel = getDynamicLevel();
if (logger.isEnabled(dynamicLevel)) {
logger.log(dynamicLevel, "Dynamic message: {}", getDynamicData());
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-apache-logging-log4j--log4j-api