All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.vfny.geoserver.global.Log4JFormatter Maven / Gradle / Ivy

There is a newer version: 1.7.0
Show newest version
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org.  All rights reserved.
 * This code is licensed under the GPL 2.0 license, availible at the root
 * application directory.
 */
package org.vfny.geoserver.global;

import org.geotools.io.LineWriter;
import org.geotools.resources.Utilities;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import java.util.prefs.Preferences;


/**
 * Log4JFormatter looks like:
 * 
*
 * [core FINE] A log message logged with level FINE from the "org.geotools.core"
 * logger.
*
* A formatter writting log message on a single line. This formatter is used by * GeoServer instead of {@link SimpleFormatter}. The main difference is that * this formatter use only one line per message instead of two. For example, a * message formatted by * * @author Martin Desruisseaux * @author Rob Hranac * @version $Id: Log4JFormatter.java,v 1.3 2002/08/19 18:15:30 desruisseaux Exp */ public class Log4JFormatter extends Formatter { /** * The string to write at the begining of all log headers (e.g. "[FINE * core]") */ private static final String PREFIX = "["; /** * The string to write at the end of every log header (e.g. "[FINE core]"). * It should includes the spaces between the header and the message body. */ private static final String SUFFIX = "] "; /** * The string to write at the end of every log header (e.g. "[FINE core]"). * It should includes the spaces between the header and the message body. */ private static long startMillis; /** * The line separator. This is the value of the "line.separator" property * at the time the Log4JFormatter was created. */ private final String lineSeparator = System.getProperty("line.separator", "\n"); /** * The line separator for the message body. This line always begin with * {@link #lineSeparator}, followed by some amount of spaces in order to * align the message. */ private String bodyLineSeparator = lineSeparator; /** * The minimum amount of spaces to use for writting level and module name * before the message. For example if this value is 12, then a message * from module "org.geotools.core" with level FINE would be formatted as * "[core  FINE]the message" (i.e. the * whole [ ] part is 12 characters wide). */ private final int margin; /** * The base logger name. This is used for shortening the logger name when * formatting message. For example, if the base logger name is * "org.geotools" and a log record come from the "org.geotools.core" * logger, it will be formatted as "[LEVEL core]" (i.e. the * "org.geotools" part is ommited). */ private final String base; /** * Buffer for formatting messages. We will reuse this buffer in order to * reduce memory allocations. */ private final StringBuffer buffer; /** * The line writer. This object transform all "\r", "\n" or "\r\n" * occurences into a single line separator. This line separator will * include space for the marging, if needed. */ private final LineWriter writer; /** * Construct a Log4JFormatter. * * @param base The base logger name. This is used for shortening the logger * name when formatting message. For example, if the base logger * name is "org.geotools" and a log record come from the * "org.geotools.core" logger, it will be formatted as "[LEVEL * core]" (i.e. the "org.geotools" part is ommited). */ public Log4JFormatter(final String base) { this.base = base.trim(); this.margin = getHeaderWidth(); Log4JFormatter.startMillis = System.currentTimeMillis(); final StringWriter str = new StringWriter(); writer = new LineWriter(str); buffer = str.getBuffer(); } /** * Format the given log record and return the formatted string. * * @param record the log record to be formatted. * * @return a formatted log record * * @throws AssertionError Should never occur. */ public synchronized String format(final LogRecord record) { String logger = record.getLoggerName(); final String recordLevel = record.getLevel().getLocalizedName(); try { buffer.setLength(1); final Long millis = new Long(record.getMillis() - startMillis); writer.write(millis.toString()); writer.write(" "); writer.write(PREFIX); writer.write(recordLevel); writer.write(SUFFIX); if (record.getSourceClassName() != null) { writer.write(record.getSourceClassName()); } writer.write(" - "); /* * Now format the message. We will use a line separator made of * the usual EOL ("\r", "\n", or "\r\n", which is plateform * specific) following by some amout of space in order to align * message body. */ writer.setLineSeparator(bodyLineSeparator); if (record.getMessage() == null) { record.setMessage("null"); } writer.write(formatMessage(record)); writer.setLineSeparator(lineSeparator); writer.write('\n'); if (record.getThrown() != null) { try { writer.write(getStackTrace(record.getThrown())); } catch (Exception e) { // do not write the exception... } } writer.flush(); } catch (IOException exception) { // Should never happen, since we are writting into a StringBuffer. throw new AssertionError(exception); } return buffer.toString(); } /** * Returns the full stack trace of the given exception * @param record * @return */ private String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); pw.close(); return sw.toString(); } /** * Setup a Log4JFormatter for the specified logger and its * children. This method search for all instances of {@link * ConsoleHandler} using the {@link SimpleFormatter}. If such instances * are found, they are replaced by a single instance of * Log4JFormatter writting to the {@linkPlain System#out * standard output stream} (instead of the {@linkPlain System#err * standard error stream}). This action has no effect on any loggers * outside the base namespace. * * @param base The base logger name to apply the change on (e.g. * "org.geotools"). * @param filterLevel The level to log at - overrides user prefs. */ public static void init(final String base, Level filterLevel) { Formatter log4j = null; final Logger logger = org.geotools.util.logging.Logging.getLogger(base); //This little routine may be a bit buggy, but it's the best I've got //to make the levels change as we reload the dto's. Feel free to //improve. ch if (!logger.getUseParentHandlers()) { logger.setLevel(filterLevel); if (logger.getHandlers().length > 0) { Handler handler = logger.getHandlers()[0]; //this should be the right handler, if set with geoserver. if (handler != null) { handler.setLevel(filterLevel); } } } for (Logger parent = logger; parent.getUseParentHandlers();) { parent = parent.getParent(); if (parent == null) { break; } final Handler[] handlers = parent.getHandlers(); if (handlers != null) { for (int i = 0; i < handlers.length; i++) { /* * Search for a ConsoleHandler. Search is performed in the target * handler and all its parent loggers. When a ConsoleHandler is * found, it will be replaced by the Stdout handler for 'logger' * only. */ Handler handler = handlers[i]; if (handler.getClass().equals(ConsoleHandler.class)) { final Formatter formatter = handler.getFormatter(); if (formatter.getClass().equals(SimpleFormatter.class)) { if (log4j == null) { log4j = new Log4JFormatter(base); } try { logger.removeHandler(handler); handler = new Stdout(handler, log4j); handler.setLevel(filterLevel); } catch (UnsupportedEncodingException exception) { unexpectedException(exception); } catch (SecurityException exception) { unexpectedException(exception); } } } if (handler.getClass().equals(Stdout.class)) { handler.setLevel(filterLevel); } logger.addHandler(handler); logger.setLevel(filterLevel); } } } //Artie Konin suggested fix (see GEOS-366) if (0 == logger.getHandlers().length) // seems that getHandlers() cannot return null { log4j = new Log4JFormatter(base); Handler handler = new Stdout(); handler.setFormatter(log4j); handler.setLevel(filterLevel); logger.addHandler(handler); } logger.setUseParentHandlers(false); } /** * Invoked when an error occurs during the initialization. * * @param e the error that occured. */ private static void unexpectedException(final Exception e) { Utilities.unexpectedException("org.geotools.resources", "GeotoolsHandler", "init", e); } /** * Returns the header width. This is the default value to use for {@link * #margin}, if no value has been explicitely set. This value can be set * in user's preferences. * * @return The header width. */ private static int getHeaderWidth() { return Preferences.userNodeForPackage(Log4JFormatter.class).getInt("logging.header", 15); } /** * Set the header width. This is the default value to use for {@link * #margin} for next {@link Log4JFormatter} to be created. * * @param margin the size of the margin to set. */ static void setHeaderWidth(final int margin) { Preferences.userNodeForPackage(Log4JFormatter.class).putInt("logging.header", margin); } /** * A {@link ConsoleHandler} sending output to {@link System#out} instead of * {@link System#err} This handler will use a {@link Log4JFormatter} * writting log message on a single line. * * @task TODO: This class should subclass {@link ConsoleHandler}. * Unfortunatly, this is currently not possible because {@link * ConsoleHandler#setOutputStream} close {@link System#err}. If this * bug get fixed, then {@link #close} no longer need to be * overriden. */ private static final class Stdout extends StreamHandler { public Stdout() { super(); } /** * Construct a handler. * * @param handler The handler to copy properties from. * @param formatter The formatter to use. * * @throws UnsupportedEncodingException if the encoding is not valid. */ public Stdout(final Handler handler, final Formatter formatter) throws UnsupportedEncodingException { super(System.out, formatter); setErrorManager(handler.getErrorManager()); setFilter(handler.getFilter()); setLevel(handler.getLevel()); setEncoding(handler.getEncoding()); } /** * Publish a {@link LogRecord} and flush the stream. * * @param record the log record to publish. */ public void publish(final LogRecord record) { super.publish(record); flush(); } /** * Override {@link StreamHandler#close} to do a flush but not to close * the output stream. That is, we do not close {@link * System#out}. */ public void close() { flush(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy