Logging serves as a critical mechanism for capturing runtime information including exceptiosn, authentication outcomes, and significant operational events. These records facilitate application state analysis and user behavior understanding, enabling continuous system improvement.
Approaches to Logging
Basic Console Output
System.out.println("Operation completed");
e.printStackTrace();
Limitations: Volatile storage, no persistent retention
File-Based Logging with IO Streams
FileOutputStream fos = new FileOutputStream("app.log");
PrintStream ps = new PrintStream(fos);
ps.println("Error occurred: " + exception.getMessage());
Drawbacks: Complex implementation, potential thread blocking, lack of log levels, limited formatting options
Logging Frameworks (Log4j) Advantages: Persistent storage, configurable severity levels, customizable formats, simplified implementation
Log4j Severity Levels
- FATAL: Critical errors causing application termination
- ERROR: Recoverable errors allowing continued operation
- WARN: Potential environmental issues requiring attention
- INFO: General application progress information
- DEBUG: Detailed debugging information for development
Log4j Configuration
Required Components
- Add log4j-1.2.8.jar to classpath
- Create log4j.properties in source directory
Configuration Example
log4j.rootLogger=error,logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/application.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n
Core Components
- Appenders: Output destinations (ConsoleAppender, FileAppender)
- Layouts: Formatting controllers (SimpleLayout, PatternLayout)
Implementation Example
import org.apache.log4j.Logger;
public class DatabaseHelper {
private static final Logger log = Logger.getLogger(DatabaseHelper.class);
public void loadConfiguration() {
log.info("Configuration loaded successfully: " + properties);
}
public void handleError(Exception ex) {
log.error("Database operation failed", ex);
}
public void debugOperation() {
log.debug("Resource cleanup completed");
}
}
Pattern Layout Formatting
- %p: Priority level (DEBUG, INFO, WARN, ERROR, FATAL)
- %d: Timestamp with customizable format
- %t: Executing thread name
- %l: Location information (class.method(file:line))
- %c: Logger category (typically class name)
- %M: Method name where log was generated
- %F: Source file name
- %L: Line number in source code
- %m: Actual log message content
- %n: Platform-specific line separator
Connection Pool Integration Example
package com.example.dao;
import org.apache.log4j.Logger;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.LinkedList;
public class ConnectionManager {
private static final Logger log = Logger.getLogger(ConnectionManager.class);
private static LinkedList<Connection> connections;
private static String dbUrl, username, password;
private static int initialConnections, maximumConnections;
static {
initializeConfiguration();
loadDatabaseDriver();
initializeConnectionPool();
}
private static void initializeConfiguration() {
ConfigurationReader config = new ConfigurationReader("/database.properties");
dbUrl = config.getValue("url");
username = config.getValue("user");
password = config.getValue("password");
initialConnections = Integer.parseInt(config.getValue("initialSize"));
maximumConnections = Integer.parseInt(config.getValue("maxSize"));
}
private static void loadDatabaseDriver() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException ex) {
log.fatal("Database driver not found", ex);
}
}
private static void initializeConnectionPool() {
connections = new LinkedList<>();
for (int i = 0; i < initialConnections; i++) {
Connection conn = createConnection();
if (conn != null) {
connections.add(conn);
log.info("Initialized connection " + conn.hashCode() + " added to pool");
}
}
}
private static Connection createConnection() {
try {
return DriverManager.getConnection(dbUrl, username, password);
} catch (Exception ex) {
log.fatal("Connection creation failed", ex);
return null;
}
}
public static Connection obtainConnection() {
Connection conn = null;
if (!connections.isEmpty()) {
conn = connections.removeFirst();
log.info("Retrieved connection from pool: " + conn.hashCode());
} else {
conn = createConnection();
log.info("Pool empty, created new connection: " + conn.hashCode());
}
return conn;
}
public static void releaseConnection(Connection conn) {
if (conn == null) {
log.warn("Null connection cannot be released");
return;
}
try {
if (conn.isClosed()) {
log.info("Connection " + conn.hashCode() + " already closed");
return;
}
if (connections.size() < maximumConnections) {
conn.setAutoCommit(true);
log.debug("Reset auto-commit for connection " + conn.hashCode());
connections.addLast(conn);
log.info("Connection " + conn.hashCode() + " returned to pool");
} else {
conn.close();
log.info("Pool full, connection " + conn.hashCode() + " closed");
}
} catch (Exception ex) {
log.error("Error releasing connection", ex);
}
}
}