import java.io.File;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
import java.util.logging.Level;
import java.util.Arrays;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.geom.Rectangle2D;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;

    /**
     * see http://weblogs.java.net/pub/wlg/1770
     */
public class AsciiArtFormatter extends Formatter {
    private final Formatter formatter;
    private final Font      font;
    private final Level     level;

    public AsciiArtFormatter() {
        this(null);
    }

    public AsciiArtFormatter(Formatter formatter) {
        this(formatter, null, null);
    }

    /**
     * Creates a formatter that will additionally use ascii art to log the message in the
     * given font if its log level is at least level.
     *
     * @param formatter used to format the message before appending ascii art message.
     *                  If null a default SimpleFormatter is used.
     * @param level     minimum level needed to enable ascii art logging.
     *                  If null Level.SEVERE is used.
     * @param font      font used for any ascii art output.
     *                  If null a sans serif font of size 18 is used.
     */
    public AsciiArtFormatter(Formatter formatter, Level level, Font font) {
        this.formatter = (formatter == null ? new SimpleFormatter() : formatter);
        this.level     = level == null ? Level.SEVERE : level;
        this.font      = font == null ? new Font("SansSerif", Font.PLAIN, 18) : font;
    }

    public String format(LogRecord record) {
        String message = formatter.format(record);
        if(record.getLevel().intValue() >= level.intValue()) {
            message = message + getAsciiArt(font, record.getMessage());
        }
        return message;
    }

    /**
     * @return the text as 'Ascii Art' in the given font using a '#' character for
     *         each pixel (the text itself if any runtime exception occurs)  
     */
    public static String getAsciiArt(Font font, String text) {
        try {
            if(text == null) {
                text = "(null)";
            }
            int tabWidth = 4;
            
            text = text.replaceAll("\\t", repeat(' ', tabWidth));
            FontRenderContext fontRenderContext = new FontRenderContext(null, false, false);
            StringBuffer      buffer            = new StringBuffer();
            String[]          lines             = text.split("\n|\r\n", 0);
            for(int lineIndex = 0; lineIndex < lines.length; lineIndex++) {
                // How stupid: TextLayout does not handle white space like I want to, and
                // GlyphVector has no convenient method to calculate overall ascent/descent.
                // So just use both...
    
                String      line        = lines[lineIndex];
                GlyphVector glyphVector = font.createGlyphVector(fontRenderContext, line);
                Rectangle2D bounds      = glyphVector.getLogicalBounds();
                int         width       = (int) bounds.getWidth();
                int         height      = (int) bounds.getHeight();

                if(line.length() == 0) {
                    buffer.append(repeat('\n', height));
                    continue;
                }

                TextLayout    textLayout = new TextLayout(line, font, fontRenderContext);
                float         ascent     = textLayout.getAscent();
                BufferedImage image      = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
                Graphics2D    graphics   = image.createGraphics();
                
                try {
                    graphics.drawGlyphVector(glyphVector, 0, ascent);

                    Raster raster = image.getRaster();
                    int[] ints = new int[1];
                    for(int y = 0; y < height; ++y) {
                        for(int x = 0; x < width; ++x) {
                            raster.getPixel(x, y, ints);
                            int pixelValue = ints[0];
                            buffer.append(pixelValue > 0 ? '#' : ' ');
                        }
                        buffer.append('\n');
                    }
                }
                finally {
                    graphics.dispose();
                }

            }

            return new String(buffer);
        }
        catch(RuntimeException e) {
            // Don't want anything silly to happen only because using this fun method.
            // Revert to plain output ;-(
            return text;
        }
    }
    
    /**
     * @return a string consisting of the character c repeated count times.
     */
    public static String repeat(char c, int count) {
        char[] fill = new char[count];
        Arrays.fill(fill, c);
        return new String(fill);
    }

    /**
     * main class to show how to use it
     */
    public static void main(String[] args) throws IOException {
        String userHome    = System.getProperty("user.home");
        File   logFile     = new File(userHome, "bigSevereText.log");
        String logFilePath = logFile.getPath();
        System.out.println("Logging to file " + logFilePath);    

        Logger logger = Logger.getLogger("default");
        logger.setLevel(Level.FINEST);
        FileHandler logFileHandler = new FileHandler(logFilePath);
        logFileHandler.setFormatter(new AsciiArtFormatter());
        logger.addHandler(logFileHandler);

        logger.fine("Fox prepares to jump.");
        logger.info("Fox is ready to jump.");
        logger.severe("Fox failed\nto jump over\nlazy dog.");
        logger.info("Dog is chasing fox.");
    }
}

