Write a program to create an append-only log file that can be used to log messages. The log file should be able to grow to a certain threshold size before it is backed up and a new log file is created.
Make sure that your application handles below requirements.
a. The log file should be thread-safe.
b. The log file should be configurable, so that you can specify the threshold size, backup directory, and other parameters.
c. The log file should be efficient, so that it does not impact the performance of the system.
Find the below working application.
ThreadSafeLogFile.java
package com.sample.app;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class ThreadSafeLogFile {
private final Object LOCK = new Object();
private static final String DEFAULT_LOG_FILE = "myLogFile.log";
private static long DEFAULT_FILE_SIZE_IN_BYTES = 10 * 1024 * 1024; // Default threshold size (10MB)
private static String DEFAULT_BACKUP_DIRECTORY = "backup_logs"; // Default backup directory
private String logFileName;
private long maxLogFileSizeBytes;
private String backupDirectory;
private void backupLogFile() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date now = new Date();
String timestamp = dateFormat.format(now);
String logFileNameAlone = new File(logFileName).getName();
String backupFileName = backupDirectory + File.separator + logFileNameAlone.split("\\.")[0] + "_" + timestamp
+ ".log";
try {
Files.copy(new File(logFileName).toPath(), new File(backupFileName).toPath());
Files.delete(new File(logFileName).toPath());
} catch (IOException e) {
e.printStackTrace();
}
}
public ThreadSafeLogFile() {
this(DEFAULT_LOG_FILE);
}
public ThreadSafeLogFile(String logFileName) {
this(logFileName, DEFAULT_FILE_SIZE_IN_BYTES);
}
public ThreadSafeLogFile(String logFileName, long maxLogFileSizeBytes) {
this(logFileName, maxLogFileSizeBytes, DEFAULT_BACKUP_DIRECTORY);
}
public ThreadSafeLogFile(String logFileName, long maxLogFileSizeBytes, String backupDirectory) {
if (logFileName == null || logFileName.isEmpty()) {
throw new IllegalArgumentException("logFileName is null or empty");
}
if (!logFileName.endsWith(".log")) {
logFileName = logFileName + ".log";
}
this.logFileName = logFileName;
if (maxLogFileSizeBytes < 1024) {
throw new IllegalArgumentException("maxLogFileSizeBytes is < 1024");
}
this.maxLogFileSizeBytes = maxLogFileSizeBytes;
if (backupDirectory == null || backupDirectory.isEmpty()) {
throw new IllegalArgumentException("backupDirectory is null or empty");
}
this.backupDirectory = backupDirectory;
// Create the directory and any necessary parent directories
File backupDir = new File(backupDirectory);
if (!backupDir.exists()) {
backupDir.mkdirs();
}
}
public void appendLogMessage(String message) throws IOException {
appendLogMessages(Arrays.asList(message));
}
public void appendLogMessages(List<String> logEntries) throws IOException {
if (logEntries == null || logEntries.isEmpty()) {
return;
}
synchronized (LOCK) {
File logFile = new File(logFileName);
if (logFile.length() >= maxLogFileSizeBytes) {
backupLogFile();
}
try (FileWriter fileWriter = new FileWriter(logFileName, true);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
for (String logEntry : logEntries) {
if (logEntry == null) {
continue;
}
bufferedWriter.write(logEntry);
bufferedWriter.newLine();
}
}
}
}
}
App.java
package com.sample.app;
import java.io.IOException;
public class App {
public static void main(String[] args) throws IOException {
// Create a log file with threshold size 10KB
ThreadSafeLogFile logFile = new ThreadSafeLogFile("/Users/Shared/chat-server.log", 10 * 1024, "/Users/Shared/backup");
for(int i=0; i < 1000; i++) {
logFile.appendLogMessage("This is message number " + i);
}
}
}
You may like
Extend the thread to check it’s running status
Implement retry handler for a task in Java
Design an utility class to capture application metrics summary in Java
Utility class to get primitive type from wrapper type and vice versa
FNV hash algorithm implementation in Java
Controlling Randomness in Java: Exploring the Role of Seeds in java.util.Random
No comments:
Post a Comment