6 min read

Building a Custom Spring Boot Error Logging Service

Learn how to create a custom error logging service in Spring Boot that logs errors and sends notifications via email.

JavaSpring BootError Handling

Java error messages can be difficult to extract and manage effectively, especially in production. In this post, I’ll show you how I built a custom error logging service in Spring Boot that simplifies error tracking and sends email alerts using Mailgun.

Why a Custom Logging Service?

When an error occurs in production, it’s crucial to capture the relevant error message and notify the right people immediately. Standard Java stack traces can be overwhelming, making it difficult to pinpoint the root cause quickly. My custom error logging service solves this by extracting relevant information and notifying administrators instantly.

Implementation

Here’s how I implemented the Spring Boot error logging service, broken down into steps. It captures exceptions, logs them to a file, and sends an email notification. Let’s walk through the key parts of the code.

Step 1: Service Setup and Dependencies

First, we define the service with dependencies for email sending and a configurable log directory.

java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;

@Service
public class ErrorLoggingService {

    private final EmailService emailService;
    private final String logDir;
    private static final String ADMIN_EMAIL = "admin@example.com";

    public ErrorLoggingService(EmailService emailService, @Value("${logging.dir:./log}") String logDir) {
        this.emailService = emailService;
        this.logDir = logDir;
        ensureLogDirectoryExists();
    }
}

Step 2: Logging Errors to a File

This step handles logging the error details, including a timestamp and stack trace, to a file in the specified directory.

java
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public void logAndNotify(String sourceFile, String errorMessage, Exception e) {
    String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
    String logFileName = logDir + File.separator + sourceFile + "_" + timestamp + ".txt";
    try (FileWriter writer = new FileWriter(logFileName, true)) {
        String logEntry = String.format("[%s] ERROR: %s\nStacktrace: %s\n\n",
                LocalDateTime.now(), errorMessage, getStackTrace(e));
        writer.write(logEntry);
    } catch (IOException ioException) {
        System.err.println("Failed to write to log file: " + ioException.getMessage());
    }
}

Step 3: Sending Email Notifications

Here, we trigger an email notification to the admin. The email implementation with Mailgun is covered in a separate blog post (linked below).

java
public void logAndNotify(String sourceFile, String errorMessage, Exception e) {
    // ... (logging code from Step 2)

    String emailSubject = "Error Occurred in " + sourceFile;
    String emailBody = "An error occurred please check it out fast";
    try {
        emailService.sendErrorNotification(ADMIN_EMAIL, emailSubject, emailBody);
    } catch (RuntimeException emailEx) {
        System.err.println("Failed to send error notification email: " + emailEx.getMessage());
    }
}

Note: For details on integrating Mailgun with Spring Boot for email notifications, check out my other blog post: ‘Sending Emails with Mailgun in Spring Boot’ (coming soon).

Step 4: Extracting the Stack Trace

This helper method formats the exception’s stack trace into a readable string for logging.

java
private String getStackTrace(Exception e) {
    StringBuilder sb = new StringBuilder();
    sb.append("Error: ").append(e.getClass().getName()).append(" - " ).append(e.getMessage()).append("\n");
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append("at " ).append(element.getClassName()).append(".")
          .append(element.getMethodName()).append(" (")
          .append(element.getFileName()).append(":")
          .append(element.getLineNumber()).append(")\n");
    }
    return sb.toString();
}

Step 5: Ensuring the Log Directory Exists

This utility method creates the log directory if it doesn’t already exist.

java
private void ensureLogDirectoryExists() {
    File dir = new File(logDir);
    if (!dir.exists()) {
        dir.mkdirs();
    }
}

Key Features

This service offers: - Logs errors with timestamps in a structured format - Extracts relevant stack trace details - Notifies administrators via email - Ensures logs are saved in a predefined directory

Conclusion

This custom error logging service simplifies error tracking and notification in Spring Boot applications. By capturing meaningful error messages and sending alerts in real time, it ensures faster debugging and issue resolution in production.