Logging the simple way

Here’s a simple class I use in my LWJGL games to log info and exceptions. I also wrote a blog post about it explaining this class. Suggestions are welcome. Features:

  • A simple, easy to maintain piece of code, no dependencies.
  • Write info, warning, or error messages along with the exact time of occurrence.
  • Write the full stack trace when an exception occurs.
  • Logfile rotating: avoid filling op storage space by limiting maximum logfile size. A backup will be made of the current log when the size is reached, and this backup will be overwritten by the next backup.

Be sure to initialize at startup.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Simple helper class for logging.
 */
public class Logging {

    static File file;
    static long maxSize;
    static SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

    /**
     * Initialize the log file.
     * 
     * @param fileName
     * @param maxSize
     */
    public static void initialize(String fileName, long maxSizeKb) {
        if (file != null) {
            throw new RuntimeException("Logging already initialized");
        }
        file = new File(fileName);
        Logging.maxSize = maxSizeKb * 1024;
    }

    /**
     * Write error message to the logfile.
     * 
     * @param message
     */
    public static void error(String message) {
        write("ERROR", message);
    }

    /**
     * Write error message to the logfile with additional exception information.
     * 
     * @param message
     * @param t
     */
    public static void error(String message, Throwable t) {
        write("ERROR", message, t);
    }

    /**
     * Write warning message to the logfile.
     * 
     * @param message
     */
    public static void warning(String message) {
        write("WARNING", message);
    }

    /**
     * Write information message to the logfile.
     * 
     * @param message
     */
    public static void info(String message) {
        write("INFO", message);
    }

    private static void write(String prefix, String message) {
        checkRotate();
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, true))) {
            bw.write("[" + prefix + " " + format.format(new Date()) + "] " + message + "\n");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    private static void write(String prefix, String message, Throwable t) {
        checkRotate();
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, true))) {
            bw.write("[" + prefix + " " + format.format(new Date()) + "] " + message + ":\n");
            t.printStackTrace(new PrintWriter(bw));
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        t.printStackTrace();
    }

    private static void checkRotate() {
        try {
            if (file.length() >= maxSize) {
                // Rotate logfiles
                File secondFile = new File(file.getName() + ".old");
                if (secondFile.exists()) {
                    secondFile.delete();
                }
                file.renameTo(secondFile);
            }
        } catch (Exception ioe) {
            ioe.printStackTrace();
        }
    }
}

If you want to you can add the full class name, method name and line number:


String fullClassName = Thread.currentThread().getStackTrace()[3].getClassName();            
String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();

message = "at " + fullClassName + "." + methodName + "(" + className + ".java:" + lineNumber + ")"
        	+ " Msg: \"" + message + "\"";

In Eclipse you can double click the message and you go to the file/line (if you print it to logcat).

Yeah that is a good one. You can also do this quite neatly using a PrintWriter, using the printStackTrace functionality:

Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
exception.printStackTrace(printWriter);
String stackTrace = writer.toString();