Some applications are difficult to extract debug logs from when there is a problem, especially if they do strange things with classloaders or run within a webserver environment.

If in doubt about where the logs are going, or the class has no access to the normal logging for some reason, don't be afraid to write your own “brute force” synchronized file logger – but make sure it is not present in production because it will be very slow!

package com.ryebuck.util;

import java.io.*;

/**
 * There are times when you MUST be able to debug and log code.
 * This throw-away class enables you to log when java logging
 * isn't showing output for some reason.
 */
public class Always
{
    private static String LOG_FILE_LOCATION = "/temp/always.log";
    private static boolean initialized = false;
     
    /**
     * Make sure that no one can construct or extend this class. Is debug
     */
    private Always()
    {
    }

    static public synchronized void log(String message, Exception e)
    {
        log(message);
        logThrowable(e);
    }

    /**
     * Log a message to the console and to the log file.
     */
    static public synchronized void log(String message)
    {
        FileOutputStream out = null;
        try
        {
            out = new FileOutputStream(LOG_FILE_LOCATION,initialized);
            initialized = true;
            PrintWriter pw = new PrintWriter(out);
            String caller = getCaller();
            String text = System.currentTimeMillis()  
                        + " [" + caller + " ] " + message;
            System.out.println(text);
            pw.println(text);
            pw.flush();
            pw.close();
        }
        catch (IOException e)
        {
            // no way to log, so just print it
            e.printStackTrace();
        }
        finally
        {
            // cleanup
            if (out != null) try {out.close();} catch (IOException e) {}
        }
    }

    /**
     * gets the line of the caller from the stack trace
     */
    public static String getCaller()
    {
        try
        {
            return getStackTraceElement(0);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return "unknown";
    }
     
    public static String getCallerCaller()
    {
        try
        {
            return getStackTraceElement(1);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return "unknown";
    }
  
    private static String getStackTraceElement(int levelsUp)
    {
        StackTraceElement[] stack = (new Exception()).getStackTrace();
         
        if (stack.length <= 3 + levelsUp)
        {
            return "JVM";
        }
        StackTraceElement element = stack[3 + levelsUp];
        return element.toString();
    }
     
    static public synchronized void logStack(String message)
    {
        try
        {
            log(message);
            logThrowable(new Throwable());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
     
    static public synchronized void logThrowable(Throwable t)
    {
        try
        {
            StringWriter sw = new StringWriter ();
            t.printStackTrace(new PrintWriter(sw));
            StringReader sr = new StringReader(sw.getBuffer().toString());
            BufferedReader br = new BufferedReader(sr);
            String line = br.readLine();
            int count = 0;
            while (line != null)
            {
                if (count > 1)  // ignore the first 2 lines
                {
                    log(line);
                }
                count++;
                line = br.readLine();
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
blog comments powered by Disqus