Sunday, 8 October 2023

Program to create append only log file in Java

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

Interview Questions

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