Simple logging

I’ve started learning OpenGL through following the ArcSynth tutorial series (there’s a nice Java implementation of the examples made by ra4king). As part of learning OpenGL and learning how to work with LWJGL I’ve been working on making a simple framework on which to build my OpenGL experiments, and later hopefully some nice games for desktop computers. Part of this framework is a simple logging class which I’m going to share here in case someone has use for it.

What are the requirements for this logging class?

  • 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.

Please note that there are all kinds of frameworks that do this logging for you, but I like to write my own code for such simple tasks, and avoid dependencies on external libraries if I can. Here’s some example output, showing my OpenGL framework failing on display initialization:

The nice thing of such logging is that I can get an immediate idea of where the problem occurred in my code (nl.bas.lib.AbstractGame line 92 in the initDisplay method), which makes debugging a lot easier. I can also see that cleaning up after the error occurred went well.

The class I use to do this logging is quite simple. I’ll go through it part by part, starting at the beginning:

The logger contains three static fields: a file to write the logging messages to, a maximum size for the log file, and a date formatter for the logging message timestamps. These fields, and the methods of the Logging class are static to ensure that they are accessible from anywhere in the application. The fields are set in the initialization method that must be called on startup:

After initialization messages may be logged, using a couple of logging methods:

Note that the error logging function has two versions: one that also writes a stack trace (Throwable is used here instead of Exception, as this also allows logging of Errors). The logging methods make use of a write method that writes output to the file:

These methods make use of the neat new Java 7 try-with-resources syntax that ensures that the output streams get closed correctly. The write methods take two steps: check if the logfile has become to big (checkRotate) and then write the log message to the file in a single write statement. The second one also writes the stack trace of the throwable to the file. Rotating the logfile is the last part of the Logging class:

And that’s it! In my code I try to follow the ‘throw early, catch late‘ approach, meaning I want the exceptions to be thrown as close to the point where things actually go wrong as possible, and catch them as late as possible. Here’s the way I do the catching, as an example:

This is the main entry point of my games (called directly from the main method). I log a couple of generic things here, like the different phases of the application: startup and shutdown. Additionally I catch the exceptions occurring in the application at the last possible moment, just before we return control to the operating system. This ensures that we handle exceptions in a consistent way, always logging them and showing a clear error message to the user. The Sys.alert method is a LWJGL method for showing a simple error dialog.

Here is the full class code, I hope you find some use for it:

Some usage tips:

  • Make sure to call Logging.initialize(fileName, maxSizeKb) at the start of the application (for example in main).
  • Although writing to the log is pretty fast, you should avoid calling it every frame as this would significantly slow down your game.
  • Write to the log in specific exceptional situations, e.g. on initialization or when cleaning up, so you can see what steps go well and what steps cause errors.
  • This implementation is not thread-safe (I think), so if you use multithreading pay attention :-)