Java Logging Facade


Recently I implemented a small Java application to gain some insights into my teams performance. The result is a dashboard which indicates issues within the following sectors:

  • Process Compliance 
  • Throughput 
  • Provided Quality 

Based on the gathered data, the dashboard can be enriched to provide recommendations for counter measures which aim the resolution of those issues. This could be used to replace myself or – at least – reduce my workload.

While implementing my application I noticed the importance of proper logging frameworks and concepts during the development lifecycle of an application, as this has a major impact on the maintenance and operatibility of the application afterwards. While talking to Serviews ITIL trainers, I learned that the approx. costs per stage in the ITIL lifecycle is defined by the factor 8 (ITIL 2011 / Service Design). One invested hour for service operations considerations (e.g. logging) in the specification phase becomes 8 hours, when identified during the implementation or 64 when this needs to be added once the application has been set live on production. Therefore, by considering the total cost of the software lifecycle, the costs of software is highly reduced with proper specifications and involvement of all required parties at the right time.

Within my previous projects for the Application Integration and Middleware (AIM) sector, I noticed the same logging issues for different scenarios:

  • Java Custom Software
  • IBM Business Process Manager (form. Lombardi Teamworks) Processes
  • IBM Operational Decision Manager (form. iLOG JRules)

Creating or using logging facades always increased the quality of my codings. This can be done, by creating a custom logger, e.g. via Log4j or JUL loggers, and adding some customizable pre-statements before for each log statement. The pre-statement should be moved into a separate method. For BPEL or BPM engines adding a prefix like the business process instance and user id is always helpful when an executable hits the productive stage, e.g.:

    [12345][fabiansc] My Log Entry

For Java applications, I noticed that automatically adding the caller class and method is a good way to go. This can be realized via the Thread and StackTraces of the classes:

    private static String prefix() {        return "[" + Log.getCallerClassName() + "][" + getCallerMethodName() + "] ";    }
    private static String getCallerMethodName() {         StackTraceElement[] stElements = Thread.currentThread().getStackTrace();        for (int i=1; i<stElements.length; i++) {            StackTraceElement ste = stElements[i];            if (!ste.getClassName().equals(Log.class.getName()) && ste.getClassName().indexOf("java.lang.Thread")!=0) {                return ste.getMethodName();            }        }        return null;     }        public static String getCallerClassName() {         StackTraceElement[] stElements = Thread.currentThread().getStackTrace();        String callerClassName = null;        for (int i=1; i<stElements.length; i++) {            StackTraceElement ste = stElements[i];            if (!ste.getClassName().equals(Log.class.getName())&& ste.getClassName().indexOf("java.lang.Thread")!=0) {                if (callerClassName==null) {                    callerClassName = ste.getClassName();                } else if (!callerClassName.equals(ste.getClassName())) {                    return ste.getClassName();                }            }        }        return null;     }

The outcome of this facade is the same as for BPM frameworks:

[DataInterface][doPost] HTTPServlet has been triggered.

This gives insights into the processing of the application, without the need to understand the whole application stack, e.g. when maintenance teams switch resources. You could also say that this gives some depper application insights.


Most developers also struggle with the available log levels and their usage. Most projects do not provide guidelines when to use which level. The outcome is a not maintainable set of log statements, which make it hard to maintain or support applications, as it\’s hard to set the correct log level on productive environments, without having performance impact; in most cases you can also guess who will forget to remove unncessary log statements during implementation. Therefore I defined the usage of the log levels as followed within my projects:

  • Severe
    For technical exception cases, which breaks down the application flow (workflow is stucked).
try {    // do something.} catch (exception e) {    log.severe("External Interface is down. Data cannot be gathered. " + e);}
  • Warning
    For technical exception cases, which are being handled based on a defined workaround-scenario.
try {     // do something.} catch (exception e) {    log.warning("Failed to do something. Using cached values. " + e);}
  • Info
    For functional exception cases, which are handled, e.g. when values are set based on assumptions or being ignored. This is especially important in case of checkups or audits within Service Operations.
Private boolean getShipment() {    // do something.    log.info("Interface was unreachable. Navigating through offline-processing. " + "Details can be found within AppCi-123 / CR 123.");}
  • Fine
    General logging for the application. This should be used for all main flows within an application, such as start of method calls, the outcome of decisions within a functional flow or for logging of the return statement of method calls.
Public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {     log.fine("HTTPServlet has been called.");}
  • Finer
    Detailed logging for the application. This should be used within loops (for, while, do-while, etc.) or decisions (if, switch, etc.).
Public void resetObject() {    // do something.    for (int i = 0 ; i < n.length ; i++ ) {        log.finer("Resetting object n at index " + i + "(" + n[i] + ")");        // do something else.    }}
  • Finest
    Fine granular logging for the applciation. This should be used, if partial results for complex flows should be logged, e.g. during interim results of recursive interface flows or for developer debugging purposes:
Public void resetObject() {    // do something.    log.finest("#fabiansc resetObject. Resetting n :: " + n.toString());    for (int i = 0 ; i < n.length ; i++ ) {        log.finer("Resetting object n at index " + i + "(" + n[i] + ")");        // do something else.    }}