Commit 44d1f5e0 authored by guus's avatar guus

Replacing Openfire custom logging implementation with SLF4J and Log4j (OF-53)

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@11195 b35dd754-fafc-0310-a699-88a17e54d16e
parent 7b16dc87
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="debug-out" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="../logs/debug.log" />
<param name="MaxFileSize" value="1024KB"/>
<param name="MaxBackupIndex" value="5"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy.MM.dd HH:mm:ss} %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="debug" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<appender name="info-out" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="../logs/info.log" />
<param name="MaxFileSize" value="1024KB"/>
<param name="MaxBackupIndex" value="5"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy.MM.dd HH:mm:ss} %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="info" />
<param name="LevelMin" value="info" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<appender name="warn-out" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="../logs/warn.log" />
<param name="MaxFileSize" value="1024KB"/>
<param name="MaxBackupIndex" value="5"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy.MM.dd HH:mm:ss} %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="warn" />
<param name="LevelMin" value="warn" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<appender name="error-out" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="../logs/error.log" />
<param name="MaxFileSize" value="1024KB"/>
<param name="MaxBackupIndex" value="5"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy.MM.dd HH:mm:ss} %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="error" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<root>
<level value="info" />
<appender-ref ref="debug-out" />
<appender-ref ref="info-out" />
<appender-ref ref="warn-out" />
<appender-ref ref="error-out" />
</root>
</log4j:configuration>
......@@ -313,7 +313,7 @@ public class SASLAuthentication {
}
}
else {
Log.fatal("SaslServer is null, should be valid object instead.");
Log.error("SaslServer is null, should be valid object instead.");
authenticationFailed(session);
status = Status.failed;
}
......
This diff is collapsed.
/**
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.util;
/**
* A simple logging service for components. Four log levels are provided:<ul>
*
* <li>Error -- an error occured in the component.
* <li>Warn -- a condition occured that an administrator should be warned about.
* <li>Info -- used to send information messages, such as a version or license notice.
* <li>Debug -- used to send debugging information. Most Log implementations will
* disable debug output by default.
* </ul>
*
* Log implementations will attempt use the native logging service of the component host
* server. However, this may not be possible in some cases -- for example, when using an
* external component that is not currently connected to the server.
*
* @author Matt Tucker
*/
public interface Logger {
/**
* Logs an error.
*
* @param message the error message.
*/
public void error(String message);
/**
* Logs an error.
*
* @param message the error message.
* @param throwable the Throwable that caused the error.
*/
public void error(String message, Throwable throwable);
/**
* Logs an error.
*
* @param throwable the Throwable that caused the error.
*/
public void error(Throwable throwable);
/**
* Logs a warning.
*
* @param message the warning message.
*/
public void warn(String message);
/**
* Logs a warning.
*
* @param message the warning message.
* @param throwable the Throwable that caused the error.
*/
public void warn(String message, Throwable throwable);
/**
* Logs a warning.
*
* @param throwable the Throwable that caused the error.
*/
public void warn(Throwable throwable);
/**
* Logs an info message.
*
* @param message the info message.
*/
public void info(String message);
/**
* Logs an info message.
*
* @param message the info message.
* @param throwable the Throwable that caused the info message.
*/
public void info(String message, Throwable throwable);
/**
* Logs an info message.
*
* @param throwable the Throwable that caused the info message.
*/
public void info(Throwable throwable);
/**
* Logs a debug message.
*
* @param message the debug message.
*/
public void debug(String message);
/**
* Logs a debug message.
*
* @param message the debug message.
* @param throwable the Throwable that caused the debug message.
*/
public void debug(String message, Throwable throwable);
/**
* Logs a debug message.
*
* @param throwable the Throwable the caused the debug message.
*/
public void debug(Throwable throwable);
}
\ No newline at end of file
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* The ContextMap contains non-hierarchical context information
* relevent to a particular LogEvent. It may include information
* such as;
* <p/>
* <ul>
* <li>user -&gt;fred</li>
* <li>hostname -&gt;helm.realityforge.org</li>
* <li>ipaddress -&gt;1.2.3.4</li>
* <li>interface -&gt;127.0.0.1</li>
* <li>caller -&gt;com.biz.MyCaller.method(MyCaller.java:18)</li>
* <li>source -&gt;1.6.3.2:33</li>
* </ul>
* The context is bound to a thread (and inherited by sub-threads) but
* it can also be added to by LogTargets.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public final class ContextMap implements Serializable {
///Thread local for holding instance of map associated with current thread
private static final ThreadLocal c_context = new InheritableThreadLocal();
private final ContextMap m_parent;
///Container to hold map of elements
private Map m_map = Collections.synchronizedMap(new HashMap());
///Flag indicating whether this map should be readonly
private transient boolean m_readOnly;
/**
* Get the Current ContextMap.
* This method returns a ContextMap associated with current thread. If the
* thread doesn't have a ContextMap associated with it then a new
* ContextMap is created.
*
* @return the current ContextMap
*/
public final static ContextMap getCurrentContext() {
return getCurrentContext(true);
}
/**
* Get the Current ContextMap.
* This method returns a ContextMap associated with current thread.
* If the thread doesn't have a ContextMap associated with it and
* autocreate is true then a new ContextMap is created.
*
* @param autocreate true if a ContextMap is to be created if it doesn't exist
* @return the current ContextMap
*/
public final static ContextMap getCurrentContext(final boolean autocreate) {
//Check security permission here???
ContextMap context = (ContextMap)c_context.get();
if (null == context && autocreate) {
context = new ContextMap();
c_context.set(context);
}
return context;
}
/**
* Bind a particular ContextMap to current thread.
*
* @param context the context map (may be null)
*/
public final static void bind(final ContextMap context) {
//Check security permission here??
c_context.set(context);
}
/**
* Default constructor.
*/
public ContextMap() {
this(null);
}
/**
* Constructor that sets parent contextMap.
*
* @param parent the parent ContextMap
*/
public ContextMap(final ContextMap parent) {
m_parent = parent;
}
/**
* Make the context read-only.
* This makes it safe to allow untrusted code reference
* to ContextMap.
*/
public void makeReadOnly() {
m_readOnly = true;
}
/**
* Determine if context is read-only.
*
* @return true if Context is read only, false otherwise
*/
public boolean isReadOnly() {
return m_readOnly;
}
/**
* Empty the context map.
*/
public void clear() {
checkReadable();
m_map.clear();
}
/**
* Get an entry from the context.
*
* @param key the key to map
* @param defaultObject a default object to return if key does not exist
* @return the object in context
*/
public Object get(final String key, final Object defaultObject) {
final Object object = get(key);
if (null != object)
return object;
else
return defaultObject;
}
/**
* Get an entry from the context.
*
* @param key the key to map
* @return the object in context or null if none with specified key
*/
public Object get(final String key) {
final Object result = m_map.get(key);
if (null == result && null != m_parent) {
return m_parent.get(key);
}
return result;
}
/**
* Set a value in context
*
* @param key the key
* @param value the value (may be null)
*/
public void set(final String key, final Object value) {
checkReadable();
if (value == null) {
m_map.remove(key);
}
else {
m_map.put(key, value);
}
}
/**
* Get the number of contexts in map.
*
* @return the number of contexts in map
*/
public int getSize() {
return m_map.size();
}
/**
* Helper method that sets context to read-only after de-serialization.
*
* @return the corrected object version
* @throws ObjectStreamException if an error occurs
*/
private Object readResolve() throws ObjectStreamException {
makeReadOnly();
return this;
}
/**
* Utility method to verify that Context is read-only.
*/
private void checkReadable() {
if (isReadOnly()) {
throw new IllegalStateException("ContextMap is read only and can not be modified");
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
/**
* Interface implemented by components that wish to
* delegate ErrorHandling to an ErrorHandler.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public interface ErrorAware {
/**
* Provide component with ErrorHandler.
*
* @param errorHandler the errorHandler
*/
void setErrorHandler(ErrorHandler errorHandler);
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
/**
* Handle unrecoverable errors that occur during logging.
* Based on Log4js notion of ErrorHandlers.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public interface ErrorHandler {
/**
* Log an unrecoverable error.
*
* @param message the error message
* @param throwable the exception associated with error (may be null)
* @param event the LogEvent that caused error, if any (may be null)
*/
void error(String message, Throwable throwable, LogEvent event);
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
/**
* A Log target which will do filtering and then pass it
* onto targets further along in chain.
* <p/>
* <p>Filtering can mena that not all LogEvents get passed
* along chain or that the LogEvents passed alongare modified
* in some manner.</p>
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface FilterTarget extends LogTarget {
/**
* Add a target to output chain.
*
* @param target the log target
*/
void addTarget(LogTarget target);
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
import org.jivesoftware.util.log.format.PatternFormatter;
import org.jivesoftware.util.log.output.io.StreamTarget;
import org.jivesoftware.util.log.util.DefaultErrorHandler;
/**
* This class encapsulates a basic independent log hierarchy.
* The hierarchy is essentially a safe wrapper around root logger.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class Hierarchy {
///Format of default formatter
private static final String FORMAT =
"%7.7{priority} %5.5{time} [%8.8{category}] (%{context}): %{message}\\n%{throwable}";
///The instance of default hierarchy
private static final Hierarchy c_hierarchy = new Hierarchy();
///Error Handler associated with hierarchy
private ErrorHandler m_errorHandler;
///The root logger which contains all Loggers in this hierarchy
private Logger m_rootLogger;
/**
* Retrieve the default hierarchy.
* <p/>
* <p>In most cases the default LogHierarchy is the only
* one used in an application. However when security is
* a concern or multiple independent applications will
* be running in same JVM it is advantageous to create
* new Hierarchies rather than reuse default.</p>
*
* @return the default Hierarchy
*/
public static Hierarchy getDefaultHierarchy() {
return c_hierarchy;
}
/**
* Create a hierarchy object.
* The default LogTarget writes to stdout.
*/
public Hierarchy() {
m_errorHandler = new DefaultErrorHandler();
m_rootLogger = new Logger(new InnerErrorHandler(), "", null, null);
//Setup default output target to print to console
final PatternFormatter formatter = new PatternFormatter(FORMAT);
final StreamTarget target = new StreamTarget(System.out, formatter);
setDefaultLogTarget(target);
}
/**
* Set the default log target for hierarchy.
* This is the target inherited by loggers if no other target is specified.
*
* @param target the default target
*/
public void setDefaultLogTarget(final LogTarget target) {
if (null == target) {
throw new IllegalArgumentException("Can not set DefaultLogTarget to null");
}
final LogTarget[] targets = new LogTarget[]{target};
getRootLogger().setLogTargets(targets);
}
/**
* Set the default log targets for this hierarchy.
* These are the targets inherited by loggers if no other targets are specified
*
* @param targets the default targets
*/
public void setDefaultLogTargets(final LogTarget[] targets) {
if (null == targets || 0 == targets.length) {
throw new IllegalArgumentException("Can not set DefaultLogTargets to null");
}
for (int i = 0; i < targets.length; i++) {
if (null == targets[i]) {
throw new IllegalArgumentException("Can not set DefaultLogTarget element to null");
}
}
getRootLogger().setLogTargets(targets);
}
/**
* Set the default priority for hierarchy.
* This is the priority inherited by loggers if no other priority is specified.
*
* @param priority the default priority
*/
public void setDefaultPriority(final Priority priority) {
if (null == priority) {
throw new IllegalArgumentException("Can not set default Hierarchy Priority to null");
}
getRootLogger().setPriority(priority);
}
/**
* Set the ErrorHandler associated with hierarchy.
*
* @param errorHandler the ErrorHandler
*/
public void setErrorHandler(final ErrorHandler errorHandler) {
if (null == errorHandler) {
throw new IllegalArgumentException("Can not set default Hierarchy ErrorHandler to null");
}
m_errorHandler = errorHandler;
}
/**
* Retrieve a logger for named category.
*
* @param category the context
* @return the Logger
*/
public Logger getLoggerFor(final String category) {
return getRootLogger().getChildLogger(category);
}
// /**
// * Logs an error message to error handler.
// * Default Error Handler is stderr.
// *
// * @param message a message to log
// * @param throwable a Throwable to log
// * @deprecated Logging components should use ErrorHandler rather than Hierarchy.log()
// */
// public void log(final String message, final Throwable throwable) {
// m_errorHandler.error(message, throwable, null);
// }
//
// /**
// * Logs an error message to error handler.
// * Default Error Handler is stderr.
// *
// * @param message a message to log
// * @deprecated Logging components should use ErrorHandler rather than Hierarchy.log()
// */
// public void log(final String message) {
// log(message, null);
// }
private class InnerErrorHandler
implements ErrorHandler {
/**
* Log an unrecoverable error.
*
* @param message the error message
* @param throwable the exception associated with error (may be null)
* @param event the LogEvent that caused error, if any (may be null)
*/
public void error(final String message,
final Throwable throwable,
final LogEvent event) {
m_errorHandler.error(message, throwable, event);
}
}
/**
* Utility method to retrieve logger for hierarchy.
* This method is intended for use by sub-classes
* which can take responsibility for manipulating
* Logger directly.
*
* @return the Logger
*/
protected final Logger getRootLogger() {
return m_rootLogger;
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* This class encapsulates each individual log event.
* LogEvents usually originate at a Logger and are routed
* to LogTargets.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public final class LogEvent
implements Serializable {
//A Constant used when retrieving time relative to start of applicaiton start
private final static long START_TIME = System.currentTimeMillis();
///The category that this LogEvent concerns. (Must not be null)
private String m_category;
///The message to be logged. (Must not be null)
private String m_message;
///The exception that caused LogEvent if any. (May be null)
private Throwable m_throwable;
///The time in millis that LogEvent occurred
private long m_time;
///The priority of LogEvent. (Must not be null)
private Priority m_priority;
///The context map associated with LogEvent. (May be null).
private ContextMap m_contextMap;
/**
* Get Priority for LogEvent.
*
* @return the LogEvent Priority
*/
public final Priority getPriority() {
return m_priority;
}
/**
* Set the priority of LogEvent.
*
* @param priority the new LogEvent priority
*/
public final void setPriority(final Priority priority) {
m_priority = priority;
}
/**
* Get ContextMap associated with LogEvent
*
* @return the ContextMap
*/
public final ContextMap getContextMap() {
return m_contextMap;
}
/**
* Set the ContextMap for this LogEvent.
*
* @param contextMap the context map
*/
public final void setContextMap(final ContextMap contextMap) {
m_contextMap = contextMap;
}
// /**
// * Get ContextStack associated with LogEvent
// *
// * @return the ContextStack
// * @deprecated ContextStack has been deprecated and thus so has this method
// */
// public final ContextStack getContextStack()
// {
// return m_contextStack;
// }
// /**
// * Set the ContextStack for this LogEvent.
// * Note that if this LogEvent ever changes threads, the
// * ContextStack must be cloned.
// *
// * @param contextStack the context stack
// * @deprecated ContextStack has been deprecated and thus so has this method
// */
// public final void setContextStack( final ContextStack contextStack )
// {
// m_contextStack = contextStack;
// }
/**
* Get the category that LogEvent relates to.
*
* @return the name of category
*/
public final String getCategory() {
return m_category;
}
/**
* Get the message associated with event.
*
* @return the message
*/
public final String getMessage() {
return m_message;
}
/**
* Get throwabe instance associated with event.
*
* @return the Throwable
*/
public final Throwable getThrowable() {
return m_throwable;
}
/**
* Get the absolute time of the log event.
*
* @return the absolute time
*/
public final long getTime() {
return m_time;
}
/**
* Get the time of the log event relative to start of application.
*
* @return the time
*/
public final long getRelativeTime() {
return m_time - START_TIME;
}
/**
* Set the LogEvent category.
*
* @param category the category
*/
public final void setCategory(final String category) {
m_category = category;
}
/**
* Set the message for LogEvent.
*
* @param message the message
*/
public final void setMessage(final String message) {
m_message = message;
}
/**
* Set the throwable for LogEvent.
*
* @param throwable the instance of Throwable
*/
public final void setThrowable(final Throwable throwable) {
m_throwable = throwable;
}
/**
* Set the absolute time of LogEvent.
*
* @param time the time
*/
public final void setTime(final long time) {
m_time = time;
}
/**
* Helper method that replaces deserialized priority with correct singleton.
*
* @return the singleton version of object
* @throws ObjectStreamException if an error occurs
*/
private Object readResolve()
throws ObjectStreamException {
if (null == m_category) m_category = "";
if (null == m_message) m_message = "";
String priorityName = "";
if (null != m_priority) {
priorityName = m_priority.getName();
}
m_priority = Priority.getPriorityForName(priorityName);
return this;
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
/**
* LogTarget is a class to encapsulate outputting LogEvent's.
* This provides the base for all output and filter targets.
* <p/>
* Warning: If performance becomes a problem then this
* interface will be rewritten as a abstract class.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public interface LogTarget {
/**
* Process a log event.
* In NO case should this method ever throw an exception/error.
* The reason is that logging is usually added for debugging/auditing
* purposes and it would be unnaceptable to have your debugging
* code cause more errors.
*
* @param event the event
*/
void processEvent(LogEvent event);
}
This diff is collapsed.
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* Class representing and holding constants for priority.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public final class Priority implements Serializable {
/**
* Developer orientated messages, usually used during development of product.
*/
public final static Priority DEBUG = new Priority("DEBUG", 5);
/**
* Useful information messages such as state changes, client connection, user login etc.
*/
public final static Priority INFO = new Priority("INFO", 10);
/**
* A problem or conflict has occurred but it may be recoverable, then
* again it could be the start of the system failing.
*/
public final static Priority WARN = new Priority("WARN", 15);
/**
* A problem has occurred but it is not fatal. The system will still function.
*/
public final static Priority ERROR = new Priority("ERROR", 20);
/**
* Something caused whole system to fail. This indicates that an administrator
* should restart the system and try to fix the problem that caused the failure.
*/
public final static Priority FATAL_ERROR = new Priority("FATAL_ERROR", 25);
private final String m_name;
private final int m_priority;
/**
* Retrieve a Priority object for the name parameter.
*
* @param priority the priority name
* @return the Priority for name
*/
public static Priority getPriorityForName(final String priority) {
if (Priority.DEBUG.getName().equals(priority))
return Priority.DEBUG;
else if (Priority.INFO.getName().equals(priority))
return Priority.INFO;
else if (Priority.WARN.getName().equals(priority))
return Priority.WARN;
else if (Priority.ERROR.getName().equals(priority))
return Priority.ERROR;
else if (Priority.FATAL_ERROR.getName().equals(priority))
return Priority.FATAL_ERROR;
else
return Priority.DEBUG;
}
/**
* Private Constructor to block instantiation outside class.
*
* @param name the string name of priority
* @param priority the numerical code of priority
*/
private Priority(final String name, final int priority) {
m_name = name;
m_priority = priority;
}
/**
* Overidden string to display Priority in human readable form.
*
* @return the string describing priority
*/
public String toString() {
return "Priority[" + getName() + "/" + getValue() + "]";
}
/**
* Get numerical value associated with priority.
*
* @return the numerical value
*/
public int getValue() {
return m_priority;
}
/**
* Get name of priority.
*
* @return the priorities name
*/
public String getName() {
return m_name;
}
/**
* Test whether this priority is greater than other priority.
*
* @param other the other Priority
*/
public boolean isGreater(final Priority other) {
return m_priority > other.getValue();
}
/**
* Test whether this priority is lower than other priority.
*
* @param other the other Priority
*/
public boolean isLower(final Priority other) {
return m_priority < other.getValue();
}
/**
* Test whether this priority is lower or equal to other priority.
*
* @param other the other Priority
*/
public boolean isLowerOrEqual(final Priority other) {
return m_priority <= other.getValue();
}
/**
* Helper method that replaces deserialized object with correct singleton.
*
* @return the singleton version of object
* @throws ObjectStreamException if an error occurs
*/
private Object readResolve()
throws ObjectStreamException {
return getPriorityForName(m_name);
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.filter;
import org.jivesoftware.util.log.FilterTarget;
import org.jivesoftware.util.log.LogEvent;
import org.jivesoftware.util.log.LogTarget;
/**
* Abstract implementation of FilterTarget.
* A concrete implementation has to implement filter method.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public abstract class AbstractFilterTarget
implements FilterTarget, LogTarget {
//Log targets in filter chain
private LogTarget m_targets[];
/**
* Add a new target to output chain.
*
* @param target the target
*/
public void addTarget(final LogTarget target) {
if (null == m_targets) {
m_targets = new LogTarget[]{target};
}
else {
final LogTarget oldTargets[] = m_targets;
m_targets = new LogTarget[oldTargets.length + 1];
System.arraycopy(oldTargets, 0, m_targets, 0, oldTargets.length);
m_targets[m_targets.length - 1] = target;
}
}
/**
* Filter the log event.
*
* @param event the event
* @return return true to discard event, false otherwise
*/
protected abstract boolean filter(LogEvent event);
/**
* Process a log event
*
* @param event the log event
*/
public void processEvent(final LogEvent event) {
if (null == m_targets || filter(event))
return;
else {
for (int i = 0; i < m_targets.length; i++) {
m_targets[i].processEvent(event);
}
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.filter;
import org.jivesoftware.util.log.LogEvent;
import org.jivesoftware.util.log.Priority;
/**
* Filters log events based on priority.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class PriorityFilter extends AbstractFilterTarget {
///Priority to filter against
private Priority m_priority;
/**
* Constructor that sets the priority that is filtered against.
*
* @param priority the Priority
*/
public PriorityFilter(final Priority priority) {
m_priority = priority;
}
/**
* Set priority used to filter.
*
* @param priority the priority to filter on
*/
public void setPriority(final Priority priority) {
m_priority = priority;
}
/**
* Filter the log event based on priority.
* <p/>
* If LogEvent has a Lower priroity then discard it.
*
* @param event the event
* @return return true to discard event, false otherwise
*/
protected boolean filter(final LogEvent event) {
return (!m_priority.isLower(event.getPriority()));
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.format;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.log.ContextMap;
import org.jivesoftware.util.log.LogEvent;
import org.jivesoftware.util.log.util.StackIntrospector;
/**
* Formatter especially designed for debugging applications.
* <p/>
* This formatter extends the standard PatternFormatter to add
* two new possible expansions. These expansions are %{method}
* and %{thread}. In both cases the context map is first checked
* for values with specified key. This is to facilitate passing
* information about caller/thread when threads change (as in
* AsyncLogTarget). They then attempt to determine appropriate
* information dynamically.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @version CVS $Revision$ $Date$
*/
public class ExtendedPatternFormatter extends PatternFormatter {
private final static int TYPE_METHOD = MAX_TYPE + 1;
private final static int TYPE_THREAD = MAX_TYPE + 2;
private final static String TYPE_METHOD_STR = "method";
private final static String TYPE_THREAD_STR = "thread";
public ExtendedPatternFormatter(final String format) {
super(format);
}
/**
* Retrieve the type-id for a particular string.
*
* @param type the string
* @return the type-id
*/
protected int getTypeIdFor(final String type) {
if (type.equalsIgnoreCase(TYPE_METHOD_STR))
return TYPE_METHOD;
else if (type.equalsIgnoreCase(TYPE_THREAD_STR))
return TYPE_THREAD;
else {
return super.getTypeIdFor(type);
}
}
/**
* Formats a single pattern run (can be extended in subclasses).
*
* @param run the pattern run to format.
* @return the formatted result.
*/
protected String formatPatternRun(final LogEvent event, final PatternRun run) {
switch (run.m_type) {
case TYPE_METHOD:
return getMethod(event, run.m_format);
case TYPE_THREAD:
return getThread(event, run.m_format);
default:
return super.formatPatternRun(event, run);
}
}
/**
* Utility method to format category.
*
* @param event
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
private String getMethod(final LogEvent event, final String format) {
final ContextMap map = event.getContextMap();
if (null != map) {
final Object object = map.get("method");
if (null != object) {
return object.toString();
}
}
// final String result = StackIntrospector.getCallerMethod(Logger.class);
final String result = StackIntrospector.getCallerMethod(Log.class);
if (null == result) {
return "UnknownMethod";
}
return result;
}
/**
* Utility thread to format category.
*
* @param event
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
private String getThread(final LogEvent event, final String format) {
final ContextMap map = event.getContextMap();
if (null != map) {
final Object object = map.get("thread");
if (null != object) {
return object.toString();
}
}
return Thread.currentThread().getName();
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.format;
import org.jivesoftware.util.log.LogEvent;
/**
* This defines the interface for components that wish to serialize
* LogEvents into Strings.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public interface Formatter {
/**
* Serialize log event into string.
*
* @param event the event
* @return the formatted string
*/
String format(LogEvent event);
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output;
import org.jivesoftware.util.log.LogEvent;
import org.jivesoftware.util.log.format.Formatter;
/**
* Abstract output target.
* Any new output target that is writing to a single connected
* resource should extend this class directly or indirectly.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public abstract class AbstractOutputTarget
extends AbstractTarget {
/**
* Formatter for target.
*/
private Formatter m_formatter;
/**
* Parameterless constructor.
*/
public AbstractOutputTarget() {
}
public AbstractOutputTarget(final Formatter formatter) {
m_formatter = formatter;
}
/**
* Retrieve the associated formatter.
*
* @return the formatter
* @deprecated Access to formatter is not advised and this method will be removed
* in future iterations. It remains only for backwards compatability.
*/
public synchronized Formatter getFormatter() {
return m_formatter;
}
/**
* Set the formatter.
*
* @param formatter the formatter
* @deprecated In future this method will become protected access.
*/
public synchronized void setFormatter(final Formatter formatter) {
writeTail();
m_formatter = formatter;
writeHead();
}
/**
* Abstract method to send data.
*
* @param data the data to be output
*/
protected void write(final String data) {
output(data);
}
/**
* Abstract method that will output event.
*
* @param data the data to be output
* @deprecated User should overide send() instead of output(). Output exists
* for backwards compatability and will be removed in future.
*/
protected void output(final String data) {
}
protected void doProcessEvent(LogEvent event) {
final String data = format(event);
write(data);
}
/**
* Startup log session.
*/
protected synchronized void open() {
if (!isOpen()) {
super.open();
writeHead();
}
}
/**
* Shutdown target.
* Attempting to send to target after close() will cause errors to be logged.
*/
public synchronized void close() {
if (isOpen()) {
writeTail();
super.close();
}
}
/**
* Helper method to format an event into a string, using the formatter if available.
*
* @param event the LogEvent
* @return the formatted string
*/
private String format(final LogEvent event) {
if (null != m_formatter) {
return m_formatter.format(event);
}
else {
return event.toString();
}
}
/**
* Helper method to send out log head.
* The head initiates a session of logging.
*/
private void writeHead() {
if (!isOpen()) return;
final String head = getHead();
if (null != head) {
write(head);
}
}
/**
* Helper method to send out log tail.
* The tail completes a session of logging.
*/
private void writeTail() {
if (!isOpen()) return;
final String tail = getTail();
if (null != tail) {
write(tail);
}
}
/**
* Helper method to retrieve head for log session.
* TODO: Extract from formatter
*
* @return the head string
*/
private String getHead() {
return null;
}
/**
* Helper method to retrieve tail for log session.
* TODO: Extract from formatter
*
* @return the head string
*/
private String getTail() {
return null;
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output;
import org.jivesoftware.util.log.ErrorAware;
import org.jivesoftware.util.log.ErrorHandler;
import org.jivesoftware.util.log.LogEvent;
import org.jivesoftware.util.log.LogTarget;
/**
* Abstract target.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public abstract class AbstractTarget implements LogTarget, ErrorAware {
///ErrorHandler used by target to delegate Error handling
private ErrorHandler m_errorHandler;
///Flag indicating that log session is finished (aka target has been closed)
private boolean m_isOpen;
/**
* Provide component with ErrorHandler.
*
* @param errorHandler the errorHandler
*/
public synchronized void setErrorHandler(final ErrorHandler errorHandler) {
m_errorHandler = errorHandler;
}
protected synchronized boolean isOpen() {
return m_isOpen;
}
/**
* Startup log session.
*/
protected synchronized void open() {
if (!isOpen()) {
m_isOpen = true;
}
}
/**
* Process a log event, via formatting and outputting it.
*
* @param event the log event
*/
public synchronized void processEvent(final LogEvent event) {
if (!isOpen()) {
getErrorHandler().error("Writing event to closed stream.", null, event);
return;
}
try {
doProcessEvent(event);
}
catch (final Throwable throwable) {
getErrorHandler().error("Unknown error writing event.", throwable, event);
}
}
/**
* Process a log event, via formatting and outputting it.
* This should be overidden by subclasses.
*
* @param event the log event
*/
protected abstract void doProcessEvent(LogEvent event)
throws Exception;
/**
* Shutdown target.
* Attempting to send to target after close() will cause errors to be logged.
*/
public synchronized void close() {
if (isOpen()) {
m_isOpen = false;
}
}
/**
* Helper method to retrieve ErrorHandler for subclasses.
*
* @return the ErrorHandler
*/
protected final ErrorHandler getErrorHandler() {
return m_errorHandler;
}
/**
* Helper method to send error messages to error handler.
*
* @param message the error message
* @param throwable the exception if any
* @deprecated Use getErrorHandler().error(...) directly
*/
protected final void error(final String message, final Throwable throwable) {
getErrorHandler().error(message, throwable, null);
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output;
import org.jivesoftware.util.log.ErrorAware;
import org.jivesoftware.util.log.ErrorHandler;
import org.jivesoftware.util.log.LogEvent;
import org.jivesoftware.util.log.LogTarget;
import java.util.LinkedList;
/**
* An asynchronous LogTarget that sends entries on in another thread.
* It is the responsibility of the user of this class to start
* the thread etc.
* <p/>
* <pre>
* LogTarget mySlowTarget = ...;
* AsyncLogTarget asyncTarget = new AsyncLogTarget( mySlowTarget );
* Thread thread = new Thread( asyncTarget );
* thread.setPriority( Thread.MIN_PRIORITY );
* thread.start();
* <p/>
* logger.setLogTargets( new LogTarget[] { asyncTarget } );
* </pre>
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class AsyncLogTarget extends AbstractTarget implements Runnable {
private final LinkedList m_list;
private final int m_queueSize;
private final LogTarget m_logTarget;
public AsyncLogTarget(final LogTarget logTarget) {
this(logTarget, 15);
}
public AsyncLogTarget(final LogTarget logTarget, final int queueSize) {
m_logTarget = logTarget;
m_list = new LinkedList();
m_queueSize = queueSize;
open();
}
/**
* Provide component with ErrorHandler.
*
* @param errorHandler the errorHandler
*/
public synchronized void setErrorHandler(final ErrorHandler errorHandler) {
super.setErrorHandler(errorHandler);
if (m_logTarget instanceof ErrorAware) {
((ErrorAware)m_logTarget).setErrorHandler(errorHandler);
}
}
/**
* Process a log event by adding it to queue.
*
* @param event the log event
*/
public void doProcessEvent(final LogEvent event) {
synchronized (m_list) {
final int size = m_list.size();
while (m_queueSize <= size) {
try {
m_list.wait();
}
catch (final InterruptedException ie) {
//This really should not occur ...
//Maybe we should log it though for
//now lets ignore it
}
}
m_list.addFirst(event);
if (size == 0) {
//tell the "server" thread to wake up
//if it is waiting for a queue to contain some items
m_list.notify();
}
}
}
public void run() {
//set this variable when thread is interupted
//so we know we can shutdown thread soon.
boolean interupted = false;
while (true) {
LogEvent event = null;
synchronized (m_list) {
while (null == event) {
final int size = m_list.size();
if (size > 0) {
event = (LogEvent)m_list.removeLast();
if (size == m_queueSize) {
//tell the "client" thread to wake up
//if it is waiting for a queue position to open up
m_list.notify();
}
}
else if (interupted || Thread.interrupted()) {
//ie there is nothing in queue and thread is interrupted
//thus we stop thread
return;
}
else {
try {
m_list.wait();
}
catch (final InterruptedException ie) {
//Ignore this and let it be dealt in next loop
//Need to set variable as the exception throw cleared status
interupted = true;
}
}
}
}
try {
//actually process an event
m_logTarget.processEvent(event);
}
catch (final Throwable throwable) {
getErrorHandler().error("Unknown error writing event.", throwable, event);
}
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io;
import org.jivesoftware.util.log.format.Formatter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* A basic target that writes to a File.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class FileTarget extends StreamTarget {
///File we are writing to
private File m_file;
///Flag indicating whether or not file should be appended to
private boolean m_append;
/**
* Construct file target to send to a file with a formatter.
*
* @param file the file to send to
* @param append true if file is to be appended to, false otherwise
* @param formatter the Formatter
* @throws IOException if an error occurs
*/
public FileTarget(final File file, final boolean append, final Formatter formatter)
throws IOException {
super(null, formatter);
if (null != file) {
setFile(file, append);
openFile();
}
}
/**
* Set the file for this target.
*
* @param file the file to send to
* @param append true if file is to be appended to, false otherwise
* @throws IOException if directories can not be created or file can not be opened
*/
protected synchronized void setFile(final File file, final boolean append)
throws IOException {
if (null == file) {
throw new NullPointerException("file property must not be null");
}
if (isOpen()) {
throw new IOException("target must be closed before " +
"file property can be set");
}
m_append = append;
m_file = file;
}
/**
* Open underlying file and allocate resources.
* This method will attempt to create directories below file and
* append to it if specified.
*/
protected synchronized void openFile()
throws IOException {
if (isOpen()) close();
final File file = getFile().getCanonicalFile();
final File parent = file.getParentFile();
if (null != parent && !parent.exists()) {
parent.mkdir();
}
final FileOutputStream outputStream =
new FileOutputStream(file.getPath(), m_append);
setOutputStream(outputStream);
open();
}
/**
* Retrieve file associated with target.
* This allows subclasses to access file object.
*
* @return the output File
*/
protected synchronized File getFile() {
return m_file;
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io;
import org.jivesoftware.util.log.format.Formatter;
import org.jivesoftware.util.log.output.AbstractOutputTarget;
import java.io.IOException;
import java.io.OutputStream;
/**
* A basic target that writes to an OutputStream.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class StreamTarget extends AbstractOutputTarget {
///OutputStream we are writing to
private OutputStream m_outputStream;
/**
* Constructor that writes to a stream and uses a particular formatter.
*
* @param outputStream the OutputStream to send to
* @param formatter the Formatter to use
*/
public StreamTarget(final OutputStream outputStream, final Formatter formatter) {
super(formatter);
if (null != outputStream) {
setOutputStream(outputStream);
open();
}
}
/**
* Set the output stream.
* Close down old stream and send tail if appropriate.
*
* @param outputStream the new OutputStream
*/
protected synchronized void setOutputStream(final OutputStream outputStream) {
if (null == outputStream) {
throw new NullPointerException("outputStream property must not be null");
}
m_outputStream = outputStream;
}
/**
* Abstract method that will output event.
*
* @param data the data to be output
*/
protected synchronized void write(final String data) {
//Cache method local version
//so that can be replaced in another thread
final OutputStream outputStream = m_outputStream;
if (null == outputStream) {
final String message = "Attempted to send data '" + data + "' to Null OutputStream";
getErrorHandler().error(message, null, null);
return;
}
try {
//TODO: We should be able to specify encoding???
outputStream.write(data.getBytes("UTF-8"));
outputStream.flush();
}
catch (final IOException ioe) {
final String message = "Error writing data '" + data + "' to OutputStream";
getErrorHandler().error(message, ioe, null);
}
}
/**
* Shutdown target.
* Attempting to send to target after close() will cause errors to be logged.
*/
public synchronized void close() {
super.close();
shutdownStream();
}
/**
* Shutdown output stream.
*/
protected synchronized void shutdownStream() {
final OutputStream outputStream = m_outputStream;
m_outputStream = null;
try {
if (null != outputStream) {
outputStream.close();
}
}
catch (final IOException ioe) {
getErrorHandler().error("Error closing OutputStream", ioe, null);
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io;
import org.jivesoftware.util.log.format.Formatter;
import org.jivesoftware.util.log.output.AbstractOutputTarget;
import java.io.IOException;
import java.io.Writer;
/**
* This target outputs to a writer.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class WriterTarget extends AbstractOutputTarget {
private Writer m_output;
/**
* Construct target with a specific writer and formatter.
*
* @param writer the writer
* @param formatter the formatter
*/
public WriterTarget(final Writer writer, final Formatter formatter) {
super(formatter);
if (null != writer) {
setWriter(writer);
open();
}
}
/**
* Set the writer.
* Close down writer and send tail if appropriate.
*
* @param writer the new writer
*/
protected synchronized void setWriter(final Writer writer) {
if (null == writer) {
throw new NullPointerException("writer property must not be null");
}
m_output = writer;
}
/**
* Concrete implementation of output that writes out to underlying writer.
*
* @param data the data to output
*/
protected void write(final String data) {
try {
m_output.write(data);
m_output.flush();
}
catch (final IOException ioe) {
getErrorHandler().error("Caught an IOException", ioe, null);
}
}
/**
* Shutdown target.
* Attempting to send to target after close() will cause errors to be logged.
*/
public synchronized void close() {
super.close();
shutdownWriter();
}
/**
* Shutdown Writer.
*/
protected synchronized void shutdownWriter() {
final Writer writer = m_output;
m_output = null;
try {
if (null != writer) {
writer.close();
}
}
catch (final IOException ioe) {
getErrorHandler().error("Error closing Writer", ioe, null);
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* strategy for naming log files based on appending revolving suffix.
* <p/>
* Heavily odified by Bruce Ritchie (Jive Software) to rotate along
* the following strategy:
* <p/>
* current log file will always be the base File name
* the next oldest file will be the _1 file
* the next oldest file will be the _2 file
* etc.
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
*/
public class ExpandingFileStrategy implements FileStrategy {
///the base file name.
private String baseFileName;
public ExpandingFileStrategy(final String baseFileName) {
this.baseFileName = baseFileName;
}
public File currentFile() {
return new File(baseFileName);
}
/**
* Calculate the real file name from the base filename.
*
* @return File the calculated file name
*/
public File nextFile() {
// go through all the possible filenames and delete/rename as necessary
for (int i = 0; true; i++) {
File test = new File(baseFileName.substring(0, baseFileName.lastIndexOf('.')) +
"_" + i + baseFileName.substring(baseFileName.lastIndexOf('.')));
if (test.exists()) {
continue;
}
else {
return test;
}
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* Strategy for naming log files.
* For a given base file name an implementation calculates
* the real file name.
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public interface FileStrategy {
/**
* Get the current logfile
*/
File currentFile();
/**
* Get the next log file to rotate to.
*
* @return the file to rotate to
*/
File nextFile();
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* Hierarchical Rotation stragety.
* This object is initialised with several rotation strategy objects.
* The <code>isRotationNeeded</code> method checks the first rotation
* strategy object. If a rotation is needed, this result is returned.
* If not the next rotation strategy object is asked and so on.
*
* @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
*/
public class OrRotateStrategy
implements RotateStrategy {
private RotateStrategy[] m_strategies;
/**
* The rotation strategy used. This marker is required for the reset()
* method.
*/
private int m_usedRotation = -1;
/**
* Constructor
*/
public OrRotateStrategy(final RotateStrategy[] strategies) {
this.m_strategies = strategies;
}
/**
* reset.
*/
public void reset() {
if (-1 != m_usedRotation) {
m_strategies[m_usedRotation].reset();
m_usedRotation = -1;
}
}
/**
* check if now a log rotation is neccessary.
* This object is initialised with several rotation strategy objects.
* The <code>isRotationNeeded</code> method checks the first rotation
* strategy object. If a rotation is needed, this result is returned.
* If not the next rotation strategy object is asked and so on.
*
* @param data the last message written to the log system
* @return boolean return true if log rotation is neccessary, else false
*/
public boolean isRotationNeeded(final String data, final File file) {
m_usedRotation = -1;
if (null != m_strategies) {
final int length = m_strategies.length;
for (int i = 0; i < length; i++) {
if (true == m_strategies[i].isRotationNeeded(data, file)) {
m_usedRotation = i;
return true;
}
}
}
return false;
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* strategy for naming log files based on appending revolving suffix.
* <p/>
* Heavily odified by Bruce Ritchie (Jive Software) to rotate along
* the following strategy:
* <p/>
* current log file will always be the base File name
* the next oldest file will be the _1 file
* the next oldest file will be the _2 file
* etc.
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
*/
public class RevolvingFileStrategy implements FileStrategy {
///max file prefix count
private int maxCount;
///the base file name.
private String baseFileName;
public RevolvingFileStrategy(final String baseFileName, final int maxCount) {
this.baseFileName = baseFileName;
this.maxCount = maxCount;
if (-1 == this.maxCount) {
this.maxCount = 5;
}
}
public File currentFile() {
return new File(baseFileName);
}
/**
* Calculate the real file name from the base filename.
*
* @return File the calculated file name
*/
public File nextFile() {
// go through all the possible filenames and delete/rename as necessary
for (int i = maxCount; i > 0; i--) {
File test = new File(baseFileName.substring(0, baseFileName.lastIndexOf('.')) +
"_" + i + baseFileName.substring(baseFileName.lastIndexOf('.')));
if (i == maxCount && test.exists()) {
test.delete();
}
if (test.exists()) {
File r = new File(baseFileName.substring(0, baseFileName.lastIndexOf('.')) +
"_" + (i + 1) + baseFileName.substring(baseFileName.lastIndexOf('.')));
test.renameTo(r);
}
}
// rename the current file
File current = new File(baseFileName);
File first = new File(baseFileName.substring(0, baseFileName.lastIndexOf('.')) +
"_1" + baseFileName.substring(baseFileName.lastIndexOf('.')));
current.renameTo(first);
// return the base filename
return new File(baseFileName);
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* Strategy that checks condition under which file rotation is needed.
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
*/
public interface RotateStrategy {
/**
* reset cumulative rotation history data.
* Called after rotation.
*/
void reset();
/**
* Check if a log rotation is neccessary at this time.
*
* @param data the serialized version of last message written to the log system
* @param file the File that we are writing to
* @return boolean return true if log rotation is neccessary, else false
*/
boolean isRotationNeeded(String data, File file);
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* Rotation stragety based on size written to log file.
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
*/
public class RotateStrategyBySize
implements RotateStrategy {
private long m_maxSize;
private long m_currentSize;
/**
* Rotate logs by size.
* By default do log rotation after writing approx. 1MB of messages
*/
public RotateStrategyBySize() {
this(1024 * 1024);
}
/**
* Rotate logs by size.
*
* @param maxSize rotate after writing max_size [byte] of messages
*/
public RotateStrategyBySize(final long maxSize) {
m_currentSize = 0;
m_maxSize = maxSize;
}
/**
* reset log size written so far.
*/
public void reset() {
m_currentSize = 0;
}
/**
* Check if now a log rotation is neccessary.
*
* @param data the last message written to the log system
* @return boolean return true if log rotation is neccessary, else false
*/
public boolean isRotationNeeded(final String data, final File file) {
m_currentSize += data.length();
if (m_currentSize >= m_maxSize) {
m_currentSize = 0;
return true;
}
else {
return false;
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import java.io.File;
/**
* rotation stragety based when log writting started.
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
*/
public class RotateStrategyByTime
implements RotateStrategy {
///time interval when rotation is triggered.
private long m_timeInterval;
///time when logging started.
private long m_startingTime;
///rotation count.
private long m_currentRotation;
/**
* Rotate logs by time.
* By default do log rotation every 24 hours
*/
public RotateStrategyByTime() {
this(1000 * 60 * 60 * 24);
}
/**
* Rotate logs by time.
*
* @param timeInterval rotate after time-interval [ms] has expired
*/
public RotateStrategyByTime(final long timeInterval) {
m_startingTime = System.currentTimeMillis();
m_currentRotation = 0;
m_timeInterval = timeInterval;
}
/**
* reset interval history counters.
*/
public void reset() {
m_startingTime = System.currentTimeMillis();
m_currentRotation = 0;
}
/**
* Check if now a log rotation is neccessary.
* If
* <code>(current_time - m_startingTime) / m_timeInterval &gt; m_currentRotation </code>
* rotation is needed.
*
* @param data the last message written to the log system
* @return boolean return true if log rotation is neccessary, else false
*/
public boolean isRotationNeeded(final String data, final File file) {
final long newRotation =
(System.currentTimeMillis() - m_startingTime) / m_timeInterval;
if (newRotation > m_currentRotation) {
m_currentRotation = newRotation;
return true;
}
else {
return false;
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import org.jivesoftware.util.log.format.Formatter;
import org.jivesoftware.util.log.output.io.FileTarget;
import java.io.File;
import java.io.IOException;
/**
* This is a basic Output log target that writes to rotating files.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:mcconnell@osm.net">Stephen McConnell</a>
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
*/
public class RotatingFileTarget extends FileTarget {
///The rotation strategy to be used.
private RotateStrategy m_rotateStrategy;
///The file strategy to be used.
private FileStrategy m_fileStrategy;
/**
* Construct RotatingFileTarget object.
*
* @param formatter Formatter to be used
*/
public RotatingFileTarget(final Formatter formatter,
final RotateStrategy rotateStrategy,
final FileStrategy fileStrategy)
throws IOException {
super(null, false, formatter);
m_rotateStrategy = rotateStrategy;
m_fileStrategy = fileStrategy;
getInitialFile();
}
public synchronized void rotate()
throws IOException {
close();
final File file = m_fileStrategy.nextFile();
setFile(file, false);
openFile();
}
/**
* Output the log message, and check if rotation is needed.
*/
public synchronized void write(final String data) {
// send the log message
super.write(data);
// if rotation is needed, close old File, create new File
final boolean rotate =
m_rotateStrategy.isRotationNeeded(data, getFile());
if (rotate) {
try {
rotate();
}
catch (final IOException ioe) {
getErrorHandler().error("Error rotating file", ioe, null);
}
}
}
private void getInitialFile() throws IOException {
close();
boolean rotate = m_rotateStrategy.isRotationNeeded("", m_fileStrategy.currentFile());
if (rotate) {
setFile(m_fileStrategy.nextFile(), false);
}
else {
setFile(m_fileStrategy.currentFile(), true);
}
openFile();
}
}
\ No newline at end of file
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.output.io.rotate;
import org.jivesoftware.util.FastDateFormat;
import java.io.File;
import java.util.Date;
/**
* Strategy for naming log files based on appending time suffix.
* A file name can be based on simply appending the number of miliseconds
* since (not really sure) 1/1/1970.
* Other constructors accept a pattern of a <code>SimpleDateFormat</code>
* to form the appended string to the base file name as well as a suffix
* which should be appended last.
* <p/>
* A <code>new UniqueFileStrategy( new File("foo.", "yyyy-MM-dd", ".log" )</code>
* object will return <code>File</code> objects with file names like
* <code>foo.2001-12-24.log</code>
*
* @author <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
* @author <a href="mailto:giacomo@apache.org">Giacomo Pati</a>
*/
public class UniqueFileStrategy
implements FileStrategy {
private File m_baseFile;
private File m_currentFile;
private FastDateFormat m_formatter;
private String m_suffix;
public UniqueFileStrategy(final File baseFile) {
m_baseFile = baseFile;
}
public UniqueFileStrategy(final File baseFile, String pattern) {
this(baseFile);
m_formatter = FastDateFormat.getInstance(pattern);
}
public UniqueFileStrategy(final File baseFile, String pattern, String suffix) {
this(baseFile, pattern);
m_suffix = suffix;
}
public File currentFile() {
return m_currentFile;
}
/**
* Calculate the real file name from the base filename.
*
* @return File the calculated file name
*/
public File nextFile() {
final StringBuilder sb = new StringBuilder();
sb.append(m_baseFile);
if (m_formatter == null) {
sb.append(System.currentTimeMillis());
}
else {
final String dateString = m_formatter.format(new Date());
sb.append(dateString);
}
if (m_suffix != null) {
sb.append(m_suffix);
}
m_currentFile = new File(sb.toString());
return m_currentFile;
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.util;
import org.jivesoftware.util.log.ErrorHandler;
import org.jivesoftware.util.log.LogEvent;
/**
* Handle unrecoverable errors that occur during logging by
* writing to standard error.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class DefaultErrorHandler
implements ErrorHandler {
/**
* Log an unrecoverable error.
*
* @param message the error message
* @param throwable the exception associated with error (may be null)
* @param event the LogEvent that caused error, if any (may be null)
*/
public void error(final String message,
final Throwable throwable,
final LogEvent event) {
System.err.println("Logging Error: " + message);
if (null != throwable) {
throwable.printStackTrace();
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.util;
import org.jivesoftware.util.log.Logger;
import org.jivesoftware.util.log.Priority;
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
/**
* Redirect an output stream to a logger.
* This class is useful to redirect standard output or
* standard error to a Logger. An example use is
* <p/>
* <pre>
* final LoggerOutputStream outputStream =
* new LoggerOutputStream( logger, Priority.DEBUG );
* final PrintStream output = new PrintStream( outputStream, true );
* <p/>
* System.setOut( output );
* </pre>
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class LoggerOutputStream
extends OutputStream {
///Logger that we log to
private final Logger m_logger;
///Log level we log to
private final Priority m_priority;
///The buffered output so far
private final StringBuffer m_output = new StringBuffer();
///Flag set to true once stream closed
private boolean m_closed;
/**
* Construct OutputStreamLogger to send to a particular logger at a particular priority.
*
* @param logger the logger to send to
* @param priority the priority at which to log
*/
public LoggerOutputStream(final Logger logger,
final Priority priority) {
m_logger = logger;
m_priority = priority;
}
/**
* Shutdown stream.
*/
public void close()
throws IOException {
flush();
super.close();
m_closed = true;
}
/**
* Write a single byte of data to output stream.
*
* @param data the byte of data
* @throws IOException if an error occurs
*/
public void write(final int data)
throws IOException {
checkValid();
//Should we properly convert char using locales etc??
m_output.append((char)data);
if ('\n' == data) {
flush();
}
}
/**
* Flush data to underlying logger.
*
* @throws IOException if an error occurs
*/
public synchronized void flush()
throws IOException {
checkValid();
m_logger.log(m_priority, m_output.toString());
m_output.setLength(0);
}
/**
* Make sure stream is valid.
*
* @throws IOException if an error occurs
*/
private void checkValid()
throws IOException {
if (true == m_closed) {
throw new EOFException("OutputStreamLogger closed");
}
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.util;
import org.jivesoftware.util.log.Logger;
import org.jivesoftware.util.log.Priority;
/**
* Redirect an output stream to a logger.
* This class is useful to redirect standard output or
* standard error to a Logger. An example use is
* <p/>
* <pre>
* final OutputStreamLogger outputStream =
* new OutputStreamLogger( logger, Priority.DEBUG );
* final PrintStream output = new PrintStream( outputStream, true );
* <p/>
* System.setOut( output );
* </pre>
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @deprecated Use LoggerOutputStream as this class was misnamed.
*/
public class OutputStreamLogger
extends LoggerOutputStream {
/**
* Construct logger to send to a particular logger at a particular priority.
*
* @param logger the logger to send to
* @param priority the priority at which to log
* @deprecated Use LoggerOutputStream as this class was misnamed.
*/
public OutputStreamLogger(final Logger logger,
final Priority priority) {
super(logger, priority);
}
}
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.jivesoftware.util.log.util;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* A set of utilities to inspect current stack frame.
*
* @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
* @author <a href="mailto:stuart.roebuck@adolos.com">Stuart Roebuck</a>
*/
public final class StackIntrospector {
/**
* Hack to get the call stack as an array of classes. The
* SecurityManager class provides it as a protected method, so
* change it to public through a new method !
*/
private final static class CallStack
extends SecurityManager {
/**
* Returns the current execution stack as an array of classes.
* The length of the array is the number of methods on the execution
* stack. The element at index 0 is the class of the currently executing
* method, the element at index 1 is the class of that method's caller,
* and so on.
*/
public Class[] get() {
return getClassContext();
}
}
///Method to cache CallStack hack as needed
private static CallStack c_callStack;
/**
* Private constructor to block instantiation.
*/
private StackIntrospector() {
}
/**
* Create Hack SecurityManager to get CallStack.
*
* @return the CallStack object
* @throws SecurityException if an existing SecurityManager disallows construction
* of another SecurityManager
*/
private synchronized static CallStack getCallStack()
throws SecurityException {
if (null == c_callStack) {
//Lazily create CallStack accessor as appropriate
c_callStack = new CallStack();
}
return c_callStack;
}
/**
* Find the caller of the passed in Class.
* May return null if caller not found on execution stack
*
* @param clazz the Class to search for on stack to find caller of
* @return the Class of object that called parrameter class
* @throws SecurityException if an existing SecurityManager disallows construction
* of another SecurityManager and thus blocks method results
*/
public final static Class getCallerClass(final Class clazz)
throws SecurityException {
final Class[] stack = getCallStack().get();
// Traverse the call stack in reverse order until we find clazz
for (int i = stack.length - 1; i >= 0; i--) {
if (clazz.isAssignableFrom(stack[i])) {
// Found : the caller is the previous stack element
return stack[i + 1];
}
}
//Unable to locate class in call stack
return null;
}
/**
* Get the method path name for the method from which the LogEvent was
* created, this includes the path name and the source filename and line
* number if the source was compiled with debugging on.
*
* @return The method path name in the form "the.package.path.Method"
*/
public final static String getCallerMethod(final Class clazz) {
final String className = clazz.getName();
//Extract stack into a StringBuffer
final StringWriter sw = new StringWriter();
final Throwable throwable = new Throwable();
throwable.printStackTrace(new PrintWriter(sw, true));
final StringBuffer buffer = sw.getBuffer();
//Cache vars used in loop
final StringBuffer line = new StringBuffer();
final int length = buffer.length();
//setup state
boolean found = false;
int state = 0;
//parse line
for (int i = 0; i < length; i++) {
final char ch = buffer.charAt(i);
switch (state) {
case 0:
//Strip the first line from input
if ('\n' == ch) state = 1;
break;
case 1:
//strip 't' from 'at'
if ('t' == ch) state = 2;
break;
case 2:
//Strip space after 'at'
line.setLength(0);
state = 3;
break;
case 3:
//accumulate all characters to end of line
if ('\n' != ch)
line.append(ch);
else {
//At this stage you have the line that looks like
//com.biz.SomeClass.someMethod(SomeClass.java:22)
final String method = line.toString();
///Determine if line is a match for class
final boolean match = method.startsWith(className);
if (!found && match) {
//If this is the first time we cound class then
//set found to true and look for caller into class
found = true;
}
else if (found && !match) {
//We have now located caller of Clazz
return method;
}
//start parsing from start of line again
state = 1;
}
}
}
return "";
}
/**
* Return the current call stack as a String, starting with the first call
* in the stack after a reference to the <code>clazz</code> class, and then
* display <code>entries</code> entries.
* <p/>
* <p>This can be useful for debugging code to determine where calls to a
* method are coming from.</p>
*
* @param clazz the last class on the stack you are <i>not</i> interested in!
* @param entries the number of stack lines to return.
* @return The method path name in the form "the.package.path.Method"
*/
public final static String getRecentStack(final Class clazz, int entries) {
final String className = clazz.getName();
//Extract stack into a StringBuffer
final StringWriter sw = new StringWriter();
final Throwable throwable = new Throwable();
throwable.printStackTrace(new PrintWriter(sw, true));
final StringBuffer buffer = sw.getBuffer();
//Cache vars used in loop
final StringBuffer line = new StringBuffer();
final StringBuffer stack = new StringBuffer();
final int length = buffer.length();
//setup state
boolean found = false;
int state = 0;
//parse line
for (int i = 0; i < length; i++) {
final char ch = buffer.charAt(i);
switch (state) {
case 0:
//Strip the first line from input
if ('\n' == ch) state = 1;
break;
case 1:
//strip 't' from 'at'
if ('t' == ch) state = 2;
break;
case 2:
//Strip space after 'at'
line.setLength(0);
state = 3;
break;
case 3:
//accumulate all characters to end of line
if ('\n' != ch)
line.append(ch);
else {
//At this stage you have the line that looks like
//com.biz.SomeClass.someMethod(SomeClass.java:22)
final String method = line.toString();
///Determine if line is a match for class
final boolean match = method.startsWith(className);
if (!found && match) {
//If this is the first time we cound class then
//set found to true and look for caller into class
found = true;
}
else if (found && !match) {
//We are looking at the callers of Clazz
stack.append(method);
entries--;
if (entries == 0) return stack.toString();
stack.append("\n");
}
//start parsing from start of line again
state = 1;
}
}
}
return "";
}
}
......@@ -97,6 +97,9 @@
String filename = log + ".log";
File logFile = new File(logDir, filename);
String lines[] = new String[0];
int start = 0;
try {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(logFile), "UTF-8"));
String line;
int totalNumLines = 0;
......@@ -108,10 +111,10 @@
if ("All".equals(numLinesParam)) {
numLines = totalNumLines;
}
String[] lines = new String[numLines];
lines = new String[numLines];
in = new BufferedReader(new InputStreamReader(new FileInputStream(logFile), "UTF-8"));
// skip lines
int start = totalNumLines - numLines;
start = totalNumLines - numLines;
if (start < 0) { start = 0; }
for (int i=0; i<start; i++) {
in.readLine();
......@@ -137,6 +140,9 @@
}
}
numLines = start + i;
} catch (FileNotFoundException ex) {
Log.info("Could not open (log)file.", ex);
}
%>
<html>
......
......@@ -134,7 +134,6 @@
if (log != null) {
log = StringUtils.escapeHTMLTags(log);
}
debugEnabled = Log.isDebugEnabled();
User pageUser = admin.getUser();
......@@ -286,6 +285,7 @@ IFRAME {
</tr>
</tbody>
</table>
</div>
<% ByteFormat byteFormatter = new ByteFormat();
Date lastMod = new Date(logFile.lastModified());
......@@ -324,11 +324,11 @@ IFRAME {
<% for (String aLINES : LINES) {
String selected = (aLINES.equals(numLinesParam)) ? " selected" : "";
%>
<option value="<%= aLINES %>"<%= selected %>><%= aLINES %>
<option value="<%= aLINES %>"<%= selected %>><%= aLINES %></option>
<% } %>
<option value="All"<%= (("All".equals(numLinesParam))?" selected":"") %>
><fmt:message key="logviewer.all" />
><fmt:message key="logviewer.all" /></option>
</select>
</td>
</tr>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment