From 829b65c1c823a6fd0d76c6be733f2a99b70cb4cf Mon Sep 17 00:00:00 2001 From: theli Date: Thu, 9 Jun 2005 09:25:08 +0000 Subject: [PATCH] *) adding additional classes needed for new logging - ConsoleOutErrHandler.java used to log warnings/errors to stderr and all other messages to stdout - GuiHandler.java used to keep logging messages in memory that can then be viewed via the http gui - serverSimpleLogFormatter.java needed to format logging messages for FileHandler, ConsoleOutErrHandler and GuiHandler - serverMiniLogFormatter.java needed for proxy access logging git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@233 6c8d7289-2bf4-0310-a012-ef5d649a1542 --- .../server/logging/ConsoleOutErrHandler.java | 134 +++++++++++ .../server/logging/ConsoleOutHandler.java | 24 ++ .../de/anomic/server/logging/GuiHandler.java | 155 +++++++++++++ .../de/anomic/server/logging/serverLog.java | 211 ++++++++++++++++++ .../logging/serverMiniLogFormatter.java | 27 +++ .../logging/serverSimpleLogFormatter.java | 84 +++++++ 6 files changed, 635 insertions(+) create mode 100644 source/de/anomic/server/logging/ConsoleOutErrHandler.java create mode 100644 source/de/anomic/server/logging/ConsoleOutHandler.java create mode 100644 source/de/anomic/server/logging/GuiHandler.java create mode 100644 source/de/anomic/server/logging/serverLog.java create mode 100644 source/de/anomic/server/logging/serverMiniLogFormatter.java create mode 100644 source/de/anomic/server/logging/serverSimpleLogFormatter.java diff --git a/source/de/anomic/server/logging/ConsoleOutErrHandler.java b/source/de/anomic/server/logging/ConsoleOutErrHandler.java new file mode 100644 index 000000000..81d8a97f9 --- /dev/null +++ b/source/de/anomic/server/logging/ConsoleOutErrHandler.java @@ -0,0 +1,134 @@ +package de.anomic.server.logging; + +import java.util.logging.ConsoleHandler; +import java.util.logging.Filter; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; + +public class ConsoleOutErrHandler extends Handler{ + + private Level splitLevel = Level.WARNING; + private final Handler stdOutHandler = new ConsoleOutHandler(); + private final Handler stdErrHandler = new ConsoleHandler(); + + public ConsoleOutErrHandler() { + this.stdOutHandler.setLevel(Level.FINEST); + this.stdErrHandler.setLevel(Level.WARNING); + configure(); + } + + /** + * Get any configuration properties set + */ + private void configure() { + LogManager manager = LogManager.getLogManager(); + String className = getClass().getName(); + + String level = manager.getProperty(className + ".level"); + setLevel((level == null) ? Level.INFO : Level.parse(level)); + + Level levelStdOut = parseLevel(manager.getProperty(className + ".levelStdOut")); + Level levelSplit = parseLevel(manager.getProperty(className + ".levelSplit")); + Level levelStdErr = parseLevel(manager.getProperty(className + ".levelStdErr")); + setLevels(levelStdOut,levelSplit,levelStdErr); + + String filter = manager.getProperty(className + ".filter"); + setFilter(makeFilter(filter)); + + String formatter = manager.getProperty(className + ".formatter"); + setFormatter(makeFormatter(formatter)); + } + + private Level parseLevel(String levelName) { + try { + return (levelName == null) ? Level.INFO : Level.parse(levelName); + } catch (Exception e) { + return Level.ALL; + } + } + + private Filter makeFilter(String name) { + if (name == null) return null; + + Filter f = null; + try { + Class c = Class.forName(name); + f = (Filter)c.newInstance(); + } catch (Exception e) { + if (name != null) { + System.err.println("Unable to load filter: " + name); + } + } + return f; + } + + private Formatter makeFormatter(String name) { + if (name == null) return null; + + Formatter f = null; + try { + Class c = Class.forName(name); + f = (Formatter)c.newInstance(); + } catch (Exception e) { + f = new SimpleFormatter(); + } + return f; + } + + + public void publish(LogRecord record) { + if (!isLoggable(record)) return; + + if (record.getLevel().intValue() >= splitLevel.intValue()) { + this.stdErrHandler.publish(record); + } else { + this.stdOutHandler.publish(record); + } + } + + public void flush() { + this.stdOutHandler.flush(); + this.stdErrHandler.flush(); + } + + public void close() throws SecurityException { + this.stdOutHandler.close(); + this.stdErrHandler.close(); + } + + public synchronized void setLevel(Level newLevel) throws SecurityException { + super.setLevel(newLevel); + } + + public void setLevels(Level stdOutLevel, Level splitLevel, Level stdErrLevel) throws SecurityException { + this.stdOutHandler.setLevel(stdOutLevel); + this.splitLevel = splitLevel; + this.stdErrHandler.setLevel(stdErrLevel); + } + + public void setFormatter(Formatter newFormatter) throws SecurityException { + super.setFormatter(newFormatter); + if (newFormatter == null) return; + try { + this.stdOutHandler.setFormatter((Formatter)newFormatter.getClass().newInstance()); + this.stdErrHandler.setFormatter((Formatter)newFormatter.getClass().newInstance()); + } catch (Exception e) { + throw new SecurityException(e.getMessage()); + } + } + + public void setFilter(Filter newFilter) throws SecurityException { + super.setFilter(newFilter); + if (newFilter == null) return; + try { + this.stdOutHandler.setFilter((Filter)newFilter.getClass().newInstance()); + this.stdErrHandler.setFilter((Filter)newFilter.getClass().newInstance()); + } catch (Exception e) { + throw new SecurityException(e.getMessage()); + } + } +} diff --git a/source/de/anomic/server/logging/ConsoleOutHandler.java b/source/de/anomic/server/logging/ConsoleOutHandler.java new file mode 100644 index 000000000..adb764757 --- /dev/null +++ b/source/de/anomic/server/logging/ConsoleOutHandler.java @@ -0,0 +1,24 @@ +package de.anomic.server.logging; + +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; +import java.util.logging.StreamHandler; + +public final class ConsoleOutHandler extends StreamHandler{ + + public ConsoleOutHandler() { + setLevel(Level.FINEST); + setFormatter(new SimpleFormatter()); + setOutputStream(System.out); + } + + public synchronized void publish(LogRecord record) { + super.publish(record); + flush(); + } + + public void close() { + flush(); + } +} diff --git a/source/de/anomic/server/logging/GuiHandler.java b/source/de/anomic/server/logging/GuiHandler.java new file mode 100644 index 000000000..21d684ce7 --- /dev/null +++ b/source/de/anomic/server/logging/GuiHandler.java @@ -0,0 +1,155 @@ +package de.anomic.server.logging; + +import java.util.logging.ErrorManager; +import java.util.logging.Filter; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; + +public class GuiHandler extends Handler{ + + private final static int DEFAULT_SIZE = 400; + private int size = DEFAULT_SIZE; + private LogRecord buffer[]; + int start, count; + + + public GuiHandler() { + super(); + configure(); + init(); + } + + /** + * Get any configuration properties set + */ + private void configure() { + LogManager manager = LogManager.getLogManager(); + String className = getClass().getName(); + + String level = manager.getProperty(className + ".level"); + setLevel((level == null) ? Level.INFO : Level.parse(level)); + + String filter = manager.getProperty(className + ".filter"); + setFilter(makeFilter(filter)); + + String formatter = manager.getProperty(className + ".formatter"); + setFormatter(makeFormatter(formatter)); + + String sizeString = manager.getProperty(className + ".size"); + this.size = parseSize(sizeString); + } + + private int parseSize(String sizeString) { + int newSize = DEFAULT_SIZE; + try { + newSize = Integer.parseInt(sizeString); + } catch (NumberFormatException e) { + newSize = DEFAULT_SIZE; + } + return newSize; + } + + private Filter makeFilter(String name) { + if (name == null) return null; + + Filter f = null; + try { + Class c = Class.forName(name); + f = (Filter)c.newInstance(); + } catch (Exception e) { + System.err.println("Unable to load filter: " + name); + } + return f; + } + + private Formatter makeFormatter(String name) { + if (name == null) return null; + + Formatter f = null; + try { + Class c = Class.forName(name); + f = (Formatter)c.newInstance(); + } catch (Exception e) { + f = new SimpleFormatter(); + } + return f; + } + + // Initialize. Size is a count of LogRecords. + private void init() { + this.buffer = new LogRecord[this.size]; + this.start = 0; + this.count = 0; + } + + public synchronized void publish(LogRecord record) { + if (!isLoggable(record)) return; + + // write it to the buffer + int ix = (this.start+this.count)%this.buffer.length; + this.buffer[ix] = record; + if (this.count < this.buffer.length) { + this.count++; + } else { + this.start++; + } + } + + /** + * Push any buffered output to the target Handler. + *

+ * The buffer is then cleared. + */ + public synchronized LogRecord[] getLogArray() { + + LogRecord tempBuffer[] = new LogRecord[this.count]; + + for (int i = 0; i < this.count; i++) { + int ix = (this.start+i)%this.buffer.length; + LogRecord record = this.buffer[ix]; + tempBuffer[i] = record; + } + + return tempBuffer; + } + + public synchronized String getLog(boolean reversed, int lineCount) { + + if ((lineCount > this.count)||(lineCount < 0)) lineCount = this.count; + + StringBuffer logMessages = new StringBuffer(this.count*40); + Formatter logFormatter = getFormatter(); + + try { + int start = (reversed)?this.start+this.count-1:this.start; + for (int i = 0; i < Math.min(this.count,lineCount); i++) { + int ix = (reversed) ? + Math.abs((start-i)%this.buffer.length) : + (start+i)%this.buffer.length; + LogRecord record = this.buffer[ix]; + logMessages.append(logFormatter.format(record)); + } + return logMessages.toString(); + } catch (Exception ex) { + // We don't want to throw an exception here, but we + // report the exception to any registered ErrorManager. + reportError(null, ex, ErrorManager.FORMAT_FAILURE); + return "Error while formatting the logging message"; + } + } + + public void flush() { + // TODO Auto-generated method stub + + } + + public void close() throws SecurityException { + // TODO Auto-generated method stub + + } + +} diff --git a/source/de/anomic/server/logging/serverLog.java b/source/de/anomic/server/logging/serverLog.java new file mode 100644 index 000000000..8537b29c0 --- /dev/null +++ b/source/de/anomic/server/logging/serverLog.java @@ -0,0 +1,211 @@ +// serverLog.java +// ------------------------------------- +// (C) by Michael Peter Christen; mc@anomic.de +// first published on http://www.anomic.de +// Frankfurt, Germany, 2004 +// last major change: 04.08.2004 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Using this software in any meaning (reading, learning, copying, compiling, +// running) means that you agree that the Author(s) is (are) not responsible +// for cost, loss of data or any harm that may be caused directly or indirectly +// by usage of this softare or this documentation. The usage of this software +// is on your own risk. The installation and usage (starting/running) of this +// software may allow other people or application to access your computer and +// any attached devices and is highly dependent on the configuration of the +// software which must be done by the user of the software; the author(s) is +// (are) also not responsible for proper configuration and usage of the +// software, even if provoked by documentation provided together with +// the software. +// +// Any changes to this file according to the GPL as documented in the file +// gpl.txt aside this file in the shipment you received can be done to the +// lines that follows this copyright notice here, but changes must not be +// done inside the copyright notive above. A re-distribution must contain +// the intact and unchanged copyright notice. +// Contributions and changes to the program code must be marked as such. + +package de.anomic.server.logging; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.LinkedList; +import java.util.TimeZone; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +public final class serverLog { + +// // statics +// private static TimeZone GMTTimeZone = TimeZone.getTimeZone("PST"); +// private static SimpleDateFormat longFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); +// private static SimpleDateFormat shortFormatter = new SimpleDateFormat("yyyyMMddHHmmss"); +// +// // log-level categories + public static final int LOGLEVEL_ZERO = Level.OFF.intValue(); // no output at all + public static final int LOGLEVEL_FAILURE = Level.SEVERE.intValue(); // system-level error, internal cause, critical and not fixeable (i.e. inconsistency) + public static final int LOGLEVEL_ERROR = Level.SEVERE.intValue(); // exceptional error, catcheable and non-critical (i.e. file error) + public static final int LOGLEVEL_WARNING = Level.WARNING.intValue(); // uncritical service failure, may require user activity (i.e. input required, wrong authorization) + public static final int LOGLEVEL_SYSTEM = Level.CONFIG.intValue(); // regular system status information (i.e. start-up messages) + public static final int LOGLEVEL_INFO = Level.INFO.intValue(); // regular action information (i.e. any httpd request URL) + public static final int LOGLEVEL_DEBUG = Level.FINEST.intValue(); // in-function status debug output +// +// // these categories are also present as character tokens + public static final char LOGTOKEN_ZERO = 'Z'; + public static final char LOGTOKEN_FAILURE = 'F'; + public static final char LOGTOKEN_ERROR = 'E'; + public static final char LOGTOKEN_WARNING = 'W'; + public static final char LOGTOKEN_SYSTEM = 'S'; + public static final char LOGTOKEN_INFO = 'I'; + public static final char LOGTOKEN_DEBUG = 'D'; + +// // an array-wrapped function +// public static final char[] l2t = new char[] { +// LOGTOKEN_ZERO, LOGTOKEN_FAILURE, LOGTOKEN_ERROR, LOGTOKEN_WARNING, +// LOGTOKEN_SYSTEM, LOGTOKEN_INFO, LOGTOKEN_DEBUG +// }; + +// // statics +// private static serverLog genericLog = new serverLog("GENERIC", LOGLEVEL_DEBUG); // generic log +// private static LinkedList lastLog = new LinkedList(); // for Web-Interface +// private static int lastlogMaxSize = 400; // for Web-Interface +// +// // class variables +// private String appName; +// private int logLevel; + + private final Logger theLogger; + + public serverLog(String appName) { + //this(appName, LOGLEVEL_DEBUG); + this.theLogger = Logger.getLogger(appName); + } + + public serverLog(String appName, int logLevel) { + this(appName); +// this.logLevel = logLevel; +// this.appName = appName; + } + + public serverLog(String appName, char logToken) { + this(appName); +// this(appName, t2l(logToken)); + } + + public void setLoglevel(int newLevel) { +// this.logLevel = newLevel; + } + +// private static int t2l(char token) { +// switch (token) { +// case LOGTOKEN_ZERO: return LOGLEVEL_ZERO; +// case LOGTOKEN_FAILURE: return LOGLEVEL_FAILURE; +// case LOGTOKEN_ERROR: return LOGLEVEL_ERROR; +// case LOGTOKEN_WARNING: return LOGLEVEL_WARNING; +// case LOGTOKEN_SYSTEM: return LOGLEVEL_SYSTEM; +// case LOGTOKEN_INFO: return LOGLEVEL_INFO; +// case LOGTOKEN_DEBUG: return LOGLEVEL_DEBUG; +// } +// return LOGLEVEL_DEBUG; +// } +// +// private static String dateLongString() { +// return longFormatter.format(new GregorianCalendar(GMTTimeZone).getTime()); +// } +// +// private static String dateShortString() { +// return shortFormatter.format(new GregorianCalendar(GMTTimeZone).getTime()); +// } +// +// private void log(int messageLevel, String message) { +// if (messageLevel <= logLevel) { +// System.out.println(l2t[messageLevel] + " " + dateLongString() + " " + appName + " " + message); +// synchronized (lastLog) { +// lastLog.add(l2t[messageLevel] + " " + dateLongString() + " " + appName + " " + message); +// while (lastLog.size() > lastlogMaxSize) lastLog.removeFirst(); +// } +// } +// } + +// public static LinkedList getLastLog(){ +// return lastLog; +// } + + // class log messages + public void logFailure(String message) {this.theLogger.severe(message);} + public void logError(String message) {this.theLogger.severe(message);} + public void logWarning(String message) {this.theLogger.warning(message);} + public void logSystem(String message) {this.theLogger.config(message);} + public void logInfo(String message) {this.theLogger.info(message);} + public void logDebug(String message) {this.theLogger.finest(message);} + + + // static log messages: log everything + private static void log(String appName, int messageLevel, String message) { +// genericLog.appName = appName; +// genericLog.log(messageLevel, message); + Logger.getLogger(appName).log(Level.parse(Integer.toString(messageLevel)),message); + } + + public static void logFailure(String appName, String message) {Logger.getLogger(appName).severe(message);} + public static void logError(String appName, String message) {Logger.getLogger(appName).severe(message);} + public static void logWarning(String appName, String message) {Logger.getLogger(appName).warning(message);} + public static void logSystem(String appName, String message) {Logger.getLogger(appName).config(message);} + public static void logInfo(String appName, String message) {Logger.getLogger(appName).info(message);} + public static void logDebug(String appName, String message) {Logger.getLogger(appName).finest(message);} + + public static final void configureLogging(String homePath) throws SecurityException, FileNotFoundException, IOException { + + // loading the logger configuration from file + LogManager logManager = LogManager.getLogManager(); + logManager.readConfiguration(new FileInputStream(new File(homePath, "yacy.logging"))); + + // creating the logging directory + File log = new File("./log/"); + if(!log.canRead()) log.mkdir(); + + // generating the root logger + Logger logger = Logger.getLogger(""); + + //StreamHandler stdOut = new StreamHandler(System.out, new serverSimpleLogFormatter()); +// ConsoleOutErrHandler stdOutErr = new ConsoleOutErrHandler(); +// stdOutErr.setFormatter(new serverSimpleLogFormatter()); +// stdOutErr.setLevel(Level.ALL); +// stdOutErr.setLevels(Level.ALL,Level.WARNING,Level.ALL); +// +// FileHandler fileLog = new FileHandler("log/yacy%u%g.log",1024*1024, 20, true); +// fileLog.setFormatter(new serverSimpleLogFormatter()); +// fileLog.setLevel(Level.ALL); +// +// GuiHandler guiLog = new GuiHandler(); +// guiLog.setFormatter(new serverSimpleLogFormatter()); +// fileLog.setLevel(Level.ALL); +// +// logger.addHandler(fileLog); +// logger.addHandler(stdOutErr); +// logger.addHandler(guiLog); + + + } +} diff --git a/source/de/anomic/server/logging/serverMiniLogFormatter.java b/source/de/anomic/server/logging/serverMiniLogFormatter.java new file mode 100644 index 000000000..6684d87f5 --- /dev/null +++ b/source/de/anomic/server/logging/serverMiniLogFormatter.java @@ -0,0 +1,27 @@ +package de.anomic.server.logging; + +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; + +public final class serverMiniLogFormatter extends SimpleFormatter { + + private final StringBuffer buffer = new StringBuffer(); + + public serverMiniLogFormatter() { + super(); + } + + public synchronized String format(LogRecord record) { + + StringBuffer buffer = this.buffer; + buffer.setLength(0); + + buffer.append(formatMessage(record)); + + // adding the stack trace if available + buffer.append(System.getProperty("line.separator")); + + + return buffer.toString(); + } +} diff --git a/source/de/anomic/server/logging/serverSimpleLogFormatter.java b/source/de/anomic/server/logging/serverSimpleLogFormatter.java new file mode 100644 index 000000000..92ccd069e --- /dev/null +++ b/source/de/anomic/server/logging/serverSimpleLogFormatter.java @@ -0,0 +1,84 @@ +package de.anomic.server.logging; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.FieldPosition; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.ConsoleHandler; +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 org.apache.commons.collections.map.CaseInsensitiveMap; + +public class serverSimpleLogFormatter extends SimpleFormatter { + + + private Date date = new Date(); + private final FieldPosition position = new FieldPosition(0); + + // e.g. 2005/05/25 11:22:53 + private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + + private final StringBuffer buffer = new StringBuffer(); + + + public serverSimpleLogFormatter() { + super(); + } + + public synchronized String format(LogRecord record) { + + StringBuffer buffer = this.buffer; + buffer.setLength(0); + + // adding the loglevel + int logLevel = record.getLevel().intValue(); + if (logLevel == serverLog.LOGLEVEL_FAILURE) + this.buffer.append(serverLog.LOGTOKEN_FAILURE); + else if (logLevel == serverLog.LOGLEVEL_ERROR) + this.buffer.append(serverLog.LOGTOKEN_ERROR); + else if (logLevel == serverLog.LOGLEVEL_WARNING) + this.buffer.append(serverLog.LOGTOKEN_WARNING); + else if (logLevel == serverLog.LOGLEVEL_SYSTEM) + this.buffer.append(serverLog.LOGTOKEN_SYSTEM); + else if (logLevel == serverLog.LOGLEVEL_INFO) + this.buffer.append(serverLog.LOGTOKEN_INFO); + else if (logLevel == serverLog.LOGLEVEL_DEBUG) + this.buffer.append(serverLog.LOGTOKEN_DEBUG); + else + this.buffer.append(serverLog.LOGTOKEN_DEBUG); + this.buffer.append(' '); + + // adding the logging date + this.date.setTime(record.getMillis()); + this.position.setBeginIndex(0); + this.formatter.format(this.date, this.buffer, this.position); + + // adding the logger name + buffer.append(' '); + buffer.append(record.getLoggerName()); + + // adding the logging message + buffer.append(' '); + buffer.append(formatMessage(record)); + + // adding the stack trace if available + buffer.append(System.getProperty("line.separator")); + if (record.getThrown() != null) { + try { + StringWriter writer = new StringWriter(); + PrintWriter printer = new PrintWriter(writer); + record.getThrown().printStackTrace(printer); + writer.close(); + buffer.append(writer.toString()); + } catch (Exception e) { + buffer.append("Failed to get stack trace: " + e.getMessage()); + } + } + return buffer.toString(); + } +}