Log4J source files uit trunk gehaald en vervangen door jar.

This commit is contained in:
2011-06-03 15:56:41 +00:00
parent 3f1d3af63c
commit 91770c9312
224 changed files with 0 additions and 43527 deletions

BIN
java/lib/log4j-1.2.16.jar Normal file

Binary file not shown.

View File

@@ -1,142 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.LoggingEvent;
/**
Implement this interface for your own strategies for outputting log
statements.
@author Ceki Gülcü
*/
public interface Appender {
/**
Add a filter to the end of the filter list.
@since 0.9.0
*/
void addFilter(Filter newFilter);
/**
Returns the head Filter. The Filters are organized in a linked list
and so all Filters on this Appender are available through the result.
@return the head Filter or null, if no Filters are present
@since 1.1
*/
public
Filter getFilter();
/**
Clear the list of filters by removing all the filters in it.
@since 0.9.0
*/
public
void clearFilters();
/**
Release any resources allocated within the appender such as file
handles, network connections, etc.
<p>It is a programming error to append to a closed appender.
@since 0.8.4
*/
public
void close();
/**
Log in <code>Appender</code> specific way. When appropriate,
Loggers will call the <code>doAppend</code> method of appender
implementations in order to log. */
public
void doAppend(LoggingEvent event);
/**
Get the name of this appender.
@return name, may be null.*/
public
String getName();
/**
Set the {@link ErrorHandler} for this appender.
@since 0.9.0
*/
public
void setErrorHandler(ErrorHandler errorHandler);
/**
Returns the {@link ErrorHandler} for this appender.
@since 1.1
*/
public
ErrorHandler getErrorHandler();
/**
Set the {@link Layout} for this appender.
@since 0.8.1
*/
public
void setLayout(Layout layout);
/**
Returns this appenders layout.
@since 1.1
*/
public
Layout getLayout();
/**
Set the name of this appender. The name is used by other
components to identify this appender.
@since 0.8.1
*/
public
void setName(String name);
/**
Configurators call this method to determine if the appender
requires a layout. If this method returns <code>true</code>,
meaning that layout is required, then the configurator will
configure an layout using the configuration information at its
disposal. If this method returns <code>false</code>, meaning that
a layout is not required, then layout configuration will be
skipped even if there is available layout configuration
information at the disposal of the configurator..
<p>In the rather exceptional case, where the appender
implementation admits a layout but can also work without it, then
the appender should return <code>true</code>.
@since 0.8.4 */
public
boolean requiresLayout();
}

View File

@@ -1,304 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.OptionHandler;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.OnlyOnceErrorHandler;
import org.apache.log4j.helpers.LogLog;
/**
* Abstract superclass of the other appenders in the package.
*
* This class provides the code for common functionality, such as
* support for threshold filtering and support for general filters.
*
* @since 0.8.1
* @author Ceki G&uuml;lc&uuml;
* */
public abstract class AppenderSkeleton implements Appender, OptionHandler {
/** The layout variable does not need to be set if the appender
implementation has its own layout. */
protected Layout layout;
/** Appenders are named. */
protected String name;
/**
There is no level threshold filtering by default. */
protected Priority threshold;
/**
It is assumed and enforced that errorHandler is never null.
*/
protected ErrorHandler errorHandler = new OnlyOnceErrorHandler();
/** The first filter in the filter chain. Set to <code>null</code>
initially. */
protected Filter headFilter;
/** The last filter in the filter chain. */
protected Filter tailFilter;
/**
Is this appender closed?
*/
protected boolean closed = false;
/**
* Create new instance.
*/
public AppenderSkeleton() {
super();
}
/**
* Create new instance.
* Provided for compatibility with log4j 1.3.
*
* @param isActive true if appender is ready for use upon construction.
* Not used in log4j 1.2.x.
* @since 1.2.15
*/
protected AppenderSkeleton(final boolean isActive) {
super();
}
/**
Derived appenders should override this method if option structure
requires it. */
public
void activateOptions() {
}
/**
Add a filter to end of the filter list.
@since 0.9.0
*/
public
void addFilter(Filter newFilter) {
if(headFilter == null) {
headFilter = tailFilter = newFilter;
} else {
tailFilter.setNext(newFilter);
tailFilter = newFilter;
}
}
/**
Subclasses of <code>AppenderSkeleton</code> should implement this
method to perform actual logging. See also {@link #doAppend
AppenderSkeleton.doAppend} method.
@since 0.9.0
*/
abstract
protected
void append(LoggingEvent event);
/**
Clear the filters chain.
@since 0.9.0 */
public
void clearFilters() {
headFilter = tailFilter = null;
}
/**
Finalize this appender by calling the derived class'
<code>close</code> method.
@since 0.8.4 */
public
void finalize() {
// An appender might be closed then garbage collected. There is no
// point in closing twice.
if(this.closed)
return;
LogLog.debug("Finalizing appender named ["+name+"].");
close();
}
/**
Return the currently set {@link ErrorHandler} for this
Appender.
@since 0.9.0 */
public
ErrorHandler getErrorHandler() {
return this.errorHandler;
}
/**
Returns the head Filter.
@since 1.1
*/
public
Filter getFilter() {
return headFilter;
}
/**
Return the first filter in the filter chain for this
Appender. The return value may be <code>null</code> if no is
filter is set.
*/
public
final
Filter getFirstFilter() {
return headFilter;
}
/**
Returns the layout of this appender. The value may be null.
*/
public
Layout getLayout() {
return layout;
}
/**
Returns the name of this appender.
@return name, may be null.
*/
public
final
String getName() {
return this.name;
}
/**
Returns this appenders threshold level. See the {@link
#setThreshold} method for the meaning of this option.
@since 1.1 */
public
Priority getThreshold() {
return threshold;
}
/**
Check whether the message level is below the appender's
threshold. If there is no threshold set, then the return value is
always <code>true</code>.
*/
public
boolean isAsSevereAsThreshold(Priority priority) {
return ((threshold == null) || priority.isGreaterOrEqual(threshold));
}
/**
* This method performs threshold checks and invokes filters before
* delegating actual logging to the subclasses specific {@link
* AppenderSkeleton#append} method.
* */
public
synchronized
void doAppend(LoggingEvent event) {
if(closed) {
LogLog.error("Attempted to append to closed appender named ["+name+"].");
return;
}
if(!isAsSevereAsThreshold(event.getLevel())) {
return;
}
Filter f = this.headFilter;
FILTER_LOOP:
while(f != null) {
switch(f.decide(event)) {
case Filter.DENY: return;
case Filter.ACCEPT: break FILTER_LOOP;
case Filter.NEUTRAL: f = f.getNext();
}
}
this.append(event);
}
/**
Set the {@link ErrorHandler} for this Appender.
@since 0.9.0
*/
public
synchronized
void setErrorHandler(ErrorHandler eh) {
if(eh == null) {
// We do not throw exception here since the cause is probably a
// bad config file.
LogLog.warn("You have tried to set a null error-handler.");
} else {
this.errorHandler = eh;
}
}
/**
Set the layout for this appender. Note that some appenders have
their own (fixed) layouts or do not use one. For example, the
{@link org.apache.log4j.net.SocketAppender} ignores the layout set
here.
*/
public
void setLayout(Layout layout) {
this.layout = layout;
}
/**
Set the name of this Appender.
*/
public
void setName(String name) {
this.name = name;
}
/**
Set the threshold level. All log events with lower level
than the threshold level are ignored by the appender.
<p>In configuration files this option is specified by setting the
value of the <b>Threshold</b> option to a level
string, such as "DEBUG", "INFO" and so on.
@since 0.8.3 */
public
void setThreshold(Priority threshold) {
this.threshold = threshold;
}
}

View File

@@ -1,596 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contibutors: Aaron Greenhouse <aarong@cs.cmu.edu>
// Thomas Tuft Muller <ttm@online.no>
package org.apache.log4j;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.helpers.AppenderAttachableImpl;
import org.apache.log4j.spi.AppenderAttachable;
import org.apache.log4j.spi.LoggingEvent;
/**
* The AsyncAppender lets users log events asynchronously.
* <p/>
* <p/>
* The AsyncAppender will collect the events sent to it and then dispatch them
* to all the appenders that are attached to it. You can attach multiple
* appenders to an AsyncAppender.
* </p>
* <p/>
* <p/>
* The AsyncAppender uses a separate thread to serve the events in its buffer.
* </p>
* <p/>
* <b>Important note:</b> The <code>AsyncAppender</code> can only be script
* configured using the {@link org.apache.log4j.xml.DOMConfigurator}.
* </p>
*
* @author Ceki G&uuml;lc&uuml;
* @author Curt Arnold
* @since 0.9.1
*/
public class AsyncAppender extends AppenderSkeleton
implements AppenderAttachable {
/**
* The default buffer size is set to 128 events.
*/
public static final int DEFAULT_BUFFER_SIZE = 128;
/**
* Event buffer, also used as monitor to protect itself and
* discardMap from simulatenous modifications.
*/
private final List buffer = new ArrayList();
/**
* Map of DiscardSummary objects keyed by logger name.
*/
private final Map discardMap = new HashMap();
/**
* Buffer size.
*/
private int bufferSize = DEFAULT_BUFFER_SIZE;
/** Nested appenders. */
AppenderAttachableImpl aai;
/**
* Nested appenders.
*/
private final AppenderAttachableImpl appenders;
/**
* Dispatcher.
*/
private final Thread dispatcher;
/**
* Should location info be included in dispatched messages.
*/
private boolean locationInfo = false;
/**
* Does appender block when buffer is full.
*/
private boolean blocking = true;
/**
* Create new instance.
*/
public AsyncAppender() {
appenders = new AppenderAttachableImpl();
//
// only set for compatibility
aai = appenders;
dispatcher =
new Thread(new Dispatcher(this, buffer, discardMap, appenders));
// It is the user's responsibility to close appenders before
// exiting.
dispatcher.setDaemon(true);
// set the dispatcher priority to lowest possible value
// dispatcher.setPriority(Thread.MIN_PRIORITY);
dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName());
dispatcher.start();
}
/**
* Add appender.
*
* @param newAppender appender to add, may not be null.
*/
public void addAppender(final Appender newAppender) {
synchronized (appenders) {
appenders.addAppender(newAppender);
}
}
/**
* {@inheritDoc}
*/
public void append(final LoggingEvent event) {
//
// if dispatcher thread has died then
// append subsequent events synchronously
// See bug 23021
if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
synchronized (appenders) {
appenders.appendLoopOnAppenders(event);
}
return;
}
// Set the NDC and thread name for the calling thread as these
// LoggingEvent fields were not set at event creation time.
event.getNDC();
event.getThreadName();
// Get a copy of this thread's MDC.
event.getMDCCopy();
if (locationInfo) {
event.getLocationInformation();
}
event.getRenderedMessage();
event.getThrowableStrRep();
synchronized (buffer) {
while (true) {
int previousSize = buffer.size();
if (previousSize < bufferSize) {
buffer.add(event);
//
// if buffer had been empty
// signal all threads waiting on buffer
// to check their conditions.
//
if (previousSize == 0) {
buffer.notifyAll();
}
break;
}
//
// Following code is only reachable if buffer is full
//
//
// if blocking and thread is not already interrupted
// and not the dispatcher then
// wait for a buffer notification
boolean discard = true;
if (blocking
&& !Thread.interrupted()
&& Thread.currentThread() != dispatcher) {
try {
buffer.wait();
discard = false;
} catch (InterruptedException e) {
//
// reset interrupt status so
// calling code can see interrupt on
// their next wait or sleep.
Thread.currentThread().interrupt();
}
}
//
// if blocking is false or thread has been interrupted
// add event to discard map.
//
if (discard) {
String loggerName = event.getLoggerName();
DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);
if (summary == null) {
summary = new DiscardSummary(event);
discardMap.put(loggerName, summary);
} else {
summary.add(event);
}
break;
}
}
}
}
/**
* Close this <code>AsyncAppender</code> by interrupting the dispatcher
* thread which will process all pending events before exiting.
*/
public void close() {
/**
* Set closed flag and notify all threads to check their conditions.
* Should result in dispatcher terminating.
*/
synchronized (buffer) {
closed = true;
buffer.notifyAll();
}
try {
dispatcher.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
org.apache.log4j.helpers.LogLog.error(
"Got an InterruptedException while waiting for the "
+ "dispatcher to finish.", e);
}
//
// close all attached appenders.
//
synchronized (appenders) {
Enumeration iter = appenders.getAllAppenders();
if (iter != null) {
while (iter.hasMoreElements()) {
Object next = iter.nextElement();
if (next instanceof Appender) {
((Appender) next).close();
}
}
}
}
}
/**
* Get iterator over attached appenders.
* @return iterator or null if no attached appenders.
*/
public Enumeration getAllAppenders() {
synchronized (appenders) {
return appenders.getAllAppenders();
}
}
/**
* Get appender by name.
*
* @param name name, may not be null.
* @return matching appender or null.
*/
public Appender getAppender(final String name) {
synchronized (appenders) {
return appenders.getAppender(name);
}
}
/**
* Gets whether the location of the logging request call
* should be captured.
*
* @return the current value of the <b>LocationInfo</b> option.
*/
public boolean getLocationInfo() {
return locationInfo;
}
/**
* Determines if specified appender is attached.
* @param appender appender.
* @return true if attached.
*/
public boolean isAttached(final Appender appender) {
synchronized (appenders) {
return appenders.isAttached(appender);
}
}
/**
* {@inheritDoc}
*/
public boolean requiresLayout() {
return false;
}
/**
* Removes and closes all attached appenders.
*/
public void removeAllAppenders() {
synchronized (appenders) {
appenders.removeAllAppenders();
}
}
/**
* Removes an appender.
* @param appender appender to remove.
*/
public void removeAppender(final Appender appender) {
synchronized (appenders) {
appenders.removeAppender(appender);
}
}
/**
* Remove appender by name.
* @param name name.
*/
public void removeAppender(final String name) {
synchronized (appenders) {
appenders.removeAppender(name);
}
}
/**
* The <b>LocationInfo</b> option takes a boolean value. By default, it is
* set to false which means there will be no effort to extract the location
* information related to the event. As a result, the event that will be
* ultimately logged will likely to contain the wrong location information
* (if present in the log format).
* <p/>
* <p/>
* Location information extraction is comparatively very slow and should be
* avoided unless performance is not a concern.
* </p>
* @param flag true if location information should be extracted.
*/
public void setLocationInfo(final boolean flag) {
locationInfo = flag;
}
/**
* Sets the number of messages allowed in the event buffer
* before the calling thread is blocked (if blocking is true)
* or until messages are summarized and discarded. Changing
* the size will not affect messages already in the buffer.
*
* @param size buffer size, must be positive.
*/
public void setBufferSize(final int size) {
//
// log4j 1.2 would throw exception if size was negative
// and deadlock if size was zero.
//
if (size < 0) {
throw new java.lang.NegativeArraySizeException("size");
}
synchronized (buffer) {
//
// don't let size be zero.
//
bufferSize = (size < 1) ? 1 : size;
buffer.notifyAll();
}
}
/**
* Gets the current buffer size.
* @return the current value of the <b>BufferSize</b> option.
*/
public int getBufferSize() {
return bufferSize;
}
/**
* Sets whether appender should wait if there is no
* space available in the event buffer or immediately return.
*
* @since 1.2.14
* @param value true if appender should wait until available space in buffer.
*/
public void setBlocking(final boolean value) {
synchronized (buffer) {
blocking = value;
buffer.notifyAll();
}
}
/**
* Gets whether appender should block calling thread when buffer is full.
* If false, messages will be counted by logger and a summary
* message appended after the contents of the buffer have been appended.
*
* @since 1.2.14
* @return true if calling thread will be blocked when buffer is full.
*/
public boolean getBlocking() {
return blocking;
}
/**
* Summary of discarded logging events for a logger.
*/
private static final class DiscardSummary {
/**
* First event of the highest severity.
*/
private LoggingEvent maxEvent;
/**
* Total count of messages discarded.
*/
private int count;
/**
* Create new instance.
*
* @param event event, may not be null.
*/
public DiscardSummary(final LoggingEvent event) {
maxEvent = event;
count = 1;
}
/**
* Add discarded event to summary.
*
* @param event event, may not be null.
*/
public void add(final LoggingEvent event) {
if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) {
maxEvent = event;
}
count++;
}
/**
* Create event with summary information.
*
* @return new event.
*/
public LoggingEvent createEvent() {
String msg =
MessageFormat.format(
"Discarded {0} messages due to full event buffer including: {1}",
new Object[] { new Integer(count), maxEvent.getMessage() });
return new LoggingEvent(
"org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION",
Logger.getLogger(maxEvent.getLoggerName()),
maxEvent.getLevel(),
msg,
null);
}
}
/**
* Event dispatcher.
*/
private static class Dispatcher implements Runnable {
/**
* Parent AsyncAppender.
*/
private final AsyncAppender parent;
/**
* Event buffer.
*/
private final List buffer;
/**
* Map of DiscardSummary keyed by logger name.
*/
private final Map discardMap;
/**
* Wrapped appenders.
*/
private final AppenderAttachableImpl appenders;
/**
* Create new instance of dispatcher.
*
* @param parent parent AsyncAppender, may not be null.
* @param buffer event buffer, may not be null.
* @param discardMap discard map, may not be null.
* @param appenders appenders, may not be null.
*/
public Dispatcher(
final AsyncAppender parent, final List buffer, final Map discardMap,
final AppenderAttachableImpl appenders) {
this.parent = parent;
this.buffer = buffer;
this.appenders = appenders;
this.discardMap = discardMap;
}
/**
* {@inheritDoc}
*/
public void run() {
boolean isActive = true;
//
// if interrupted (unlikely), end thread
//
try {
//
// loop until the AsyncAppender is closed.
//
while (isActive) {
LoggingEvent[] events = null;
//
// extract pending events while synchronized
// on buffer
//
synchronized (buffer) {
int bufferSize = buffer.size();
isActive = !parent.closed;
while ((bufferSize == 0) && isActive) {
buffer.wait();
bufferSize = buffer.size();
isActive = !parent.closed;
}
if (bufferSize > 0) {
events = new LoggingEvent[bufferSize + discardMap.size()];
buffer.toArray(events);
//
// add events due to buffer overflow
//
int index = bufferSize;
for (
Iterator iter = discardMap.values().iterator();
iter.hasNext();) {
events[index++] = ((DiscardSummary) iter.next()).createEvent();
}
//
// clear buffer and discard map
//
buffer.clear();
discardMap.clear();
//
// allow blocked appends to continue
buffer.notifyAll();
}
}
//
// process events after lock on buffer is released.
//
if (events != null) {
for (int i = 0; i < events.length; i++) {
synchronized (appenders) {
appenders.appendLoopOnAppenders(events[i]);
}
}
}
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}

View File

@@ -1,73 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contibutors: "Luke Blanshard" <Luke@quiq.com>
// "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
// "Muly Oved" <mulyoved@hotmail.com>
package org.apache.log4j;
/**
Use this class to quickly configure the package.
<p>For file based configuration see {@link
PropertyConfigurator}. For XML based configuration see {@link
org.apache.log4j.xml.DOMConfigurator DOMConfigurator}.
@since 0.8.1
@author Ceki G&uuml;lc&uuml; */
public class BasicConfigurator {
protected BasicConfigurator() {
}
/**
Add a {@link ConsoleAppender} that uses {@link PatternLayout}
using the {@link PatternLayout#TTCC_CONVERSION_PATTERN} and
prints to <code>System.out</code> to the root category. */
static
public
void configure() {
Logger root = Logger.getRootLogger();
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
}
/**
Add <code>appender</code> to the root category.
@param appender The appender to add to the root category.
*/
static
public
void configure(Appender appender) {
Logger root = Logger.getRootLogger();
root.addAppender(appender);
}
/**
Reset the default hierarchy to its defaut. It is equivalent to
calling
<code>Category.getDefaultHierarchy().resetConfiguration()</code>.
See {@link Hierarchy#resetConfiguration()} for more details. */
public
static
void resetConfiguration() {
LogManager.resetConfiguration();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
/**
CategoryKey is a wrapper for String that apparently accellerated
hash table lookup in early JVM's.
@author Ceki G&uuml;lc&uuml;
*/
class CategoryKey {
String name;
int hashCache;
CategoryKey(String name) {
this.name = name;
hashCache = name.hashCode();
}
final
public
int hashCode() {
return hashCache;
}
final
public
boolean equals(Object rArg) {
if(this == rArg)
return true;
if(rArg != null && CategoryKey.class == rArg.getClass())
return name.equals(((CategoryKey)rArg ).name);
else
return false;
}
}

View File

@@ -1,220 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.log4j.helpers.LogLog;
/**
* ConsoleAppender appends log events to <code>System.out</code> or
* <code>System.err</code> using a layout specified by the user. The
* default target is <code>System.out</code>.
*
* @author Ceki G&uuml;lc&uuml;
* @author Curt Arnold
* @since 1.1 */
public class ConsoleAppender extends WriterAppender {
public static final String SYSTEM_OUT = "System.out";
public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT;
/**
* Determines if the appender honors reassignments of System.out
* or System.err made after configuration.
*/
private boolean follow = false;
/**
* Constructs an unconfigured appender.
*/
public ConsoleAppender() {
}
/**
* Creates a configured appender.
*
* @param layout layout, may not be null.
*/
public ConsoleAppender(Layout layout) {
this(layout, SYSTEM_OUT);
}
/**
* Creates a configured appender.
* @param layout layout, may not be null.
* @param target target, either "System.err" or "System.out".
*/
public ConsoleAppender(Layout layout, String target) {
setLayout(layout);
setTarget(target);
activateOptions();
}
/**
* Sets the value of the <b>Target</b> option. Recognized values
* are "System.out" and "System.err". Any other value will be
* ignored.
* */
public
void setTarget(String value) {
String v = value.trim();
if (SYSTEM_OUT.equalsIgnoreCase(v)) {
target = SYSTEM_OUT;
} else if (SYSTEM_ERR.equalsIgnoreCase(v)) {
target = SYSTEM_ERR;
} else {
targetWarn(value);
}
}
/**
* Returns the current value of the <b>Target</b> property. The
* default value of the option is "System.out".
*
* See also {@link #setTarget}.
* */
public
String getTarget() {
return target;
}
/**
* Sets whether the appender honors reassignments of System.out
* or System.err made after configuration.
* @param newValue if true, appender will use value of System.out or
* System.err in force at the time when logging events are appended.
* @since 1.2.13
*/
public final void setFollow(final boolean newValue) {
follow = newValue;
}
/**
* Gets whether the appender honors reassignments of System.out
* or System.err made after configuration.
* @return true if appender will use value of System.out or
* System.err in force at the time when logging events are appended.
* @since 1.2.13
*/
public final boolean getFollow() {
return follow;
}
void targetWarn(String val) {
LogLog.warn("["+val+"] should be System.out or System.err.");
LogLog.warn("Using previously set target, System.out by default.");
}
/**
* Prepares the appender for use.
*/
public void activateOptions() {
if (follow) {
if (target.equals(SYSTEM_ERR)) {
setWriter(createWriter(new SystemErrStream()));
} else {
setWriter(createWriter(new SystemOutStream()));
}
} else {
if (target.equals(SYSTEM_ERR)) {
setWriter(createWriter(System.err));
} else {
setWriter(createWriter(System.out));
}
}
super.activateOptions();
}
/**
* {@inheritDoc}
*/
protected
final
void closeWriter() {
if (follow) {
super.closeWriter();
}
}
/**
* An implementation of OutputStream that redirects to the
* current System.err.
*
*/
private static class SystemErrStream extends OutputStream {
public SystemErrStream() {
}
public void close() {
}
public void flush() {
System.err.flush();
}
public void write(final byte[] b) throws IOException {
System.err.write(b);
}
public void write(final byte[] b, final int off, final int len)
throws IOException {
System.err.write(b, off, len);
}
public void write(final int b) throws IOException {
System.err.write(b);
}
}
/**
* An implementation of OutputStream that redirects to the
* current System.out.
*
*/
private static class SystemOutStream extends OutputStream {
public SystemOutStream() {
}
public void close() {
}
public void flush() {
System.out.flush();
}
public void write(final byte[] b) throws IOException {
System.out.write(b);
}
public void write(final byte[] b, final int off, final int len)
throws IOException {
System.out.write(b, off, len);
}
public void write(final int b) throws IOException {
System.out.write(b);
}
}
}

View File

@@ -1,454 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.IOException;
import java.io.File;
import java.io.InterruptedIOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.Locale;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
/**
DailyRollingFileAppender extends {@link FileAppender} so that the
underlying file is rolled over at a user chosen frequency.
DailyRollingFileAppender has been observed to exhibit
synchronization issues and data loss. The log4j extras
companion includes alternatives which should be considered
for new deployments and which are discussed in the documentation
for org.apache.log4j.rolling.RollingFileAppender.
<p>The rolling schedule is specified by the <b>DatePattern</b>
option. This pattern should follow the {@link SimpleDateFormat}
conventions. In particular, you <em>must</em> escape literal text
within a pair of single quotes. A formatted version of the date
pattern is used as the suffix for the rolled file name.
<p>For example, if the <b>File</b> option is set to
<code>/foo/bar.log</code> and the <b>DatePattern</b> set to
<code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging
file <code>/foo/bar.log</code> will be copied to
<code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17
will continue in <code>/foo/bar.log</code> until it rolls over
the next day.
<p>Is is possible to specify monthly, weekly, half-daily, daily,
hourly, or minutely rollover schedules.
<p><table border="1" cellpadding="2">
<tr>
<th>DatePattern</th>
<th>Rollover schedule</th>
<th>Example</th>
<tr>
<td><code>'.'yyyy-MM</code>
<td>Rollover at the beginning of each month</td>
<td>At midnight of May 31st, 2002 <code>/foo/bar.log</code> will be
copied to <code>/foo/bar.log.2002-05</code>. Logging for the month
of June will be output to <code>/foo/bar.log</code> until it is
also rolled over the next month.
<tr>
<td><code>'.'yyyy-ww</code>
<td>Rollover at the first day of each week. The first day of the
week depends on the locale.</td>
<td>Assuming the first day of the week is Sunday, on Saturday
midnight, June 9th 2002, the file <i>/foo/bar.log</i> will be
copied to <i>/foo/bar.log.2002-23</i>. Logging for the 24th week
of 2002 will be output to <code>/foo/bar.log</code> until it is
rolled over the next week.
<tr>
<td><code>'.'yyyy-MM-dd</code>
<td>Rollover at midnight each day.</td>
<td>At midnight, on March 8th, 2002, <code>/foo/bar.log</code> will
be copied to <code>/foo/bar.log.2002-03-08</code>. Logging for the
9th day of March will be output to <code>/foo/bar.log</code> until
it is rolled over the next day.
<tr>
<td><code>'.'yyyy-MM-dd-a</code>
<td>Rollover at midnight and midday of each day.</td>
<td>At noon, on March 9th, 2002, <code>/foo/bar.log</code> will be
copied to <code>/foo/bar.log.2002-03-09-AM</code>. Logging for the
afternoon of the 9th will be output to <code>/foo/bar.log</code>
until it is rolled over at midnight.
<tr>
<td><code>'.'yyyy-MM-dd-HH</code>
<td>Rollover at the top of every hour.</td>
<td>At approximately 11:00.000 o'clock on March 9th, 2002,
<code>/foo/bar.log</code> will be copied to
<code>/foo/bar.log.2002-03-09-10</code>. Logging for the 11th hour
of the 9th of March will be output to <code>/foo/bar.log</code>
until it is rolled over at the beginning of the next hour.
<tr>
<td><code>'.'yyyy-MM-dd-HH-mm</code>
<td>Rollover at the beginning of every minute.</td>
<td>At approximately 11:23,000, on March 9th, 2001,
<code>/foo/bar.log</code> will be copied to
<code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minute
of 11:23 (9th of March) will be output to
<code>/foo/bar.log</code> until it is rolled over the next minute.
</table>
<p>Do not use the colon ":" character in anywhere in the
<b>DatePattern</b> option. The text before the colon is interpeted
as the protocol specificaion of a URL which is probably not what
you want.
@author Eirik Lygre
@author Ceki G&uuml;lc&uuml;*/
public class DailyRollingFileAppender extends FileAppender {
// The code assumes that the following constants are in a increasing
// sequence.
static final int TOP_OF_TROUBLE=-1;
static final int TOP_OF_MINUTE = 0;
static final int TOP_OF_HOUR = 1;
static final int HALF_DAY = 2;
static final int TOP_OF_DAY = 3;
static final int TOP_OF_WEEK = 4;
static final int TOP_OF_MONTH = 5;
/**
The date pattern. By default, the pattern is set to
"'.'yyyy-MM-dd" meaning daily rollover.
*/
private String datePattern = "'.'yyyy-MM-dd";
/**
The log file will be renamed to the value of the
scheduledFilename variable when the next interval is entered. For
example, if the rollover period is one hour, the log file will be
renamed to the value of "scheduledFilename" at the beginning of
the next hour.
The precise time when a rollover occurs depends on logging
activity.
*/
private String scheduledFilename;
/**
The next time we estimate a rollover should occur. */
private long nextCheck = System.currentTimeMillis () - 1;
Date now = new Date();
SimpleDateFormat sdf;
RollingCalendar rc = new RollingCalendar();
int checkPeriod = TOP_OF_TROUBLE;
// The gmtTimeZone is used only in computeCheckPeriod() method.
static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
/**
The default constructor does nothing. */
public DailyRollingFileAppender() {
}
/**
Instantiate a <code>DailyRollingFileAppender</code> and open the
file designated by <code>filename</code>. The opened filename will
become the ouput destination for this appender.
*/
public DailyRollingFileAppender (Layout layout, String filename,
String datePattern) throws IOException {
super(layout, filename, true);
this.datePattern = datePattern;
activateOptions();
}
/**
The <b>DatePattern</b> takes a string in the same format as
expected by {@link SimpleDateFormat}. This options determines the
rollover schedule.
*/
public void setDatePattern(String pattern) {
datePattern = pattern;
}
/** Returns the value of the <b>DatePattern</b> option. */
public String getDatePattern() {
return datePattern;
}
public void activateOptions() {
super.activateOptions();
if(datePattern != null && fileName != null) {
now.setTime(System.currentTimeMillis());
sdf = new SimpleDateFormat(datePattern);
int type = computeCheckPeriod();
printPeriodicity(type);
rc.setType(type);
File file = new File(fileName);
scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
} else {
LogLog.error("Either File or DatePattern options are not set for appender ["
+name+"].");
}
}
void printPeriodicity(int type) {
switch(type) {
case TOP_OF_MINUTE:
LogLog.debug("Appender ["+name+"] to be rolled every minute.");
break;
case TOP_OF_HOUR:
LogLog.debug("Appender ["+name
+"] to be rolled on top of every hour.");
break;
case HALF_DAY:
LogLog.debug("Appender ["+name
+"] to be rolled at midday and midnight.");
break;
case TOP_OF_DAY:
LogLog.debug("Appender ["+name
+"] to be rolled at midnight.");
break;
case TOP_OF_WEEK:
LogLog.debug("Appender ["+name
+"] to be rolled at start of week.");
break;
case TOP_OF_MONTH:
LogLog.debug("Appender ["+name
+"] to be rolled at start of every month.");
break;
default:
LogLog.warn("Unknown periodicity for appender ["+name+"].");
}
}
// This method computes the roll over period by looping over the
// periods, starting with the shortest, and stopping when the r0 is
// different from from r1, where r0 is the epoch formatted according
// the datePattern (supplied by the user) and r1 is the
// epoch+nextMillis(i) formatted according to datePattern. All date
// formatting is done in GMT and not local format because the test
// logic is based on comparisons relative to 1970-01-01 00:00:00
// GMT (the epoch).
int computeCheckPeriod() {
RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
// set sate to 1970-01-01 00:00:00 GMT
Date epoch = new Date(0);
if(datePattern != null) {
for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
String r0 = simpleDateFormat.format(epoch);
rollingCalendar.setType(i);
Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
String r1 = simpleDateFormat.format(next);
//System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
if(r0 != null && r1 != null && !r0.equals(r1)) {
return i;
}
}
}
return TOP_OF_TROUBLE; // Deliberately head for trouble...
}
/**
Rollover the current file to a new file.
*/
void rollOver() throws IOException {
/* Compute filename, but only if datePattern is specified */
if (datePattern == null) {
errorHandler.error("Missing DatePattern option in rollOver().");
return;
}
String datedFilename = fileName+sdf.format(now);
// It is too early to roll over because we are still within the
// bounds of the current interval. Rollover will occur once the
// next interval is reached.
if (scheduledFilename.equals(datedFilename)) {
return;
}
// close current file, and rename it to datedFilename
this.closeFile();
File target = new File(scheduledFilename);
if (target.exists()) {
target.delete();
}
File file = new File(fileName);
boolean result = file.renameTo(target);
if(result) {
LogLog.debug(fileName +" -> "+ scheduledFilename);
} else {
LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
}
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
}
catch(IOException e) {
errorHandler.error("setFile("+fileName+", true) call failed.");
}
scheduledFilename = datedFilename;
}
/**
* This method differentiates DailyRollingFileAppender from its
* super class.
*
* <p>Before actually logging, this method will check whether it is
* time to do a rollover. If it is, it will schedule the next
* rollover time and then rollover.
* */
protected void subAppend(LoggingEvent event) {
long n = System.currentTimeMillis();
if (n >= nextCheck) {
now.setTime(n);
nextCheck = rc.getNextCheckMillis(now);
try {
rollOver();
}
catch(IOException ioe) {
if (ioe instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("rollOver() failed.", ioe);
}
}
super.subAppend(event);
}
}
/**
* RollingCalendar is a helper class to DailyRollingFileAppender.
* Given a periodicity type and the current time, it computes the
* start of the next interval.
* */
class RollingCalendar extends GregorianCalendar {
private static final long serialVersionUID = -3560331770601814177L;
int type = DailyRollingFileAppender.TOP_OF_TROUBLE;
RollingCalendar() {
super();
}
RollingCalendar(TimeZone tz, Locale locale) {
super(tz, locale);
}
void setType(int type) {
this.type = type;
}
public long getNextCheckMillis(Date now) {
return getNextCheckDate(now).getTime();
}
public Date getNextCheckDate(Date now) {
this.setTime(now);
switch(type) {
case DailyRollingFileAppender.TOP_OF_MINUTE:
this.set(Calendar.SECOND, 0);
this.set(Calendar.MILLISECOND, 0);
this.add(Calendar.MINUTE, 1);
break;
case DailyRollingFileAppender.TOP_OF_HOUR:
this.set(Calendar.MINUTE, 0);
this.set(Calendar.SECOND, 0);
this.set(Calendar.MILLISECOND, 0);
this.add(Calendar.HOUR_OF_DAY, 1);
break;
case DailyRollingFileAppender.HALF_DAY:
this.set(Calendar.MINUTE, 0);
this.set(Calendar.SECOND, 0);
this.set(Calendar.MILLISECOND, 0);
int hour = get(Calendar.HOUR_OF_DAY);
if(hour < 12) {
this.set(Calendar.HOUR_OF_DAY, 12);
} else {
this.set(Calendar.HOUR_OF_DAY, 0);
this.add(Calendar.DAY_OF_MONTH, 1);
}
break;
case DailyRollingFileAppender.TOP_OF_DAY:
this.set(Calendar.HOUR_OF_DAY, 0);
this.set(Calendar.MINUTE, 0);
this.set(Calendar.SECOND, 0);
this.set(Calendar.MILLISECOND, 0);
this.add(Calendar.DATE, 1);
break;
case DailyRollingFileAppender.TOP_OF_WEEK:
this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
this.set(Calendar.HOUR_OF_DAY, 0);
this.set(Calendar.MINUTE, 0);
this.set(Calendar.SECOND, 0);
this.set(Calendar.MILLISECOND, 0);
this.add(Calendar.WEEK_OF_YEAR, 1);
break;
case DailyRollingFileAppender.TOP_OF_MONTH:
this.set(Calendar.DATE, 1);
this.set(Calendar.HOUR_OF_DAY, 0);
this.set(Calendar.MINUTE, 0);
this.set(Calendar.SECOND, 0);
this.set(Calendar.MILLISECOND, 0);
this.add(Calendar.MONTH, 1);
break;
default:
throw new IllegalStateException("Unknown periodicity type.");
}
return getTime();
}
}

View File

@@ -1,31 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggerFactory;
class DefaultCategoryFactory implements LoggerFactory {
DefaultCategoryFactory() {
}
public
Logger makeNewLoggerInstance(String name) {
return new Logger(name);
}
}

View File

@@ -1,83 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.ThrowableRenderer;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.ArrayList;
/**
* Default implementation of ThrowableRenderer using
* Throwable.printStackTrace.
*
* @since 1.2.16
*/
public final class DefaultThrowableRenderer implements ThrowableRenderer {
/**
* Construct new instance.
*/
public DefaultThrowableRenderer() {
}
/**
* {@inheritDoc}
*/
public String[] doRender(final Throwable throwable) {
return render(throwable);
}
/**
* Render throwable using Throwable.printStackTrace.
* @param throwable throwable, may not be null.
* @return string representation.
*/
public static String[] render(final Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
throwable.printStackTrace(pw);
} catch(RuntimeException ex) {
}
pw.flush();
LineNumberReader reader = new LineNumberReader(
new StringReader(sw.toString()));
ArrayList lines = new ArrayList();
try {
String line = reader.readLine();
while(line != null) {
lines.add(line);
line = reader.readLine();
}
} catch(IOException ex) {
if (ex instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
lines.add(ex.toString());
}
String[] tempRep = new String[lines.size()];
lines.toArray(tempRep);
return tempRep;
}
}

View File

@@ -1,125 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.helpers.AppenderAttachableImpl;
import org.apache.log4j.spi.LoggingEvent;
/**
* Obsolete AsyncAppender dispatcher provided for compatibility only.
*
* @deprecated Since 1.3.
*/
class Dispatcher extends Thread {
/**
* @deprecated
*/
private org.apache.log4j.helpers.BoundedFIFO bf;
private AppenderAttachableImpl aai;
private boolean interrupted = false;
AsyncAppender container;
/**
*
* @param bf
* @param container
* @deprecated
*/
Dispatcher(org.apache.log4j.helpers.BoundedFIFO bf, AsyncAppender container) {
this.bf = bf;
this.container = container;
this.aai = container.aai;
// It is the user's responsibility to close appenders before
// exiting.
this.setDaemon(true);
// set the dispatcher priority to lowest possible value
this.setPriority(Thread.MIN_PRIORITY);
this.setName("Dispatcher-" + getName());
// set the dispatcher priority to MIN_PRIORITY plus or minus 2
// depending on the direction of MIN to MAX_PRIORITY.
//+ (Thread.MAX_PRIORITY > Thread.MIN_PRIORITY ? 1 : -1)*2);
}
void close() {
synchronized (bf) {
interrupted = true;
// We have a waiting dispacther if and only if bf.length is
// zero. In that case, we need to give it a death kiss.
if (bf.length() == 0) {
bf.notify();
}
}
}
/**
* The dispatching strategy is to wait until there are events in the buffer
* to process. After having processed an event, we release the monitor
* (variable bf) so that new events can be placed in the buffer, instead of
* keeping the monitor and processing the remaining events in the buffer.
*
* <p>
* Other approaches might yield better results.
* </p>
*/
public void run() {
//Category cat = Category.getInstance(Dispatcher.class.getName());
LoggingEvent event;
while (true) {
synchronized (bf) {
if (bf.length() == 0) {
// Exit loop if interrupted but only if the the buffer is empty.
if (interrupted) {
//cat.info("Exiting.");
break;
}
try {
//LogLog.debug("Waiting for new event to dispatch.");
bf.wait();
} catch (InterruptedException e) {
break;
}
}
event = bf.get();
if (bf.wasFull()) {
//LogLog.debug("Notifying AsyncAppender about freed space.");
bf.notify();
}
}
// synchronized
synchronized (container.aai) {
if ((aai != null) && (event != null)) {
aai.appendLoopOnAppenders(event);
}
}
}
// while
// close and remove all appenders
aai.removeAllAppenders();
}
}

View File

@@ -1,559 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.pattern.BridgePatternConverter;
import org.apache.log4j.spi.LoggingEvent;
// Contributors: Nelson Minar <nelson@monkey.org>
// Anders Kristensen <akristensen@dynamicsoft.com>
/**
* This class is an enhanced version of org.apache.log4j.PatternLayout
* which was originally developed as part of the abandoned log4j 1.3
* effort and has been available in the extras companion.
* This pattern layout should be used in preference to
* org.apache.log4j.PatternLayout except when compatibility
* where PatternLayout has been extended either through subclassing
* or alternative pattern parsers.
*
*
* <p>A flexible layout configurable with pattern string. The goal of this class
* is to {@link #format format} a {@link LoggingEvent} and return the results
* in a {@link StringBuffer}. The format of the result depends on the
* <em>conversion pattern</em>.
* <p>
*
* <p>The conversion pattern is closely related to the conversion
* pattern of the printf function in C. A conversion pattern is
* composed of literal text and format control expressions called
* <em>conversion specifiers</em>.
*
* <p><i>Note that you are free to insert any literal text within the
* conversion pattern.</i>
* </p>
<p>Each conversion specifier starts with a percent sign (%) and is
followed by optional <em>format modifiers</em> and a <em>conversion
character</em>. The conversion character specifies the type of
data, e.g. category, priority, date, thread name. The format
modifiers control such things as field width, padding, left and
right justification. The following is a simple example.
<p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
that the log4j environment was set to use a EnhancedPatternLayout. Then the
statements
<pre>
Category root = Category.getRoot();
root.debug("Message 1");
root.warn("Message 2");
</pre>
would yield the output
<pre>
DEBUG [main]: Message 1
WARN [main]: Message 2
</pre>
<p>Note that there is no explicit separator between text and
conversion specifiers. The pattern parser knows when it has reached
the end of a conversion specifier when it reads a conversion
character. In the example above the conversion specifier
<b>%-5p</b> means the priority of the logging event should be left
justified to a width of five characters.
The recognized conversion characters are
<p>
<table border="1" CELLPADDING="8">
<th>Conversion Character</th>
<th>Effect</th>
<tr>
<td align=center><b>c</b></td>
<td>Used to output the category of the logging event. The
category conversion specifier can be optionally followed by
NameAbbreviator pattern.
<p>For example, for the category name "alpha.beta.gamma" the pattern
<b>%c{2}</b> will output the last two elements ("beta.gamma"),
<b>%c{-2}</b> will remove two elements leaving "gamma",
<b>%c{1.}</b> will output "a.b.gamma".
</td>
</tr>
<tr>
<td align=center><b>C</b></td>
<td>Used to output the fully qualified class name of the caller
issuing the logging request. This conversion specifier
can be optionally followed by <em>precision specifier</em>, that
is a decimal constant in brackets.
<td>Used to output the category of the logging event. The
category conversion specifier can be optionally followed by
NameAbbreviator pattern.
<p>For example, for the category name "alpha.beta.gamma" the pattern
<b>%c{2}</b> will output the last two elements ("beta.gamma"),
<b>%c{-2}</b> will remove two elements leaving "gamma",
<b>%c{1.}</b> will output "a.b.gamma".
<p><b>WARNING</b> Generating the caller class information is
slow. Thus, its use should be avoided unless execution speed is
not an issue.
</td>
</tr>
<tr> <td align=center><b>d</b></td> <td>Used to output the date of
the logging event. The date conversion specifier may be
followed by a set of braces containing a
date and time pattern strings {@link java.text.SimpleDateFormat},
<em>ABSOLUTE</em>, <em>DATE</em> or <em>ISO8601</em>
and a set of braces containing a time zone id per
{@link java.util.TimeZone#getTimeZone(String)}.
For example, <b>%d{HH:mm:ss,SSS}</b>,
<b>%d{dd&nbsp;MMM&nbsp;yyyy&nbsp;HH:mm:ss,SSS}</b>,
<b>%d{DATE}</b> or <b>%d{HH:mm:ss}{GMT+0}</b>. If no date format specifier is given then
ISO8601 format is assumed.
</td>
</tr>
<tr>
<td align=center><b>F</b></td>
<td>Used to output the file name where the logging request was
issued.
<p><b>WARNING</b> Generating caller location information is
extremely slow and should be avoided unless execution speed
is not an issue.
</tr>
<tr>
<td align=center><b>l</b></td>
<td>Used to output location information of the caller which generated
the logging event.
<p>The location information depends on the JVM implementation but
usually consists of the fully qualified name of the calling
method followed by the callers source the file name and line
number between parentheses.
<p>The location information can be very useful. However, its
generation is <em>extremely</em> slow and should be avoided
unless execution speed is not an issue.
</td>
</tr>
<tr>
<td align=center><b>L</b></td>
<td>Used to output the line number from where the logging request
was issued.
<p><b>WARNING</b> Generating caller location information is
extremely slow and should be avoided unless execution speed
is not an issue.
</tr>
<tr>
<td align=center><b>m</b></td>
<td>Used to output the application supplied message associated with
the logging event.</td>
</tr>
<tr>
<td align=center><b>M</b></td>
<td>Used to output the method name where the logging request was
issued.
<p><b>WARNING</b> Generating caller location information is
extremely slow and should be avoided unless execution speed
is not an issue.
</tr>
<tr>
<td align=center><b>n</b></td>
<td>Outputs the platform dependent line separator character or
characters.
<p>This conversion character offers practically the same
performance as using non-portable line separator strings such as
"\n", or "\r\n". Thus, it is the preferred way of specifying a
line separator.
</tr>
<tr>
<td align=center><b>p</b></td>
<td>Used to output the priority of the logging event.</td>
</tr>
<tr>
<td align=center><b>r</b></td>
<td>Used to output the number of milliseconds elapsed since the construction
of the layout until the creation of the logging event.</td>
</tr>
<tr>
<td align=center><b>t</b></td>
<td>Used to output the name of the thread that generated the
logging event.</td>
</tr>
<tr>
<td align=center><b>x</b></td>
<td>Used to output the NDC (nested diagnostic context) associated
with the thread that generated the logging event.
</td>
</tr>
<tr>
<td align=center><b>X</b></td>
<td>
<p>Used to output the MDC (mapped diagnostic context) associated
with the thread that generated the logging event. The <b>X</b>
conversion character can be followed by the key for the
map placed between braces, as in <b>%X{clientNumber}</b> where
<code>clientNumber</code> is the key. The value in the MDC
corresponding to the key will be output. If no additional sub-option
is specified, then the entire contents of the MDC key value pair set
is output using a format {{key1,val1},{key2,val2}}</p>
<p>See {@link MDC} class for more details.
</p>
</td>
</tr>
<tr>
<td align=center><b>properties</b></td>
<td>
<p>Used to output the Properties associated
with the logging event. The <b>properties</b>
conversion word can be followed by the key for the
map placed between braces, as in <b>%properties{application}</b> where
<code>application</code> is the key. The value in the Properties bundle
corresponding to the key will be output. If no additional sub-option
is specified, then the entire contents of the Properties key value pair set
is output using a format {{key1,val1},{key2,val2}}</p>
</td>
</tr>
<tr>
<td align=center><b>throwable</b></td>
<td>
<p>Used to output the Throwable trace that has been bound to the LoggingEvent, by
default this will output the full trace as one would normally
find by a call to Throwable.printStackTrace().
<b>%throwable{short}</b> or <b>%throwable{1}</b> will output the first line of
stack trace. <b>throwable{none}</b> or <b>throwable{0}</b> will suppress
the stack trace. <b>%throwable{n}</b> will output n lines of stack trace
if a positive integer or omit the last -n lines if a negative integer.
If no %throwable pattern is specified, the appender will take
responsibility to output the stack trace as it sees fit.</p>
</td>
</tr>
<tr>
<td align=center><b>%</b></td>
<td>The sequence %% outputs a single percent sign.
</td>
</tr>
</table>
<p>By default the relevant information is output as is. However,
with the aid of format modifiers it is possible to change the
minimum field width, the maximum field width and justification.
<p>The optional format modifier is placed between the percent sign
and the conversion character.
<p>The first optional format modifier is the <em>left justification
flag</em> which is just the minus (-) character. Then comes the
optional <em>minimum field width</em> modifier. This is a decimal
constant that represents the minimum number of characters to
output. If the data item requires fewer characters, it is padded on
either the left or the right until the minimum width is
reached. The default is to pad on the left (right justify) but you
can specify right padding with the left justification flag. The
padding character is space. If the data item is larger than the
minimum field width, the field is expanded to accommodate the
data. The value is never truncated.
<p>This behavior can be changed using the <em>maximum field
width</em> modifier which is designated by a period followed by a
decimal constant. If the data item is longer than the maximum
field, then the extra characters are removed from the
<em>beginning</em> of the data item and not from the end. For
example, it the maximum field width is eight and the data item is
ten characters long, then the first two characters of the data item
are dropped. This behavior deviates from the printf function in C
where truncation is done from the end.
<p>Below are various format modifier examples for the category
conversion specifier.
<p>
<TABLE BORDER=1 CELLPADDING=8>
<th>Format modifier
<th>left justify
<th>minimum width
<th>maximum width
<th>comment
<tr>
<td align=center>%20c</td>
<td align=center>false</td>
<td align=center>20</td>
<td align=center>none</td>
<td>Left pad with spaces if the category name is less than 20
characters long.
<tr> <td align=center>%-20c</td> <td align=center>true</td> <td
align=center>20</td> <td align=center>none</td> <td>Right pad with
spaces if the category name is less than 20 characters long.
<tr>
<td align=center>%.30c</td>
<td align=center>NA</td>
<td align=center>none</td>
<td align=center>30</td>
<td>Truncate from the beginning if the category name is longer than 30
characters.
<tr>
<td align=center>%20.30c</td>
<td align=center>false</td>
<td align=center>20</td>
<td align=center>30</td>
<td>Left pad with spaces if the category name is shorter than 20
characters. However, if category name is longer than 30 characters,
then truncate from the beginning.
<tr>
<td align=center>%-20.30c</td>
<td align=center>true</td>
<td align=center>20</td>
<td align=center>30</td>
<td>Right pad with spaces if the category name is shorter than 20
characters. However, if category name is longer than 30 characters,
then truncate from the beginning.
</table>
<p>Below are some examples of conversion patterns.
<dl>
<p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
<p><dd>This is essentially the TTCC layout.
<p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
<p><dd>Similar to the TTCC layout except that the relative time is
right padded if less than 6 digits, thread name is right padded if
less than 15 characters and truncated if longer and the category
name is left padded if shorter than 30 characters and truncated if
longer.
</dl>
<p>The above text is largely inspired from Peter A. Darnell and
Philip E. Margolis' highly recommended book "C -- a Software
Engineering Approach", ISBN 0-387-97389-3.
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
@author Ceki G&uuml;lc&uuml;
@since 1.2.16 */
public class EnhancedPatternLayout extends Layout {
/** Default pattern string for log output. Currently set to the
string <b>"%m%n"</b> which just prints the application supplied
message. */
public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
/** A conversion pattern equivalent to the TTCCCLayout.
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
public static final String TTCC_CONVERSION_PATTERN =
"%r [%t] %p %c %x - %m%n";
/**
* Initial size of internal buffer, no longer used.
* @deprecated since 1.3
*/
protected final int BUF_SIZE = 256;
/**
* Maximum capacity of internal buffer, no longer used.
* @deprecated since 1.3
*/
protected final int MAX_CAPACITY = 1024;
/**
* Customized pattern conversion rules are stored under this key in the
* {@link org.apache.log4j.spi.LoggerRepository LoggerRepository} object store.
*/
public static final String PATTERN_RULE_REGISTRY = "PATTERN_RULE_REGISTRY";
/**
* Initial converter for pattern.
*/
private PatternConverter head;
/**
* Conversion pattern.
*/
private String conversionPattern;
/**
* True if any element in pattern formats information from exceptions.
*/
private boolean handlesExceptions;
/**
Constructs a EnhancedPatternLayout using the DEFAULT_LAYOUT_PATTERN.
The default pattern just produces the application supplied message.
*/
public EnhancedPatternLayout() {
this(DEFAULT_CONVERSION_PATTERN);
}
/**
* Constructs a EnhancedPatternLayout using the supplied conversion pattern.
* @param pattern conversion pattern.
*/
public EnhancedPatternLayout(final String pattern) {
this.conversionPattern = pattern;
head = createPatternParser(
(pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern).parse();
if (head instanceof BridgePatternConverter) {
handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable();
} else {
handlesExceptions = false;
}
}
/**
* Set the <b>ConversionPattern</b> option. This is the string which
* controls formatting and consists of a mix of literal content and
* conversion specifiers.
*
* @param conversionPattern conversion pattern.
*/
public void setConversionPattern(final String conversionPattern) {
this.conversionPattern =
OptionConverter.convertSpecialChars(conversionPattern);
head = createPatternParser(this.conversionPattern).parse();
if (head instanceof BridgePatternConverter) {
handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable();
} else {
handlesExceptions = false;
}
}
/**
* Returns the value of the <b>ConversionPattern</b> option.
* @return conversion pattern.
*/
public String getConversionPattern() {
return conversionPattern;
}
/**
Returns PatternParser used to parse the conversion string. Subclasses
may override this to return a subclass of PatternParser which recognize
custom conversion characters.
@since 0.9.0
*/
protected org.apache.log4j.helpers.PatternParser createPatternParser(String pattern) {
return new org.apache.log4j.pattern.BridgePatternParser(pattern);
}
/**
Activates the conversion pattern. Do not forget to call this method after
you change the parameters of the EnhancedPatternLayout instance.
*/
public void activateOptions() {
// nothing to do.
}
/**
* Formats a logging event to a writer.
* @param event logging event to be formatted.
*/
public String format(final LoggingEvent event) {
StringBuffer buf = new StringBuffer();
for(PatternConverter c = head;
c != null;
c = c.next) {
c.format(buf, event);
}
return buf.toString();
}
/**
* Will return false if any of the conversion specifiers in the pattern
* handles {@link Exception Exceptions}.
* @return true if the pattern formats any information from exceptions.
*/
public boolean ignoresThrowable() {
return !handlesExceptions;
}
}

View File

@@ -1,168 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.ThrowableRenderer;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.CodeSource;
import java.util.HashMap;
import java.util.Map;
/**
* Enhanced implementation of ThrowableRenderer. Uses Throwable.getStackTrace
* if running on JDK 1.4 or later and delegates to DefaultThrowableRenderer.render
* on earlier virtual machines.
*
* @since 1.2.16
*/
public final class EnhancedThrowableRenderer implements ThrowableRenderer {
/**
* Throwable.getStackTrace() method.
*/
private Method getStackTraceMethod;
/**
* StackTraceElement.getClassName() method.
*/
private Method getClassNameMethod;
/**
* Construct new instance.
*/
public EnhancedThrowableRenderer() {
try {
Class[] noArgs = null;
getStackTraceMethod = Throwable.class.getMethod("getStackTrace", noArgs);
Class ste = Class.forName("java.lang.StackTraceElement");
getClassNameMethod = ste.getMethod("getClassName", noArgs);
} catch(Exception ex) {
}
}
/**
* {@inheritDoc}
*/
public String[] doRender(final Throwable throwable) {
if (getStackTraceMethod != null) {
try {
Object[] noArgs = null;
Object[] elements = (Object[]) getStackTraceMethod.invoke(throwable, noArgs);
String[] lines = new String[elements.length + 1];
lines[0] = throwable.toString();
Map classMap = new HashMap();
for(int i = 0; i < elements.length; i++) {
lines[i+1] = formatElement(elements[i], classMap);
}
return lines;
} catch(Exception ex) {
}
}
return DefaultThrowableRenderer.render(throwable);
}
/**
* Format one element from stack trace.
* @param element element, may not be null.
* @param classMap map of class name to location.
* @return string representation of element.
*/
private String formatElement(final Object element, final Map classMap) {
StringBuffer buf = new StringBuffer("\tat ");
buf.append(element);
try {
String className = getClassNameMethod.invoke(element, (Object[]) null).toString();
Object classDetails = classMap.get(className);
if (classDetails != null) {
buf.append(classDetails);
} else {
Class cls = findClass(className);
int detailStart = buf.length();
buf.append('[');
try {
CodeSource source = cls.getProtectionDomain().getCodeSource();
if (source != null) {
URL locationURL = source.getLocation();
if (locationURL != null) {
//
// if a file: URL
//
if ("file".equals(locationURL.getProtocol())) {
String path = locationURL.getPath();
if (path != null) {
//
// find the last file separator character
//
int lastSlash = path.lastIndexOf('/');
int lastBack = path.lastIndexOf(File.separatorChar);
if (lastBack > lastSlash) {
lastSlash = lastBack;
}
//
// if no separator or ends with separator (a directory)
// then output the URL, otherwise just the file name.
//
if (lastSlash <= 0 || lastSlash == path.length() - 1) {
buf.append(locationURL);
} else {
buf.append(path.substring(lastSlash + 1));
}
}
} else {
buf.append(locationURL);
}
}
}
} catch(SecurityException ex) {
}
buf.append(':');
Package pkg = cls.getPackage();
if (pkg != null) {
String implVersion = pkg.getImplementationVersion();
if (implVersion != null) {
buf.append(implVersion);
}
}
buf.append(']');
classMap.put(className, buf.substring(detailStart));
}
} catch(Exception ex) {
}
return buf.toString();
}
/**
* Find class given class name.
* @param className class name, may not be null.
* @return class, will not be null.
* @throws ClassNotFoundException thrown if class can not be found.
*/
private Class findClass(final String className) throws ClassNotFoundException {
try {
return Thread.currentThread().getContextClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e1) {
return getClass().getClassLoader().loadClass(className);
}
}
}
}

View File

@@ -1,348 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.Writer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.spi.ErrorCode;
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
// Ben Sandee
/**
* FileAppender appends log events to a file.
*
* <p>Support for <code>java.io.Writer</code> and console appending
* has been deprecated and then removed. See the replacement
* solutions: {@link WriterAppender} and {@link ConsoleAppender}.
*
* @author Ceki G&uuml;lc&uuml;
* */
public class FileAppender extends WriterAppender {
/** Controls file truncatation. The default value for this variable
* is <code>true</code>, meaning that by default a
* <code>FileAppender</code> will append to an existing file and not
* truncate it.
*
* <p>This option is meaningful only if the FileAppender opens the
* file.
*/
protected boolean fileAppend = true;
/**
The name of the log file. */
protected String fileName = null;
/**
Do we do bufferedIO? */
protected boolean bufferedIO = false;
/**
* Determines the size of IO buffer be. Default is 8K.
*/
protected int bufferSize = 8*1024;
/**
The default constructor does not do anything.
*/
public
FileAppender() {
}
/**
Instantiate a <code>FileAppender</code> and open the file
designated by <code>filename</code>. The opened filename will
become the output destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file designated by
<code>filename</code> will be truncated before being opened.
<p>If the <code>bufferedIO</code> parameter is <code>true</code>,
then buffered IO will be used to write to the output file.
*/
public
FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
int bufferSize) throws IOException {
this.layout = layout;
this.setFile(filename, append, bufferedIO, bufferSize);
}
/**
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file designated by
<code>filename</code> will be truncated before being opened.
*/
public
FileAppender(Layout layout, String filename, boolean append)
throws IOException {
this.layout = layout;
this.setFile(filename, append, false, bufferSize);
}
/**
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>The file will be appended to. */
public
FileAppender(Layout layout, String filename) throws IOException {
this(layout, filename, true);
}
/**
The <b>File</b> property takes a string value which should be the
name of the file to append to.
<p><font color="#DD0044"><b>Note that the special values
"System.out" or "System.err" are no longer honored.</b></font>
<p>Note: Actual opening of the file is made when {@link
#activateOptions} is called, not when the options are set. */
public void setFile(String file) {
// Trim spaces from both ends. The users probably does not want
// trailing spaces in file names.
String val = file.trim();
fileName = val;
}
/**
Returns the value of the <b>Append</b> option.
*/
public
boolean getAppend() {
return fileAppend;
}
/** Returns the value of the <b>File</b> option. */
public
String getFile() {
return fileName;
}
/**
If the value of <b>File</b> is not <code>null</code>, then {@link
#setFile} is called with the values of <b>File</b> and
<b>Append</b> properties.
@since 0.8.1 */
public
void activateOptions() {
if(fileName != null) {
try {
setFile(fileName, fileAppend, bufferedIO, bufferSize);
}
catch(java.io.IOException e) {
errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
e, ErrorCode.FILE_OPEN_FAILURE);
}
} else {
//LogLog.error("File option not set for appender ["+name+"].");
LogLog.warn("File option not set for appender ["+name+"].");
LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
}
}
/**
Closes the previously opened file.
*/
protected
void closeFile() {
if(this.qw != null) {
try {
this.qw.close();
}
catch(java.io.IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
// Exceptionally, it does not make sense to delegate to an
// ErrorHandler. Since a closed appender is basically dead.
LogLog.error("Could not close " + qw, e);
}
}
}
/**
Get the value of the <b>BufferedIO</b> option.
<p>BufferedIO will significatnly increase performance on heavily
loaded systems.
*/
public
boolean getBufferedIO() {
return this.bufferedIO;
}
/**
Get the size of the IO buffer.
*/
public
int getBufferSize() {
return this.bufferSize;
}
/**
The <b>Append</b> option takes a boolean value. It is set to
<code>true</code> by default. If true, then <code>File</code>
will be opened in append mode by {@link #setFile setFile} (see
above). Otherwise, {@link #setFile setFile} will open
<code>File</code> in truncate mode.
<p>Note: Actual opening of the file is made when {@link
#activateOptions} is called, not when the options are set.
*/
public
void setAppend(boolean flag) {
fileAppend = flag;
}
/**
The <b>BufferedIO</b> option takes a boolean value. It is set to
<code>false</code> by default. If true, then <code>File</code>
will be opened and the resulting {@link java.io.Writer} wrapped
around a {@link BufferedWriter}.
BufferedIO will significatnly increase performance on heavily
loaded systems.
*/
public
void setBufferedIO(boolean bufferedIO) {
this.bufferedIO = bufferedIO;
if(bufferedIO) {
immediateFlush = false;
}
}
/**
Set the size of the IO buffer.
*/
public
void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
/**
<p>Sets and <i>opens</i> the file where the log output will
go. The specified file must be writable.
<p>If there was already an opened file, then the previous file
is closed first.
<p><b>Do not use this method directly. To configure a FileAppender
or one of its subclasses, set its properties one by one and then
call activateOptions.</b>
@param fileName The path to the log file.
@param append If true will append to fileName. Otherwise will
truncate fileName. */
public
synchronized
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
throws IOException {
LogLog.debug("setFile called: "+fileName+", "+append);
// It does not make sense to have immediate flush and bufferedIO.
if(bufferedIO) {
setImmediateFlush(false);
}
reset();
FileOutputStream ostream = null;
try {
//
// attempt to create file
//
ostream = new FileOutputStream(fileName, append);
} catch(FileNotFoundException ex) {
//
// if parent directory does not exist then
// attempt to create it and try to create file
// see bug 9150
//
String parentName = new File(fileName).getParent();
if (parentName != null) {
File parentDir = new File(parentName);
if(!parentDir.exists() && parentDir.mkdirs()) {
ostream = new FileOutputStream(fileName, append);
} else {
throw ex;
}
} else {
throw ex;
}
}
Writer fw = createWriter(ostream);
if(bufferedIO) {
fw = new BufferedWriter(fw, bufferSize);
}
this.setQWForFiles(fw);
this.fileName = fileName;
this.fileAppend = append;
this.bufferedIO = bufferedIO;
this.bufferSize = bufferSize;
writeHeader();
LogLog.debug("setFile ended");
}
/**
Sets the quiet writer being used.
This method is overriden by {@link RollingFileAppender}.
*/
protected
void setQWForFiles(Writer writer) {
this.qw = new QuietWriter(writer, errorHandler);
}
/**
Close any previously opened file and call the parent's
<code>reset</code>. */
protected
void reset() {
closeFile();
this.fileName = null;
super.reset();
}
}

View File

@@ -1,267 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.helpers.Transform;
/**
* This layout outputs events in a HTML table.
*
* Appenders using this layout should have their encoding
* set to UTF-8 or UTF-16, otherwise events containing
* non ASCII characters could result in corrupted
* log files.
*
* @author Ceki G&uuml;lc&uuml;
*/
public class HTMLLayout extends Layout {
protected final int BUF_SIZE = 256;
protected final int MAX_CAPACITY = 1024;
static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";
// output buffer appended to when format() is invoked
private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
/**
A string constant used in naming the option for setting the the
location information flag. Current value of this string
constant is <b>LocationInfo</b>.
<p>Note that all option keys are case sensitive.
@deprecated Options are now handled using the JavaBeans paradigm.
This constant is not longer needed and will be removed in the
<em>near</em> term.
*/
public static final String LOCATION_INFO_OPTION = "LocationInfo";
/**
A string constant used in naming the option for setting the the
HTML document title. Current value of this string
constant is <b>Title</b>.
*/
public static final String TITLE_OPTION = "Title";
// Print no location info by default
boolean locationInfo = false;
String title = "Log4J Log Messages";
/**
The <b>LocationInfo</b> option takes a boolean value. By
default, it is set to false which means there will be no location
information output by this layout. If the the option is set to
true, then the file name and line number of the statement
at the origin of the log statement will be output.
<p>If you are embedding this layout within an {@link
org.apache.log4j.net.SMTPAppender} then make sure to set the
<b>LocationInfo</b> option of that appender as well.
*/
public
void setLocationInfo(boolean flag) {
locationInfo = flag;
}
/**
Returns the current value of the <b>LocationInfo</b> option.
*/
public
boolean getLocationInfo() {
return locationInfo;
}
/**
The <b>Title</b> option takes a String value. This option sets the
document title of the generated HTML document.
<p>Defaults to 'Log4J Log Messages'.
*/
public
void setTitle(String title) {
this.title = title;
}
/**
Returns the current value of the <b>Title</b> option.
*/
public
String getTitle() {
return title;
}
/**
Returns the content type output by this layout, i.e "text/html".
*/
public
String getContentType() {
return "text/html";
}
/**
No options to activate.
*/
public
void activateOptions() {
}
public
String format(LoggingEvent event) {
if(sbuf.capacity() > MAX_CAPACITY) {
sbuf = new StringBuffer(BUF_SIZE);
} else {
sbuf.setLength(0);
}
sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);
sbuf.append("<td>");
sbuf.append(event.timeStamp - LoggingEvent.getStartTime());
sbuf.append("</td>" + Layout.LINE_SEP);
String escapedThread = Transform.escapeTags(event.getThreadName());
sbuf.append("<td title=\"" + escapedThread + " thread\">");
sbuf.append(escapedThread);
sbuf.append("</td>" + Layout.LINE_SEP);
sbuf.append("<td title=\"Level\">");
if (event.getLevel().equals(Level.DEBUG)) {
sbuf.append("<font color=\"#339933\">");
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</font>");
}
else if(event.getLevel().isGreaterOrEqual(Level.WARN)) {
sbuf.append("<font color=\"#993300\"><strong>");
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</strong></font>");
} else {
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
}
sbuf.append("</td>" + Layout.LINE_SEP);
String escapedLogger = Transform.escapeTags(event.getLoggerName());
sbuf.append("<td title=\"" + escapedLogger + " category\">");
sbuf.append(escapedLogger);
sbuf.append("</td>" + Layout.LINE_SEP);
if(locationInfo) {
LocationInfo locInfo = event.getLocationInformation();
sbuf.append("<td>");
sbuf.append(Transform.escapeTags(locInfo.getFileName()));
sbuf.append(':');
sbuf.append(locInfo.getLineNumber());
sbuf.append("</td>" + Layout.LINE_SEP);
}
sbuf.append("<td title=\"Message\">");
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
sbuf.append("</td>" + Layout.LINE_SEP);
sbuf.append("</tr>" + Layout.LINE_SEP);
if (event.getNDC() != null) {
sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");
sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));
sbuf.append("</td></tr>" + Layout.LINE_SEP);
}
String[] s = event.getThrowableStrRep();
if(s != null) {
sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"6\">");
appendThrowableAsHTML(s, sbuf);
sbuf.append("</td></tr>" + Layout.LINE_SEP);
}
return sbuf.toString();
}
void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
if(s != null) {
int len = s.length;
if(len == 0)
return;
sbuf.append(Transform.escapeTags(s[0]));
sbuf.append(Layout.LINE_SEP);
for(int i = 1; i < len; i++) {
sbuf.append(TRACE_PREFIX);
sbuf.append(Transform.escapeTags(s[i]));
sbuf.append(Layout.LINE_SEP);
}
}
}
/**
Returns appropriate HTML headers.
*/
public
String getHeader() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + Layout.LINE_SEP);
sbuf.append("<html>" + Layout.LINE_SEP);
sbuf.append("<head>" + Layout.LINE_SEP);
sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);
sbuf.append("<style type=\"text/css\">" + Layout.LINE_SEP);
sbuf.append("<!--" + Layout.LINE_SEP);
sbuf.append("body, table {font-family: arial,sans-serif; font-size: x-small;}" + Layout.LINE_SEP);
sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);
sbuf.append("-->" + Layout.LINE_SEP);
sbuf.append("</style>" + Layout.LINE_SEP);
sbuf.append("</head>" + Layout.LINE_SEP);
sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP);
sbuf.append("<hr size=\"1\" noshade>" + Layout.LINE_SEP);
sbuf.append("Log session start time " + new java.util.Date() + "<br>" + Layout.LINE_SEP);
sbuf.append("<br>" + Layout.LINE_SEP);
sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);
sbuf.append("<tr>" + Layout.LINE_SEP);
sbuf.append("<th>Time</th>" + Layout.LINE_SEP);
sbuf.append("<th>Thread</th>" + Layout.LINE_SEP);
sbuf.append("<th>Level</th>" + Layout.LINE_SEP);
sbuf.append("<th>Category</th>" + Layout.LINE_SEP);
if(locationInfo) {
sbuf.append("<th>File:Line</th>" + Layout.LINE_SEP);
}
sbuf.append("<th>Message</th>" + Layout.LINE_SEP);
sbuf.append("</tr>" + Layout.LINE_SEP);
return sbuf.toString();
}
/**
Returns the appropriate HTML footers.
*/
public
String getFooter() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("</table>" + Layout.LINE_SEP);
sbuf.append("<br>" + Layout.LINE_SEP);
sbuf.append("</body></html>");
return sbuf.toString();
}
/**
The HTML layout handles the throwable contained in logging
events. Hence, this method return <code>false</code>. */
public
boolean ignoresThrowable() {
return false;
}
}

View File

@@ -1,577 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// WARNING This class MUST not have references to the Category or
// WARNING RootCategory classes in its static initiliazation neither
// WARNING directly nor indirectly.
// Contributors:
// Luke Blanshard <luke@quiq.com>
// Mario Schomburg - IBM Global Services/Germany
// Anders Kristensen
// Igor Poteryaev
package org.apache.log4j;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.log4j.spi.LoggerFactory;
import org.apache.log4j.spi.HierarchyEventListener;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.RendererSupport;
import org.apache.log4j.or.RendererMap;
import org.apache.log4j.or.ObjectRenderer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.ThrowableRendererSupport;
import org.apache.log4j.spi.ThrowableRenderer;
/**
This class is specialized in retrieving loggers by name and also
maintaining the logger hierarchy.
<p><em>The casual user does not have to deal with this class
directly.</em>
<p>The structure of the logger hierarchy is maintained by the
{@link #getLogger} method. The hierarchy is such that children link
to their parent but parents do not have any pointers to their
children. Moreover, loggers can be instantiated in any order, in
particular descendant before ancestor.
<p>In case a descendant is created before a particular ancestor,
then it creates a provision node for the ancestor and adds itself
to the provision node. Other descendants of the same ancestor add
themselves to the previously created provision node.
@author Ceki G&uuml;lc&uuml;
*/
public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
private LoggerFactory defaultFactory;
private Vector listeners;
Hashtable ht;
Logger root;
RendererMap rendererMap;
int thresholdInt;
Level threshold;
boolean emittedNoAppenderWarning = false;
boolean emittedNoResourceBundleWarning = false;
private ThrowableRenderer throwableRenderer = null;
/**
Create a new logger hierarchy.
@param root The root of the new hierarchy.
*/
public
Hierarchy(Logger root) {
ht = new Hashtable();
listeners = new Vector(1);
this.root = root;
// Enable all level levels by default.
setThreshold(Level.ALL);
this.root.setHierarchy(this);
rendererMap = new RendererMap();
defaultFactory = new DefaultCategoryFactory();
}
/**
Add an object renderer for a specific class.
*/
public
void addRenderer(Class classToRender, ObjectRenderer or) {
rendererMap.put(classToRender, or);
}
public
void addHierarchyEventListener(HierarchyEventListener listener) {
if(listeners.contains(listener)) {
LogLog.warn("Ignoring attempt to add an existent listener.");
} else {
listeners.addElement(listener);
}
}
/**
This call will clear all logger definitions from the internal
hashtable. Invoking this method will irrevocably mess up the
logger hierarchy.
<p>You should <em>really</em> know what you are doing before
invoking this method.
@since 0.9.0 */
public
void clear() {
//System.out.println("\n\nAbout to clear internal hash table.");
ht.clear();
}
public
void emitNoAppenderWarning(Category cat) {
// No appenders in hierarchy, warn user only once.
if(!this.emittedNoAppenderWarning) {
LogLog.warn("No appenders could be found for logger (" +
cat.getName() + ").");
LogLog.warn("Please initialize the log4j system properly.");
LogLog.warn("See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.");
this.emittedNoAppenderWarning = true;
}
}
/**
Check if the named logger exists in the hierarchy. If so return
its reference, otherwise returns <code>null</code>.
@param name The name of the logger to search for.
*/
public
Logger exists(String name) {
Object o = ht.get(new CategoryKey(name));
if(o instanceof Logger) {
return (Logger) o;
} else {
return null;
}
}
/**
The string form of {@link #setThreshold(Level)}.
*/
public
void setThreshold(String levelStr) {
Level l = (Level) Level.toLevel(levelStr, null);
if(l != null) {
setThreshold(l);
} else {
LogLog.warn("Could not convert ["+levelStr+"] to Level.");
}
}
/**
Enable logging for logging requests with level <code>l</code> or
higher. By default all levels are enabled.
@param l The minimum level for which logging requests are sent to
their appenders. */
public
void setThreshold(Level l) {
if(l != null) {
thresholdInt = l.level;
threshold = l;
}
}
public
void fireAddAppenderEvent(Category logger, Appender appender) {
if(listeners != null) {
int size = listeners.size();
HierarchyEventListener listener;
for(int i = 0; i < size; i++) {
listener = (HierarchyEventListener) listeners.elementAt(i);
listener.addAppenderEvent(logger, appender);
}
}
}
void fireRemoveAppenderEvent(Category logger, Appender appender) {
if(listeners != null) {
int size = listeners.size();
HierarchyEventListener listener;
for(int i = 0; i < size; i++) {
listener = (HierarchyEventListener) listeners.elementAt(i);
listener.removeAppenderEvent(logger, appender);
}
}
}
/**
Returns a {@link Level} representation of the <code>enable</code>
state.
@since 1.2 */
public
Level getThreshold() {
return threshold;
}
/**
Returns an integer representation of the this repository's
threshold.
@since 1.2 */
//public
//int getThresholdInt() {
// return thresholdInt;
//}
/**
Return a new logger instance named as the first parameter using
the default factory.
<p>If a logger of that name already exists, then it will be
returned. Otherwise, a new logger will be instantiated and
then linked with its existing ancestors as well as children.
@param name The name of the logger to retrieve.
*/
public
Logger getLogger(String name) {
return getLogger(name, defaultFactory);
}
/**
Return a new logger instance named as the first parameter using
<code>factory</code>.
<p>If a logger of that name already exists, then it will be
returned. Otherwise, a new logger will be instantiated by the
<code>factory</code> parameter and linked with its existing
ancestors as well as children.
@param name The name of the logger to retrieve.
@param factory The factory that will make the new logger instance.
*/
public
Logger getLogger(String name, LoggerFactory factory) {
//System.out.println("getInstance("+name+") called.");
CategoryKey key = new CategoryKey(name);
// Synchronize to prevent write conflicts. Read conflicts (in
// getChainedLevel method) are possible only if variable
// assignments are non-atomic.
Logger logger;
synchronized(ht) {
Object o = ht.get(key);
if(o == null) {
logger = factory.makeNewLoggerInstance(name);
logger.setHierarchy(this);
ht.put(key, logger);
updateParents(logger);
return logger;
} else if(o instanceof Logger) {
return (Logger) o;
} else if (o instanceof ProvisionNode) {
//System.out.println("("+name+") ht.get(this) returned ProvisionNode");
logger = factory.makeNewLoggerInstance(name);
logger.setHierarchy(this);
ht.put(key, logger);
updateChildren((ProvisionNode) o, logger);
updateParents(logger);
return logger;
}
else {
// It should be impossible to arrive here
return null; // but let's keep the compiler happy.
}
}
}
/**
Returns all the currently defined categories in this hierarchy as
an {@link java.util.Enumeration Enumeration}.
<p>The root logger is <em>not</em> included in the returned
{@link Enumeration}. */
public
Enumeration getCurrentLoggers() {
// The accumlation in v is necessary because not all elements in
// ht are Logger objects as there might be some ProvisionNodes
// as well.
Vector v = new Vector(ht.size());
Enumeration elems = ht.elements();
while(elems.hasMoreElements()) {
Object o = elems.nextElement();
if(o instanceof Logger) {
v.addElement(o);
}
}
return v.elements();
}
/**
@deprecated Please use {@link #getCurrentLoggers} instead.
*/
public
Enumeration getCurrentCategories() {
return getCurrentLoggers();
}
/**
Get the renderer map for this hierarchy.
*/
public
RendererMap getRendererMap() {
return rendererMap;
}
/**
Get the root of this hierarchy.
@since 0.9.0
*/
public
Logger getRootLogger() {
return root;
}
/**
This method will return <code>true</code> if this repository is
disabled for <code>level</code> object passed as parameter and
<code>false</code> otherwise. See also the {@link
#setThreshold(Level) threshold} emthod. */
public
boolean isDisabled(int level) {
return thresholdInt > level;
}
/**
@deprecated Deprecated with no replacement.
*/
public
void overrideAsNeeded(String override) {
LogLog.warn("The Hiearchy.overrideAsNeeded method has been deprecated.");
}
/**
Reset all values contained in this hierarchy instance to their
default. This removes all appenders from all categories, sets
the level of all non-root categories to <code>null</code>,
sets their additivity flag to <code>true</code> and sets the level
of the root logger to {@link Level#DEBUG DEBUG}. Moreover,
message disabling is set its default "off" value.
<p>Existing categories are not removed. They are just reset.
<p>This method should be used sparingly and with care as it will
block all logging until it is completed.</p>
@since 0.8.5 */
public
void resetConfiguration() {
getRootLogger().setLevel((Level) Level.DEBUG);
root.setResourceBundle(null);
setThreshold(Level.ALL);
// the synchronization is needed to prevent JDK 1.2.x hashtable
// surprises
synchronized(ht) {
shutdown(); // nested locks are OK
Enumeration cats = getCurrentLoggers();
while(cats.hasMoreElements()) {
Logger c = (Logger) cats.nextElement();
c.setLevel(null);
c.setAdditivity(true);
c.setResourceBundle(null);
}
}
rendererMap.clear();
throwableRenderer = null;
}
/**
Does nothing.
@deprecated Deprecated with no replacement.
*/
public
void setDisableOverride(String override) {
LogLog.warn("The Hiearchy.setDisableOverride method has been deprecated.");
}
/**
Used by subclasses to add a renderer to the hierarchy passed as parameter.
*/
public
void setRenderer(Class renderedClass, ObjectRenderer renderer) {
rendererMap.put(renderedClass, renderer);
}
/**
* {@inheritDoc}
*/
public void setThrowableRenderer(final ThrowableRenderer renderer) {
throwableRenderer = renderer;
}
/**
* {@inheritDoc}
*/
public ThrowableRenderer getThrowableRenderer() {
return throwableRenderer;
}
/**
Shutting down a hierarchy will <em>safely</em> close and remove
all appenders in all categories including the root logger.
<p>Some appenders such as {@link org.apache.log4j.net.SocketAppender}
and {@link AsyncAppender} need to be closed before the
application exists. Otherwise, pending logging events might be
lost.
<p>The <code>shutdown</code> method is careful to close nested
appenders before closing regular appenders. This is allows
configurations where a regular appender is attached to a logger
and again to a nested appender.
@since 1.0 */
public
void shutdown() {
Logger root = getRootLogger();
// begin by closing nested appenders
root.closeNestedAppenders();
synchronized(ht) {
Enumeration cats = this.getCurrentLoggers();
while(cats.hasMoreElements()) {
Logger c = (Logger) cats.nextElement();
c.closeNestedAppenders();
}
// then, remove all appenders
root.removeAllAppenders();
cats = this.getCurrentLoggers();
while(cats.hasMoreElements()) {
Logger c = (Logger) cats.nextElement();
c.removeAllAppenders();
}
}
}
/**
This method loops through all the *potential* parents of
'cat'. There 3 possible cases:
1) No entry for the potential parent of 'cat' exists
We create a ProvisionNode for this potential parent and insert
'cat' in that provision node.
2) There entry is of type Logger for the potential parent.
The entry is 'cat's nearest existing parent. We update cat's
parent field with this entry. We also break from the loop
because updating our parent's parent is our parent's
responsibility.
3) There entry is of type ProvisionNode for this potential parent.
We add 'cat' to the list of children for this potential parent.
*/
final
private
void updateParents(Logger cat) {
String name = cat.name;
int length = name.length();
boolean parentFound = false;
//System.out.println("UpdateParents called for " + name);
// if name = "w.x.y.z", loop thourgh "w.x.y", "w.x" and "w", but not "w.x.y.z"
for(int i = name.lastIndexOf('.', length-1); i >= 0;
i = name.lastIndexOf('.', i-1)) {
String substr = name.substring(0, i);
//System.out.println("Updating parent : " + substr);
CategoryKey key = new CategoryKey(substr); // simple constructor
Object o = ht.get(key);
// Create a provision node for a future parent.
if(o == null) {
//System.out.println("No parent "+substr+" found. Creating ProvisionNode.");
ProvisionNode pn = new ProvisionNode(cat);
ht.put(key, pn);
} else if(o instanceof Category) {
parentFound = true;
cat.parent = (Category) o;
//System.out.println("Linking " + cat.name + " -> " + ((Category) o).name);
break; // no need to update the ancestors of the closest ancestor
} else if(o instanceof ProvisionNode) {
((ProvisionNode) o).addElement(cat);
} else {
Exception e = new IllegalStateException("unexpected object type " +
o.getClass() + " in ht.");
e.printStackTrace();
}
}
// If we could not find any existing parents, then link with root.
if(!parentFound)
cat.parent = root;
}
/**
We update the links for all the children that placed themselves
in the provision node 'pn'. The second argument 'cat' is a
reference for the newly created Logger, parent of all the
children in 'pn'
We loop on all the children 'c' in 'pn':
If the child 'c' has been already linked to a child of
'cat' then there is no need to update 'c'.
Otherwise, we set cat's parent field to c's parent and set
c's parent field to cat.
*/
final
private
void updateChildren(ProvisionNode pn, Logger logger) {
//System.out.println("updateChildren called for " + logger.name);
final int last = pn.size();
for(int i = 0; i < last; i++) {
Logger l = (Logger) pn.elementAt(i);
//System.out.println("Updating child " +p.name);
// Unless this child already points to a correct (lower) parent,
// make cat.parent point to l.parent and l.parent to cat.
if(!l.parent.name.startsWith(logger.name)) {
logger.parent = l.parent;
l.parent = logger;
}
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.OptionHandler;
import org.apache.log4j.spi.LoggingEvent;
/**
Extend this abstract class to create your own log layout format.
@author Ceki G&uuml;lc&uuml;
*/
public abstract class Layout implements OptionHandler {
// Note that the line.separator property can be looked up even by
// applets.
public final static String LINE_SEP = System.getProperty("line.separator");
public final static int LINE_SEP_LEN = LINE_SEP.length();
/**
Implement this method to create your own layout format.
*/
abstract
public
String format(LoggingEvent event);
/**
Returns the content type output by this layout. The base class
returns "text/plain".
*/
public
String getContentType() {
return "text/plain";
}
/**
Returns the header for the layout format. The base class returns
<code>null</code>. */
public
String getHeader() {
return null;
}
/**
Returns the footer for the layout format. The base class returns
<code>null</code>. */
public
String getFooter() {
return null;
}
/**
If the layout handles the throwable object contained within
{@link LoggingEvent}, then the layout should return
<code>false</code>. Otherwise, if the layout ignores throwable
object, then the layout should return <code>true</code>.
If ignoresThrowable is true, the appender is responsible for
rendering the throwable.
<p>The {@link SimpleLayout}, {@link TTCCLayout}, {@link
PatternLayout} all return <code>true</code>. The {@link
org.apache.log4j.xml.XMLLayout} returns <code>false</code>.
@since 0.8.4 */
abstract
public
boolean ignoresThrowable();
}

View File

@@ -1,224 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Kitching Simon <Simon.Kitching@orange.ch>
// Nicholas Wolff
package org.apache.log4j;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
Defines the minimum set of levels recognized by the system, that is
<code>OFF</code>, <code>FATAL</code>, <code>ERROR</code>,
<code>WARN</code>, <code>INFO</code, <code>DEBUG</code> and
<code>ALL</code>.
<p>The <code>Level</code> class may be subclassed to define a larger
level set.
@author Ceki G&uuml;lc&uuml;
*/
public class Level extends Priority implements Serializable {
/**
* TRACE level integer value.
* @since 1.2.12
*/
public static final int TRACE_INT = 5000;
/**
The <code>OFF</code> has the highest possible rank and is
intended to turn off logging. */
final static public Level OFF = new Level(OFF_INT, "OFF", 0);
/**
The <code>FATAL</code> level designates very severe error
events that will presumably lead the application to abort.
*/
final static public Level FATAL = new Level(FATAL_INT, "FATAL", 0);
/**
The <code>ERROR</code> level designates error events that
might still allow the application to continue running. */
final static public Level ERROR = new Level(ERROR_INT, "ERROR", 3);
/**
The <code>WARN</code> level designates potentially harmful situations.
*/
final static public Level WARN = new Level(WARN_INT, "WARN", 4);
/**
The <code>INFO</code> level designates informational messages
that highlight the progress of the application at coarse-grained
level. */
final static public Level INFO = new Level(INFO_INT, "INFO", 6);
/**
The <code>DEBUG</code> Level designates fine-grained
informational events that are most useful to debug an
application. */
final static public Level DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
/**
* The <code>TRACE</code> Level designates finer-grained
* informational events than the <code>DEBUG</code level.
* @since 1.2.12
*/
public static final Level TRACE = new Level(TRACE_INT, "TRACE", 7);
/**
The <code>ALL</code> has the lowest possible rank and is intended to
turn on all logging. */
final static public Level ALL = new Level(ALL_INT, "ALL", 7);
/**
* Serialization version id.
*/
static final long serialVersionUID = 3491141966387921974L;
/**
Instantiate a Level object.
*/
protected
Level(int level, String levelStr, int syslogEquivalent) {
super(level, levelStr, syslogEquivalent);
}
/**
Convert the string passed as argument to a level. If the
conversion fails, then this method returns {@link #DEBUG}.
*/
public
static
Level toLevel(String sArg) {
return (Level) toLevel(sArg, Level.DEBUG);
}
/**
Convert an integer passed as argument to a level. If the
conversion fails, then this method returns {@link #DEBUG}.
*/
public
static
Level toLevel(int val) {
return (Level) toLevel(val, Level.DEBUG);
}
/**
Convert an integer passed as argument to a level. If the
conversion fails, then this method returns the specified default.
*/
public
static
Level toLevel(int val, Level defaultLevel) {
switch(val) {
case ALL_INT: return ALL;
case DEBUG_INT: return Level.DEBUG;
case INFO_INT: return Level.INFO;
case WARN_INT: return Level.WARN;
case ERROR_INT: return Level.ERROR;
case FATAL_INT: return Level.FATAL;
case OFF_INT: return OFF;
case TRACE_INT: return Level.TRACE;
default: return defaultLevel;
}
}
/**
Convert the string passed as argument to a level. If the
conversion fails, then this method returns the value of
<code>defaultLevel</code>.
*/
public
static
Level toLevel(String sArg, Level defaultLevel) {
if(sArg == null)
return defaultLevel;
String s = sArg.toUpperCase();
if(s.equals("ALL")) return Level.ALL;
if(s.equals("DEBUG")) return Level.DEBUG;
if(s.equals("INFO")) return Level.INFO;
if(s.equals("WARN")) return Level.WARN;
if(s.equals("ERROR")) return Level.ERROR;
if(s.equals("FATAL")) return Level.FATAL;
if(s.equals("OFF")) return Level.OFF;
if(s.equals("TRACE")) return Level.TRACE;
//
// For Turkish i problem, see bug 40937
//
if(s.equals("\u0130NFO")) return Level.INFO;
return defaultLevel;
}
/**
* Custom deserialization of Level.
* @param s serialization stream.
* @throws IOException if IO exception.
* @throws ClassNotFoundException if class not found.
*/
private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
level = s.readInt();
syslogEquivalent = s.readInt();
levelStr = s.readUTF();
if (levelStr == null) {
levelStr = "";
}
}
/**
* Serialize level.
* @param s serialization stream.
* @throws IOException if exception during serialization.
*/
private void writeObject(final ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(level);
s.writeInt(syslogEquivalent);
s.writeUTF(levelStr);
}
/**
* Resolved deserialized level to one of the stock instances.
* May be overriden in classes derived from Level.
* @return resolved object.
* @throws ObjectStreamException if exception during resolution.
*/
private Object readResolve() throws ObjectStreamException {
//
// if the deserizalized object is exactly an instance of Level
//
if (getClass() == Level.class) {
return toLevel(level);
}
//
// extension of Level can't substitute stock item
//
return this;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,276 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.LoggerFactory;
import org.apache.log4j.spi.RepositorySelector;
import org.apache.log4j.spi.DefaultRepositorySelector;
import org.apache.log4j.spi.RootLogger;
import org.apache.log4j.spi.NOPLoggerRepository;
import org.apache.log4j.helpers.Loader;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.LogLog;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Enumeration;
import java.io.StringWriter;
import java.io.PrintWriter;
/**
* Use the <code>LogManager</code> class to retreive {@link Logger}
* instances or to operate on the current {@link
* LoggerRepository}. When the <code>LogManager</code> class is loaded
* into memory the default initalzation procedure is inititated. The
* default intialization procedure</a> is described in the <a
* href="../../../../manual.html#defaultInit">short log4j manual</a>.
*
* @author Ceki G&uuml;lc&uuml; */
public class LogManager {
/**
* @deprecated This variable is for internal use only. It will
* become package protected in future versions.
* */
static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
/**
* @deprecated This variable is for internal use only. It will
* become private in future versions.
* */
static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
/**
* @deprecated This variable is for internal use only. It will
* become private in future versions.
* */
static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
/**
* @deprecated This variable is for internal use only. It will
* become private in future versions.
*/
public static final String DEFAULT_INIT_OVERRIDE_KEY =
"log4j.defaultInitOverride";
static private Object guard = null;
static private RepositorySelector repositorySelector;
static {
// By default we use a DefaultRepositorySelector which always returns 'h'.
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h);
/** Search for the properties file log4j.properties in the CLASSPATH. */
String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
null);
// if there is no default init override, then get the resource
// specified by the user or the default config file.
if(override == null || "false".equalsIgnoreCase(override)) {
String configurationOptionStr = OptionConverter.getSystemProperty(
DEFAULT_CONFIGURATION_KEY,
null);
String configuratorClassName = OptionConverter.getSystemProperty(
CONFIGURATOR_CLASS_KEY,
null);
URL url = null;
// if the user has not specified the log4j.configuration
// property, we search first for the file "log4j.xml" and then
// "log4j.properties"
if(configurationOptionStr == null) {
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
if(url == null) {
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
}
} else {
try {
url = new URL(configurationOptionStr);
} catch (MalformedURLException ex) {
// so, resource is not a URL:
// attempt to get the resource from the class path
url = Loader.getResource(configurationOptionStr);
}
}
// If we have a non-null url, then delegate the rest of the
// configuration to the OptionConverter.selectAndConfigure
// method.
if(url != null) {
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
try {
OptionConverter.selectAndConfigure(url, configuratorClassName,
LogManager.getLoggerRepository());
} catch (NoClassDefFoundError e) {
LogLog.warn("Error during default initialization", e);
}
} else {
LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
}
} else {
LogLog.debug("Default initialization of overridden by " +
DEFAULT_INIT_OVERRIDE_KEY + "property.");
}
}
/**
Sets <code>LoggerFactory</code> but only if the correct
<em>guard</em> is passed as parameter.
<p>Initally the guard is null. If the guard is
<code>null</code>, then invoking this method sets the logger
factory and the guard. Following invocations will throw a {@link
IllegalArgumentException}, unless the previously set
<code>guard</code> is passed as the second parameter.
<p>This allows a high-level component to set the {@link
RepositorySelector} used by the <code>LogManager</code>.
<p>For example, when tomcat starts it will be able to install its
own repository selector. However, if and when Tomcat is embedded
within JBoss, then JBoss will install its own repository selector
and Tomcat will use the repository selector set by its container,
JBoss. */
static
public
void setRepositorySelector(RepositorySelector selector, Object guard)
throws IllegalArgumentException {
if((LogManager.guard != null) && (LogManager.guard != guard)) {
throw new IllegalArgumentException(
"Attempted to reset the LoggerFactory without possessing the guard.");
}
if(selector == null) {
throw new IllegalArgumentException("RepositorySelector must be non-null.");
}
LogManager.guard = guard;
LogManager.repositorySelector = selector;
}
/**
* This method tests if called from a method that
* is known to result in class members being abnormally
* set to null but is assumed to be harmless since the
* all classes are in the process of being unloaded.
*
* @param ex exception used to determine calling stack.
* @return true if calling stack is recognized as likely safe.
*/
private static boolean isLikelySafeScenario(final Exception ex) {
StringWriter stringWriter = new StringWriter();
ex.printStackTrace(new PrintWriter(stringWriter));
String msg = stringWriter.toString();
return msg.indexOf("org.apache.catalina.loader.WebappClassLoader.stop") != -1;
}
static
public
LoggerRepository getLoggerRepository() {
if (repositorySelector == null) {
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
guard = null;
Exception ex = new IllegalStateException("Class invariant violation");
String msg =
"log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
if (isLikelySafeScenario(ex)) {
LogLog.debug(msg, ex);
} else {
LogLog.error(msg, ex);
}
}
return repositorySelector.getLoggerRepository();
}
/**
Retrieve the appropriate root logger.
*/
public
static
Logger getRootLogger() {
// Delegate the actual manufacturing of the logger to the logger repository.
return getLoggerRepository().getRootLogger();
}
/**
Retrieve the appropriate {@link Logger} instance.
*/
public
static
Logger getLogger(final String name) {
// Delegate the actual manufacturing of the logger to the logger repository.
return getLoggerRepository().getLogger(name);
}
/**
Retrieve the appropriate {@link Logger} instance.
*/
public
static
Logger getLogger(final Class clazz) {
// Delegate the actual manufacturing of the logger to the logger repository.
return getLoggerRepository().getLogger(clazz.getName());
}
/**
Retrieve the appropriate {@link Logger} instance.
*/
public
static
Logger getLogger(final String name, final LoggerFactory factory) {
// Delegate the actual manufacturing of the logger to the logger repository.
return getLoggerRepository().getLogger(name, factory);
}
public
static
Logger exists(final String name) {
return getLoggerRepository().exists(name);
}
public
static
Enumeration getCurrentLoggers() {
return getLoggerRepository().getCurrentLoggers();
}
public
static
void shutdown() {
getLoggerRepository().shutdown();
}
public
static
void resetConfiguration() {
getLoggerRepository().resetConfiguration();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,371 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggingEvent;
/**
* This is a base class for LogMF and LogSF parameterized logging classes.
*
*
* @see org.apache.log4j.LogMF
* @see org.apache.log4j.LogSF
* @since 1.2.16
*/
public abstract class LogXF {
/**
* Trace level.
*/
protected static final Level TRACE = new Level(5000, "TRACE", 7);
/**
* Fully Qualified Class Name of this class.
*/
private static final String FQCN = LogXF.class.getName();
protected LogXF() {
}
/**
* Returns a Boolean instance representing the specified boolean.
* Boolean.valueOf was added in JDK 1.4.
*
* @param b a boolean value.
* @return a Boolean instance representing b.
*/
protected static Boolean valueOf(final boolean b) {
if (b) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
/**
* Returns a Character instance representing the specified char.
* Character.valueOf was added in JDK 1.5.
*
* @param c a character value.
* @return a Character instance representing c.
*/
protected static Character valueOf(final char c) {
return new Character(c);
}
/**
* Returns a Byte instance representing the specified byte.
* Byte.valueOf was added in JDK 1.5.
*
* @param b a byte value.
* @return a Byte instance representing b.
*/
protected static Byte valueOf(final byte b) {
return new Byte(b);
}
/**
* Returns a Short instance representing the specified short.
* Short.valueOf was added in JDK 1.5.
*
* @param b a short value.
* @return a Byte instance representing b.
*/
protected static Short valueOf(final short b) {
return new Short(b);
}
/**
* Returns an Integer instance representing the specified int.
* Integer.valueOf was added in JDK 1.5.
*
* @param b an int value.
* @return an Integer instance representing b.
*/
protected static Integer valueOf(final int b) {
return new Integer(b);
}
/**
* Returns a Long instance representing the specified long.
* Long.valueOf was added in JDK 1.5.
*
* @param b a long value.
* @return a Long instance representing b.
*/
protected static Long valueOf(final long b) {
return new Long(b);
}
/**
* Returns a Float instance representing the specified float.
* Float.valueOf was added in JDK 1.5.
*
* @param b a float value.
* @return a Float instance representing b.
*/
protected static Float valueOf(final float b) {
return new Float(b);
}
/**
* Returns a Double instance representing the specified double.
* Double.valueOf was added in JDK 1.5.
*
* @param b a double value.
* @return a Byte instance representing b.
*/
protected static Double valueOf(final double b) {
return new Double(b);
}
/**
* Create new array.
*
* @param param1 parameter 1.
* @return new array.
*/
protected static Object[] toArray(final Object param1) {
return new Object[]{
param1
};
}
/**
* Create new array.
*
* @param param1 parameter 1.
* @param param2 parameter 2.
* @return new array.
*/
protected static Object[] toArray(final Object param1,
final Object param2) {
return new Object[]{
param1, param2
};
}
/**
* Create new array.
*
* @param param1 parameter 1.
* @param param2 parameter 2.
* @param param3 parameter 3.
* @return new array.
*/
protected static Object[] toArray(final Object param1,
final Object param2,
final Object param3) {
return new Object[]{
param1, param2, param3
};
}
/**
* Create new array.
*
* @param param1 parameter 1.
* @param param2 parameter 2.
* @param param3 parameter 3.
* @param param4 parameter 4.
* @return new array.
*/
protected static Object[] toArray(final Object param1,
final Object param2,
final Object param3,
final Object param4) {
return new Object[]{
param1, param2, param3, param4
};
}
/**
* Log an entering message at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
*/
public static void entering(final Logger logger,
final String sourceClass,
final String sourceMethod) {
if (logger.isDebugEnabled()) {
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
sourceClass + "." + sourceMethod + " ENTRY", null));
}
}
/**
* Log an entering message with a parameter at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
* @param param parameter, may be null.
*/
public static void entering(final Logger logger,
final String sourceClass,
final String sourceMethod,
final String param) {
if (logger.isDebugEnabled()) {
String msg = sourceClass + "." + sourceMethod + " ENTRY " + param;
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
msg, null));
}
}
/**
* Log an entering message with a parameter at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
* @param param parameter, may be null.
*/
public static void entering(final Logger logger,
final String sourceClass,
final String sourceMethod,
final Object param) {
if (logger.isDebugEnabled()) {
String msg = sourceClass + "." + sourceMethod + " ENTRY ";
if (param == null) {
msg += "null";
} else {
try {
msg += param;
} catch(Throwable ex) {
msg += "?";
}
}
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
msg, null));
}
}
/**
* Log an entering message with an array of parameters at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
* @param params parameters, may be null.
*/
public static void entering(final Logger logger,
final String sourceClass,
final String sourceMethod,
final Object[] params) {
if (logger.isDebugEnabled()) {
String msg = sourceClass + "." + sourceMethod + " ENTRY ";
if (params != null && params.length > 0) {
String delim = "{";
for (int i = 0; i < params.length; i++) {
try {
msg += delim + params[i];
} catch(Throwable ex) {
msg += delim + "?";
}
delim = ",";
}
msg += "}";
} else {
msg += "{}";
}
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
msg, null));
}
}
/**
* Log an exiting message at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
*/
public static void exiting(final Logger logger,
final String sourceClass,
final String sourceMethod) {
if (logger.isDebugEnabled()) {
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
sourceClass + "." + sourceMethod + " RETURN", null));
}
}
/**
* Log an exiting message with result at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
* @param result result, may be null.
*/
public static void exiting(
final Logger logger,
final String sourceClass,
final String sourceMethod,
final String result) {
if (logger.isDebugEnabled()) {
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
sourceClass + "." + sourceMethod + " RETURN " + result, null));
}
}
/**
* Log an exiting message with result at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
* @param result result, may be null.
*/
public static void exiting(
final Logger logger,
final String sourceClass,
final String sourceMethod,
final Object result) {
if (logger.isDebugEnabled()) {
String msg = sourceClass + "." + sourceMethod + " RETURN ";
if (result == null) {
msg += "null";
} else {
try {
msg += result;
} catch(Throwable ex) {
msg += "?";
}
}
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
msg, null));
}
}
/**
* Logs a throwing message at DEBUG level.
*
* @param logger logger, may not be null.
* @param sourceClass source class, may be null.
* @param sourceMethod method, may be null.
* @param thrown throwable, may be null.
*/
public static void throwing(
final Logger logger,
final String sourceClass,
final String sourceMethod,
final Throwable thrown) {
if (logger.isDebugEnabled()) {
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
sourceClass + "." + sourceMethod + " THROW", thrown));
}
}
}

View File

@@ -1,212 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggerFactory;
/**
This is the central class in the log4j package. Most logging
operations, except configuration, are done through this class.
@since log4j 1.2
@author Ceki G&uuml;lc&uuml; */
public class Logger extends Category {
/**
The fully qualified name of the Logger class. See also the
getFQCN method. */
private static final String FQCN = Logger.class.getName();
protected
Logger(String name) {
super(name);
}
/**
Log a message object with the {@link Level#FINE FINE} level which
is just an alias for the {@link Level#DEBUG DEBUG} level.
<p>This method first checks if this category is <code>DEBUG</code>
enabled by comparing the level of this category with the {@link
Level#DEBUG DEBUG} level. If this category is
<code>DEBUG</code> enabled, then it converts the message object
(passed as parameter) to a string by invoking the appropriate
{@link org.apache.log4j.or.ObjectRenderer}. It then proceeds to call all the
registered appenders in this category and also higher in the
hierarchy depending on the value of the additivity flag.
<p><b>WARNING</b> Note that passing a {@link Throwable} to this
method will print the name of the <code>Throwable</code> but no
stack trace. To print a stack trace use the {@link #debug(Object,
Throwable)} form instead.
@param message the message object to log. */
//public
//void fine(Object message) {
// if(repository.isDisabled(Level.DEBUG_INT))
// return;
// if(Level.DEBUG.isGreaterOrEqual(this.getChainedLevel())) {
// forcedLog(FQCN, Level.DEBUG, message, null);
// }
//}
/**
Log a message object with the <code>FINE</code> level including
the stack trace of the {@link Throwable} <code>t</code> passed as
parameter.
<p>See {@link #fine(Object)} form for more detailed information.
@param message the message object to log.
@param t the exception to log, including its stack trace. */
//public
//void fine(Object message, Throwable t) {
// if(repository.isDisabled(Level.DEBUG_INT))
// return;
// if(Level.DEBUG.isGreaterOrEqual(this.getChainedLevel()))
// forcedLog(FQCN, Level.FINE, message, t);
//}
/**
* Retrieve a logger named according to the value of the
* <code>name</code> parameter. If the named logger already exists,
* then the existing instance will be returned. Otherwise, a new
* instance is created.
*
* <p>By default, loggers do not have a set level but inherit it
* from their neareast ancestor with a set level. This is one of the
* central features of log4j.
*
* @param name The name of the logger to retrieve.
*/
static
public
Logger getLogger(String name) {
return LogManager.getLogger(name);
}
/**
* Shorthand for <code>getLogger(clazz.getName())</code>.
*
* @param clazz The name of <code>clazz</code> will be used as the
* name of the logger to retrieve. See {@link #getLogger(String)}
* for more detailed information.
*/
static
public
Logger getLogger(Class clazz) {
return LogManager.getLogger(clazz.getName());
}
/**
* Return the root logger for the current logger repository.
* <p>
* The {@link #getName Logger.getName()} method for the root logger always returns
* stirng value: "root". However, calling
* <code>Logger.getLogger("root")</code> does not retrieve the root
* logger but a logger just under root named "root".
* <p>
* In other words, calling this method is the only way to retrieve the
* root logger.
*/
public
static
Logger getRootLogger() {
return LogManager.getRootLogger();
}
/**
Like {@link #getLogger(String)} except that the type of logger
instantiated depends on the type returned by the {@link
LoggerFactory#makeNewLoggerInstance} method of the
<code>factory</code> parameter.
<p>This method is intended to be used by sub-classes.
@param name The name of the logger to retrieve.
@param factory A {@link LoggerFactory} implementation that will
actually create a new Instance.
@since 0.8.5 */
public
static
Logger getLogger(String name, LoggerFactory factory) {
return LogManager.getLogger(name, factory);
}
/**
* Log a message object with the {@link org.apache.log4j.Level#TRACE TRACE} level.
*
* @param message the message object to log.
* @see #debug(Object) for an explanation of the logic applied.
* @since 1.2.12
*/
public void trace(Object message) {
if (repository.isDisabled(Level.TRACE_INT)) {
return;
}
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
forcedLog(FQCN, Level.TRACE, message, null);
}
}
/**
* Log a message object with the <code>TRACE</code> level including the
* stack trace of the {@link Throwable}<code>t</code> passed as parameter.
*
* <p>
* See {@link #debug(Object)} form for more detailed information.
* </p>
*
* @param message the message object to log.
* @param t the exception to log, including its stack trace.
* @since 1.2.12
*/
public void trace(Object message, Throwable t) {
if (repository.isDisabled(Level.TRACE_INT)) {
return;
}
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
forcedLog(FQCN, Level.TRACE, message, t);
}
}
/**
* Check whether this category is enabled for the TRACE Level.
* @since 1.2.12
*
* @return boolean - <code>true</code> if this category is enabled for level
* TRACE, <code>false</code> otherwise.
*/
public boolean isTraceEnabled() {
if (repository.isDisabled(Level.TRACE_INT)) {
return false;
}
return Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel());
}
}

View File

@@ -1,187 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.util.Hashtable;
import org.apache.log4j.helpers.Loader;
import org.apache.log4j.helpers.ThreadLocalMap;
/**
The MDC class is similar to the {@link NDC} class except that it is
based on a map instead of a stack. It provides <em>mapped
diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
MDC in short, is an instrument for distinguishing interleaved log
output from different sources. Log output is typically interleaved
when a server handles multiple clients near-simultaneously.
<p><b><em>The MDC is managed on a per thread basis</em></b>. A
child thread automatically inherits a <em>copy</em> of the mapped
diagnostic context of its parent.
<p>The MDC class requires JDK 1.2 or above. Under JDK 1.1 the MDC
will always return empty values but otherwise will not affect or
harm your application.
@since 1.2
@author Ceki G&uuml;lc&uuml; */
public class MDC {
final static MDC mdc = new MDC();
static final int HT_SIZE = 7;
boolean java1;
Object tlm;
private
MDC() {
java1 = Loader.isJava1();
if(!java1) {
tlm = new ThreadLocalMap();
}
}
/**
Put a context value (the <code>o</code> parameter) as identified
with the <code>key</code> parameter into the current thread's
context map.
<p>If the current thread does not have a context map it is
created as a side effect.
*/
static
public
void put(String key, Object o) {
if (mdc != null) {
mdc.put0(key, o);
}
}
/**
Get the context identified by the <code>key</code> parameter.
<p>This method has no side effects.
*/
static
public
Object get(String key) {
if (mdc != null) {
return mdc.get0(key);
}
return null;
}
/**
Remove the the context identified by the <code>key</code>
parameter.
*/
static
public
void remove(String key) {
if (mdc != null) {
mdc.remove0(key);
}
}
/**
* Get the current thread's MDC as a hashtable. This method is
* intended to be used internally.
* */
public static Hashtable getContext() {
if (mdc != null) {
return mdc.getContext0();
} else {
return null;
}
}
/**
* Remove all values from the MDC.
* @since 1.2.16
*/
public static void clear() {
if (mdc != null) {
mdc.clear0();
}
}
private
void put0(String key, Object o) {
if(java1 || tlm == null) {
return;
} else {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if(ht == null) {
ht = new Hashtable(HT_SIZE);
((ThreadLocalMap)tlm).set(ht);
}
ht.put(key, o);
}
}
private
Object get0(String key) {
if(java1 || tlm == null) {
return null;
} else {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if(ht != null && key != null) {
return ht.get(key);
} else {
return null;
}
}
}
private
void remove0(String key) {
if(!java1 && tlm != null) {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if(ht != null) {
ht.remove(key);
}
}
}
private
Hashtable getContext0() {
if(java1 || tlm == null) {
return null;
} else {
return (Hashtable) ((ThreadLocalMap)tlm).get();
}
}
private
void clear0() {
if(!java1 && tlm != null) {
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
if(ht != null) {
ht.clear();
}
}
}
}

View File

@@ -1,436 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Dan Milstein
// Ray Millard
package org.apache.log4j;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.log4j.helpers.LogLog;
/**
The NDC class implements <i>nested diagnostic contexts</i> as
defined by Neil Harrison in the article "Patterns for Logging
Diagnostic Messages" part of the book "<i>Pattern Languages of
Program Design 3</i>" edited by Martin et al.
<p>A Nested Diagnostic Context, or NDC in short, is an instrument
to distinguish interleaved log output from different sources. Log
output is typically interleaved when a server handles multiple
clients near-simultaneously.
<p>Interleaved log output can still be meaningful if each log entry
from different contexts had a distinctive stamp. This is where NDCs
come into play.
<p><em><b>Note that NDCs are managed on a per thread
basis</b></em>. NDC operations such as {@link #push push}, {@link
#pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
affect the NDC of the <em>current</em> thread only. NDCs of other
threads remain unaffected.
<p>For example, a servlet can build a per client request NDC
consisting the clients host name and other information contained in
the the request. <em>Cookies</em> are another source of distinctive
information. To build an NDC one uses the {@link #push push}
operation. Simply put,
<p><ul>
<li>Contexts can be nested.
<p><li>When entering a context, call <code>NDC.push</code>. As a
side effect, if there is no nested diagnostic context for the
current thread, this method will create it.
<p><li>When leaving a context, call <code>NDC.pop</code>.
<p><li><b>When exiting a thread make sure to call {@link #remove
NDC.remove()}</b>.
</ul>
<p>There is no penalty for forgetting to match each
<code>push</code> operation with a corresponding <code>pop</code>,
except the obvious mismatch between the real application context
and the context set in the NDC.
<p>If configured to do so, {@link PatternLayout} and {@link
TTCCLayout} instances automatically retrieve the nested diagnostic
context for the current thread without any user intervention.
Hence, even if a servlet is serving multiple clients
simultaneously, the logs emanating from the same code (belonging to
the same category) can still be distinguished because each client
request will have a different NDC tag.
<p>Heavy duty systems should call the {@link #remove} method when
leaving the running method of a thread. This ensures that the memory
used by the thread can be freed by the Java garbage
collector. There is a mechanism to lazily remove references to dead
threads. In practice, this means that you can be a little sloppy
and sometimes forget to call {@link #remove} before exiting a
thread.
<p>A thread may inherit the nested diagnostic context of another
(possibly parent) thread using the {@link #inherit inherit}
method. A thread may obtain a copy of its NDC with the {@link
#cloneStack cloneStack} method and pass the reference to any other
thread, in particular to a child.
@author Ceki G&uuml;lc&uuml;
@since 0.7.0
*/
public class NDC {
// The synchronized keyword is not used in this class. This may seem
// dangerous, especially since the class will be used by
// multiple-threads. In particular, all threads share the same
// hashtable (the "ht" variable). This is OK since java hashtables
// are thread safe. Same goes for Stacks.
// More importantly, when inheriting diagnostic contexts the child
// thread is handed a clone of the parent's NDC. It follows that
// each thread has its own NDC (i.e. stack).
static Hashtable ht = new Hashtable();
static int pushCounter = 0; // the number of times push has been called
// after the latest call to lazyRemove
// The number of times we allow push to be called before we call lazyRemove
// 5 is a relatively small number. As such, lazyRemove is not called too
// frequently. We thus avoid the cost of creating an Enumeration too often.
// The higher this number, the longer is the avarage period for which all
// logging calls in all threads are blocked.
static final int REAP_THRESHOLD = 5;
// No instances allowed.
private NDC() {}
/**
* Get NDC stack for current thread.
* @return NDC stack for current thread.
*/
private static Stack getCurrentStack() {
if (ht != null) {
return (Stack) ht.get(Thread.currentThread());
}
return null;
}
/**
Clear any nested diagnostic information if any. This method is
useful in cases where the same thread can be potentially used
over and over in different unrelated contexts.
<p>This method is equivalent to calling the {@link #setMaxDepth}
method with a zero <code>maxDepth</code> argument.
@since 0.8.4c */
public
static
void clear() {
Stack stack = getCurrentStack();
if(stack != null)
stack.setSize(0);
}
/**
Clone the diagnostic context for the current thread.
<p>Internally a diagnostic context is represented as a stack. A
given thread can supply the stack (i.e. diagnostic context) to a
child thread so that the child can inherit the parent thread's
diagnostic context.
<p>The child thread uses the {@link #inherit inherit} method to
inherit the parent's diagnostic context.
@return Stack A clone of the current thread's diagnostic context.
*/
public
static
Stack cloneStack() {
Stack stack = getCurrentStack();
if(stack == null)
return null;
else {
return (Stack) stack.clone();
}
}
/**
Inherit the diagnostic context of another thread.
<p>The parent thread can obtain a reference to its diagnostic
context using the {@link #cloneStack} method. It should
communicate this information to its child so that it may inherit
the parent's diagnostic context.
<p>The parent's diagnostic context is cloned before being
inherited. In other words, once inherited, the two diagnostic
contexts can be managed independently.
<p>In java, a child thread cannot obtain a reference to its
parent, unless it is directly handed the reference. Consequently,
there is no client-transparent way of inheriting diagnostic
contexts. Do you know any solution to this problem?
@param stack The diagnostic context of the parent thread.
*/
public
static
void inherit(Stack stack) {
if(stack != null)
ht.put(Thread.currentThread(), stack);
}
/**
<font color="#FF4040"><b>Never use this method directly, use the {@link
org.apache.log4j.spi.LoggingEvent#getNDC} method instead</b></font>.
*/
static
public
String get() {
Stack s = getCurrentStack();
if(s != null && !s.isEmpty())
return ((DiagnosticContext) s.peek()).fullMessage;
else
return null;
}
/**
* Get the current nesting depth of this diagnostic context.
*
* @see #setMaxDepth
* @since 0.7.5
*/
public
static
int getDepth() {
Stack stack = getCurrentStack();
if(stack == null)
return 0;
else
return stack.size();
}
private
static
void lazyRemove() {
if (ht == null) return;
// The synchronization on ht is necessary to prevent JDK 1.2.x from
// throwing ConcurrentModificationExceptions at us. This sucks BIG-TIME.
// One solution is to write our own hashtable implementation.
Vector v;
synchronized(ht) {
// Avoid calling clean-up too often.
if(++pushCounter <= REAP_THRESHOLD) {
return; // We release the lock ASAP.
} else {
pushCounter = 0; // OK let's do some work.
}
int misses = 0;
v = new Vector();
Enumeration enumeration = ht.keys();
// We give up after 4 straigt missses. That is 4 consecutive
// inspected threads in 'ht' that turn out to be alive.
// The higher the proportion on dead threads in ht, the higher the
// chances of removal.
while(enumeration.hasMoreElements() && (misses <= 4)) {
Thread t = (Thread) enumeration.nextElement();
if(t.isAlive()) {
misses++;
} else {
misses = 0;
v.addElement(t);
}
}
} // synchronized
int size = v.size();
for(int i = 0; i < size; i++) {
Thread t = (Thread) v.elementAt(i);
LogLog.debug("Lazy NDC removal for thread [" + t.getName() + "] ("+
ht.size() + ").");
ht.remove(t);
}
}
/**
Clients should call this method before leaving a diagnostic
context.
<p>The returned value is the value that was pushed last. If no
context is available, then the empty string "" is returned.
@return String The innermost diagnostic context.
*/
public
static
String pop() {
Stack stack = getCurrentStack();
if(stack != null && !stack.isEmpty())
return ((DiagnosticContext) stack.pop()).message;
else
return "";
}
/**
Looks at the last diagnostic context at the top of this NDC
without removing it.
<p>The returned value is the value that was pushed last. If no
context is available, then the empty string "" is returned.
@return String The innermost diagnostic context.
*/
public
static
String peek() {
Stack stack = getCurrentStack();
if(stack != null && !stack.isEmpty())
return ((DiagnosticContext) stack.peek()).message;
else
return "";
}
/**
Push new diagnostic context information for the current thread.
<p>The contents of the <code>message</code> parameter is
determined solely by the client.
@param message The new diagnostic context information. */
public
static
void push(String message) {
Stack stack = getCurrentStack();
if(stack == null) {
DiagnosticContext dc = new DiagnosticContext(message, null);
stack = new Stack();
Thread key = Thread.currentThread();
ht.put(key, stack);
stack.push(dc);
} else if (stack.isEmpty()) {
DiagnosticContext dc = new DiagnosticContext(message, null);
stack.push(dc);
} else {
DiagnosticContext parent = (DiagnosticContext) stack.peek();
stack.push(new DiagnosticContext(message, parent));
}
}
/**
Remove the diagnostic context for this thread.
<p>Each thread that created a diagnostic context by calling
{@link #push} should call this method before exiting. Otherwise,
the memory used by the <b>thread</b> cannot be reclaimed by the
VM.
<p>As this is such an important problem in heavy duty systems and
because it is difficult to always guarantee that the remove
method is called before exiting a thread, this method has been
augmented to lazily remove references to dead threads. In
practice, this means that you can be a little sloppy and
occasionally forget to call {@link #remove} before exiting a
thread. However, you must call <code>remove</code> sometime. If
you never call it, then your application is sure to running out of
memory.
*/
static
public
void remove() {
if (ht != null) {
ht.remove(Thread.currentThread());
// Lazily remove dead-thread references in ht.
lazyRemove();
}
}
/**
Set maximum depth of this diagnostic context. If the current
depth is smaller or equal to <code>maxDepth</code>, then no
action is taken.
<p>This method is a convenient alternative to multiple {@link
#pop} calls. Moreover, it is often the case that at the end of
complex call sequences, the depth of the NDC is
unpredictable. The <code>setMaxDepth</code> method circumvents
this problem.
<p>For example, the combination
<pre>
void foo() {
&nbsp; int depth = NDC.getDepth();
&nbsp; ... complex sequence of calls
&nbsp; NDC.setMaxDepth(depth);
}
</pre>
ensures that between the entry and exit of foo the depth of the
diagnostic stack is conserved.
@see #getDepth
@since 0.7.5 */
static
public
void setMaxDepth(int maxDepth) {
Stack stack = getCurrentStack();
if(stack != null && maxDepth < stack.size())
stack.setSize(maxDepth);
}
// =====================================================================
private static class DiagnosticContext {
String fullMessage;
String message;
DiagnosticContext(String message, DiagnosticContext parent) {
this.message = message;
if(parent != null) {
fullMessage = parent.fullMessage + ' ' + message;
} else {
fullMessage = message;
}
}
}
}

View File

@@ -1,511 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.helpers.PatternConverter;
// Contributors: Nelson Minar <nelson@monkey.org>
// Anders Kristensen <akristensen@dynamicsoft.com>
/**
A flexible layout configurable with pattern string.
This code is known to have synchronization and other issues
which are not present in org.apache.log4j.EnhancedPatternLayout.
EnhancedPatternLayout should be used in preference to PatternLayout.
EnhancedPatternLayout is distributed in the log4j extras companion.
<p>The goal of this class is to {@link #format format} a {@link
LoggingEvent} and return the results as a String. The results
depend on the <em>conversion pattern</em>.
<p>The conversion pattern is closely related to the conversion
pattern of the printf function in C. A conversion pattern is
composed of literal text and format control expressions called
<em>conversion specifiers</em>.
<p><i>You are free to insert any literal text within the conversion
pattern.</i>
<p>Each conversion specifier starts with a percent sign (%) and is
followed by optional <em>format modifiers</em> and a <em>conversion
character</em>. The conversion character specifies the type of
data, e.g. category, priority, date, thread name. The format
modifiers control such things as field width, padding, left and
right justification. The following is a simple example.
<p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
that the log4j environment was set to use a PatternLayout. Then the
statements
<pre>
Category root = Category.getRoot();
root.debug("Message 1");
root.warn("Message 2");
</pre>
would yield the output
<pre>
DEBUG [main]: Message 1
WARN [main]: Message 2
</pre>
<p>Note that there is no explicit separator between text and
conversion specifiers. The pattern parser knows when it has reached
the end of a conversion specifier when it reads a conversion
character. In the example above the conversion specifier
<b>%-5p</b> means the priority of the logging event should be left
justified to a width of five characters.
The recognized conversion characters are
<p>
<table border="1" CELLPADDING="8">
<th>Conversion Character</th>
<th>Effect</th>
<tr>
<td align=center><b>c</b></td>
<td>Used to output the category of the logging event. The
category conversion specifier can be optionally followed by
<em>precision specifier</em>, that is a decimal constant in
brackets.
<p>If a precision specifier is given, then only the corresponding
number of right most components of the category name will be
printed. By default the category name is printed in full.
<p>For example, for the category name "a.b.c" the pattern
<b>%c{2}</b> will output "b.c".
</td>
</tr>
<tr>
<td align=center><b>C</b></td>
<td>Used to output the fully qualified class name of the caller
issuing the logging request. This conversion specifier
can be optionally followed by <em>precision specifier</em>, that
is a decimal constant in brackets.
<p>If a precision specifier is given, then only the corresponding
number of right most components of the class name will be
printed. By default the class name is output in fully qualified form.
<p>For example, for the class name "org.apache.xyz.SomeClass", the
pattern <b>%C{1}</b> will output "SomeClass".
<p><b>WARNING</b> Generating the caller class information is
slow. Thus, use should be avoided unless execution speed is
not an issue.
</td>
</tr>
<tr> <td align=center><b>d</b></td> <td>Used to output the date of
the logging event. The date conversion specifier may be
followed by a <em>date format specifier</em> enclosed between
braces. For example, <b>%d{HH:mm:ss,SSS}</b> or
<b>%d{dd&nbsp;MMM&nbsp;yyyy&nbsp;HH:mm:ss,SSS}</b>. If no
date format specifier is given then ISO8601 format is
assumed.
<p>The date format specifier admits the same syntax as the
time pattern string of the {@link
java.text.SimpleDateFormat}. Although part of the standard
JDK, the performance of <code>SimpleDateFormat</code> is
quite poor.
<p>For better results it is recommended to use the log4j date
formatters. These can be specified using one of the strings
"ABSOLUTE", "DATE" and "ISO8601" for specifying {@link
org.apache.log4j.helpers.AbsoluteTimeDateFormat
AbsoluteTimeDateFormat}, {@link
org.apache.log4j.helpers.DateTimeDateFormat DateTimeDateFormat}
and respectively {@link
org.apache.log4j.helpers.ISO8601DateFormat
ISO8601DateFormat}. For example, <b>%d{ISO8601}</b> or
<b>%d{ABSOLUTE}</b>.
<p>These dedicated date formatters perform significantly
better than {@link java.text.SimpleDateFormat}.
</td>
</tr>
<tr>
<td align=center><b>F</b></td>
<td>Used to output the file name where the logging request was
issued.
<p><b>WARNING</b> Generating caller location information is
extremely slow and should be avoided unless execution speed
is not an issue.
</tr>
<tr>
<td align=center><b>l</b></td>
<td>Used to output location information of the caller which generated
the logging event.
<p>The location information depends on the JVM implementation but
usually consists of the fully qualified name of the calling
method followed by the callers source the file name and line
number between parentheses.
<p>The location information can be very useful. However, its
generation is <em>extremely</em> slow and should be avoided
unless execution speed is not an issue.
</td>
</tr>
<tr>
<td align=center><b>L</b></td>
<td>Used to output the line number from where the logging request
was issued.
<p><b>WARNING</b> Generating caller location information is
extremely slow and should be avoided unless execution speed
is not an issue.
</tr>
<tr>
<td align=center><b>m</b></td>
<td>Used to output the application supplied message associated with
the logging event.</td>
</tr>
<tr>
<td align=center><b>M</b></td>
<td>Used to output the method name where the logging request was
issued.
<p><b>WARNING</b> Generating caller location information is
extremely slow and should be avoided unless execution speed
is not an issue.
</tr>
<tr>
<td align=center><b>n</b></td>
<td>Outputs the platform dependent line separator character or
characters.
<p>This conversion character offers practically the same
performance as using non-portable line separator strings such as
"\n", or "\r\n". Thus, it is the preferred way of specifying a
line separator.
</tr>
<tr>
<td align=center><b>p</b></td>
<td>Used to output the priority of the logging event.</td>
</tr>
<tr>
<td align=center><b>r</b></td>
<td>Used to output the number of milliseconds elapsed from the construction
of the layout until the creation of the logging event.</td>
</tr>
<tr>
<td align=center><b>t</b></td>
<td>Used to output the name of the thread that generated the
logging event.</td>
</tr>
<tr>
<td align=center><b>x</b></td>
<td>Used to output the NDC (nested diagnostic context) associated
with the thread that generated the logging event.
</td>
</tr>
<tr>
<td align=center><b>X</b></td>
<td>
<p>Used to output the MDC (mapped diagnostic context) associated
with the thread that generated the logging event. The <b>X</b>
conversion character <em>must</em> be followed by the key for the
map placed between braces, as in <b>%X{clientNumber}</b> where
<code>clientNumber</code> is the key. The value in the MDC
corresponding to the key will be output.</p>
<p>See {@link MDC} class for more details.
</p>
</td>
</tr>
<tr>
<td align=center><b>%</b></td>
<td>The sequence %% outputs a single percent sign.
</td>
</tr>
</table>
<p>By default the relevant information is output as is. However,
with the aid of format modifiers it is possible to change the
minimum field width, the maximum field width and justification.
<p>The optional format modifier is placed between the percent sign
and the conversion character.
<p>The first optional format modifier is the <em>left justification
flag</em> which is just the minus (-) character. Then comes the
optional <em>minimum field width</em> modifier. This is a decimal
constant that represents the minimum number of characters to
output. If the data item requires fewer characters, it is padded on
either the left or the right until the minimum width is
reached. The default is to pad on the left (right justify) but you
can specify right padding with the left justification flag. The
padding character is space. If the data item is larger than the
minimum field width, the field is expanded to accommodate the
data. The value is never truncated.
<p>This behavior can be changed using the <em>maximum field
width</em> modifier which is designated by a period followed by a
decimal constant. If the data item is longer than the maximum
field, then the extra characters are removed from the
<em>beginning</em> of the data item and not from the end. For
example, it the maximum field width is eight and the data item is
ten characters long, then the first two characters of the data item
are dropped. This behavior deviates from the printf function in C
where truncation is done from the end.
<p>Below are various format modifier examples for the category
conversion specifier.
<p>
<TABLE BORDER=1 CELLPADDING=8>
<th>Format modifier
<th>left justify
<th>minimum width
<th>maximum width
<th>comment
<tr>
<td align=center>%20c</td>
<td align=center>false</td>
<td align=center>20</td>
<td align=center>none</td>
<td>Left pad with spaces if the category name is less than 20
characters long.
<tr> <td align=center>%-20c</td> <td align=center>true</td> <td
align=center>20</td> <td align=center>none</td> <td>Right pad with
spaces if the category name is less than 20 characters long.
<tr>
<td align=center>%.30c</td>
<td align=center>NA</td>
<td align=center>none</td>
<td align=center>30</td>
<td>Truncate from the beginning if the category name is longer than 30
characters.
<tr>
<td align=center>%20.30c</td>
<td align=center>false</td>
<td align=center>20</td>
<td align=center>30</td>
<td>Left pad with spaces if the category name is shorter than 20
characters. However, if category name is longer than 30 characters,
then truncate from the beginning.
<tr>
<td align=center>%-20.30c</td>
<td align=center>true</td>
<td align=center>20</td>
<td align=center>30</td>
<td>Right pad with spaces if the category name is shorter than 20
characters. However, if category name is longer than 30 characters,
then truncate from the beginning.
</table>
<p>Below are some examples of conversion patterns.
<dl>
<p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
<p><dd>This is essentially the TTCC layout.
<p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
<p><dd>Similar to the TTCC layout except that the relative time is
right padded if less than 6 digits, thread name is right padded if
less than 15 characters and truncated if longer and the category
name is left padded if shorter than 30 characters and truncated if
longer.
</dl>
<p>The above text is largely inspired from Peter A. Darnell and
Philip E. Margolis' highly recommended book "C -- a Software
Engineering Approach", ISBN 0-387-97389-3.
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
@author Ceki G&uuml;lc&uuml;
@since 0.8.2 */
public class PatternLayout extends Layout {
/** Default pattern string for log output. Currently set to the
string <b>"%m%n"</b> which just prints the application supplied
message. */
public final static String DEFAULT_CONVERSION_PATTERN ="%m%n";
/** A conversion pattern equivalent to the TTCCCLayout.
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
public final static String TTCC_CONVERSION_PATTERN
= "%r [%t] %p %c %x - %m%n";
protected final int BUF_SIZE = 256;
protected final int MAX_CAPACITY = 1024;
// output buffer appended to when format() is invoked
private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
private String pattern;
private PatternConverter head;
/**
Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
The default pattern just produces the application supplied message.
*/
public PatternLayout() {
this(DEFAULT_CONVERSION_PATTERN);
}
/**
Constructs a PatternLayout using the supplied conversion pattern.
*/
public PatternLayout(String pattern) {
this.pattern = pattern;
head = createPatternParser((pattern == null) ? DEFAULT_CONVERSION_PATTERN :
pattern).parse();
}
/**
Set the <b>ConversionPattern</b> option. This is the string which
controls formatting and consists of a mix of literal content and
conversion specifiers.
*/
public
void setConversionPattern(String conversionPattern) {
pattern = conversionPattern;
head = createPatternParser(conversionPattern).parse();
}
/**
Returns the value of the <b>ConversionPattern</b> option.
*/
public
String getConversionPattern() {
return pattern;
}
/**
Does not do anything as options become effective
*/
public
void activateOptions() {
// nothing to do.
}
/**
The PatternLayout does not handle the throwable contained within
{@link LoggingEvent LoggingEvents}. Thus, it returns
<code>true</code>.
@since 0.8.4 */
public
boolean ignoresThrowable() {
return true;
}
/**
Returns PatternParser used to parse the conversion string. Subclasses
may override this to return a subclass of PatternParser which recognize
custom conversion characters.
@since 0.9.0
*/
protected PatternParser createPatternParser(String pattern) {
return new PatternParser(pattern);
}
/**
Produces a formatted string as specified by the conversion pattern.
*/
public String format(LoggingEvent event) {
// Reset working stringbuffer
if(sbuf.capacity() > MAX_CAPACITY) {
sbuf = new StringBuffer(BUF_SIZE);
} else {
sbuf.setLength(0);
}
PatternConverter c = head;
while(c != null) {
c.format(sbuf, event);
c = c.next;
}
return sbuf.toString();
}
}

View File

@@ -1,193 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Kitching Simon <Simon.Kitching@orange.ch>
package org.apache.log4j;
/**
<font color="#AA4444">Refrain from using this class directly, use
the {@link Level} class instead</font>.
@author Ceki G&uuml;lc&uuml; */
public class Priority {
transient int level;
transient String levelStr;
transient int syslogEquivalent;
public final static int OFF_INT = Integer.MAX_VALUE;
public final static int FATAL_INT = 50000;
public final static int ERROR_INT = 40000;
public final static int WARN_INT = 30000;
public final static int INFO_INT = 20000;
public final static int DEBUG_INT = 10000;
//public final static int FINE_INT = DEBUG_INT;
public final static int ALL_INT = Integer.MIN_VALUE;
/**
* @deprecated Use {@link Level#FATAL} instead.
*/
final static public Priority FATAL = new Level(FATAL_INT, "FATAL", 0);
/**
* @deprecated Use {@link Level#ERROR} instead.
*/
final static public Priority ERROR = new Level(ERROR_INT, "ERROR", 3);
/**
* @deprecated Use {@link Level#WARN} instead.
*/
final static public Priority WARN = new Level(WARN_INT, "WARN", 4);
/**
* @deprecated Use {@link Level#INFO} instead.
*/
final static public Priority INFO = new Level(INFO_INT, "INFO", 6);
/**
* @deprecated Use {@link Level#DEBUG} instead.
*/
final static public Priority DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
/**
* Default constructor for deserialization.
*/
protected Priority() {
level = DEBUG_INT;
levelStr = "DEBUG";
syslogEquivalent = 7;
}
/**
Instantiate a level object.
*/
protected
Priority(int level, String levelStr, int syslogEquivalent) {
this.level = level;
this.levelStr = levelStr;
this.syslogEquivalent = syslogEquivalent;
}
/**
Two priorities are equal if their level fields are equal.
@since 1.2
*/
public
boolean equals(Object o) {
if(o instanceof Priority) {
Priority r = (Priority) o;
return (this.level == r.level);
} else {
return false;
}
}
/**
Return the syslog equivalent of this priority as an integer.
*/
public
final
int getSyslogEquivalent() {
return syslogEquivalent;
}
/**
Returns <code>true</code> if this level has a higher or equal
level than the level passed as argument, <code>false</code>
otherwise.
<p>You should think twice before overriding the default
implementation of <code>isGreaterOrEqual</code> method.
*/
public
boolean isGreaterOrEqual(Priority r) {
return level >= r.level;
}
/**
Return all possible priorities as an array of Level objects in
descending order.
@deprecated This method will be removed with no replacement.
*/
public
static
Priority[] getAllPossiblePriorities() {
return new Priority[] {Priority.FATAL, Priority.ERROR, Level.WARN,
Priority.INFO, Priority.DEBUG};
}
/**
Returns the string representation of this priority.
*/
final
public
String toString() {
return levelStr;
}
/**
Returns the integer representation of this level.
*/
public
final
int toInt() {
return level;
}
/**
* @deprecated Please use the {@link Level#toLevel(String)} method instead.
*/
public
static
Priority toPriority(String sArg) {
return Level.toLevel(sArg);
}
/**
* @deprecated Please use the {@link Level#toLevel(int)} method instead.
*/
public
static
Priority toPriority(int val) {
return toPriority(val, Priority.DEBUG);
}
/**
* @deprecated Please use the {@link Level#toLevel(int, Level)} method instead.
*/
public
static
Priority toPriority(int val, Priority defaultPriority) {
return Level.toLevel(val, (Level) defaultPriority);
}
/**
* @deprecated Please use the {@link Level#toLevel(String, Level)} method instead.
*/
public
static
Priority toPriority(String sArg, Priority defaultPriority) {
return Level.toLevel(sArg, (Level) defaultPriority);
}
}

View File

@@ -1,963 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contibutors: "Luke Blanshard" <Luke@quiq.com>
// "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
// Anders Kristensen <akristensen@dynamicsoft.com>
package org.apache.log4j;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Iterator;
import java.util.Map;
import org.apache.log4j.config.PropertySetter;
import org.apache.log4j.helpers.FileWatchdog;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.or.RendererMap;
import org.apache.log4j.spi.Configurator;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggerFactory;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.OptionHandler;
import org.apache.log4j.spi.RendererSupport;
import org.apache.log4j.spi.ThrowableRenderer;
import org.apache.log4j.spi.ThrowableRendererSupport;
import org.apache.log4j.spi.ErrorHandler;
/**
Allows the configuration of log4j from an external file. See
<b>{@link #doConfigure(String, LoggerRepository)}</b> for the
expected format.
<p>It is sometimes useful to see how log4j is reading configuration
files. You can enable log4j internal logging by defining the
<b>log4j.debug</b> variable.
<P>As of log4j version 0.8.5, at class initialization time class,
the file <b>log4j.properties</b> will be searched from the search
path used to load classes. If the file can be found, then it will
be fed to the {@link PropertyConfigurator#configure(java.net.URL)}
method.
<p>The <code>PropertyConfigurator</code> does not handle the
advanced configuration features supported by the {@link
org.apache.log4j.xml.DOMConfigurator DOMConfigurator} such as
support custom {@link org.apache.log4j.spi.ErrorHandler ErrorHandlers},
nested appenders such as the {@link org.apache.log4j.AsyncAppender
AsyncAppender}, etc.
<p>All option <em>values</em> admit variable substitution. The
syntax of variable substitution is similar to that of Unix
shells. The string between an opening <b>&quot;${&quot;</b> and
closing <b>&quot;}&quot;</b> is interpreted as a key. The value of
the substituted variable can be defined as a system property or in
the configuration file itself. The value of the key is first
searched in the system properties, and if not found there, it is
then searched in the configuration file being parsed. The
corresponding value replaces the ${variableName} sequence. For
example, if <code>java.home</code> system property is set to
<code>/home/xyz</code>, then every occurrence of the sequence
<code>${java.home}</code> will be interpreted as
<code>/home/xyz</code>.
@author Ceki G&uuml;lc&uuml;
@author Anders Kristensen
@since 0.8.1 */
public class PropertyConfigurator implements Configurator {
/**
Used internally to keep track of configured appenders.
*/
protected Hashtable registry = new Hashtable(11);
private LoggerRepository repository;
protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
static final String CATEGORY_PREFIX = "log4j.category.";
static final String LOGGER_PREFIX = "log4j.logger.";
static final String FACTORY_PREFIX = "log4j.factory";
static final String ADDITIVITY_PREFIX = "log4j.additivity.";
static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
static final String APPENDER_PREFIX = "log4j.appender.";
static final String RENDERER_PREFIX = "log4j.renderer.";
static final String THRESHOLD_PREFIX = "log4j.threshold";
private static final String THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
private static final String LOGGER_REF = "logger-ref";
private static final String ROOT_REF = "root-ref";
private static final String APPENDER_REF_TAG = "appender-ref";
/** Key for specifying the {@link org.apache.log4j.spi.LoggerFactory
LoggerFactory}. Currently set to "<code>log4j.loggerFactory</code>". */
public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
/**
* If property set to true, then hierarchy will be reset before configuration.
*/
private static final String RESET_KEY = "log4j.reset";
static final private String INTERNAL_ROOT_NAME = "root";
/**
Read configuration from a file. <b>The existing configuration is
not cleared nor reset.</b> If you require a different behavior,
then call {@link LogManager#resetConfiguration
resetConfiguration} method before calling
<code>doConfigure</code>.
<p>The configuration file consists of statements in the format
<code>key=value</code>. The syntax of different configuration
elements are discussed below.
<h3>Repository-wide threshold</h3>
<p>The repository-wide threshold filters logging requests by level
regardless of logger. The syntax is:
<pre>
log4j.threshold=[level]
</pre>
<p>The level value can consist of the string values OFF, FATAL,
ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
custom level value can be specified in the form
level#classname. By default the repository-wide threshold is set
to the lowest possible value, namely the level <code>ALL</code>.
</p>
<h3>Appender configuration</h3>
<p>Appender configuration syntax is:
<pre>
# For appender named <i>appenderName</i>, set its class.
# Note: The appender name can contain dots.
log4j.appender.appenderName=fully.qualified.name.of.appender.class
# Set appender specific options.
log4j.appender.appenderName.option1=value1
...
log4j.appender.appenderName.optionN=valueN
</pre>
For each named appender you can configure its {@link Layout}. The
syntax for configuring an appender's layout is:
<pre>
log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1=value1
....
log4j.appender.appenderName.layout.optionN=valueN
</pre>
The syntax for adding {@link Filter}s to an appender is:
<pre>
log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
log4j.appender.appenderName.filter.ID.option1=value1
...
log4j.appender.appenderName.filter.ID.optionN=valueN
</pre>
The first line defines the class name of the filter identified by ID;
subsequent lines with the same ID specify filter option - value
paris. Multiple filters are added to the appender in the lexicographic
order of IDs.
The syntax for adding an {@link ErrorHandler} to an appender is:
<pre>
log4j.appender.appenderName.errorhandler=fully.qualified.name.of.filter.class
log4j.appender.appenderName.errorhandler.root-ref={true|false}
log4j.appender.appenderName.errorhandler.logger-ref=loggerName
log4j.appender.appenderName.errorhandler.appender-ref=appenderName
log4j.appender.appenderName.errorhandler.option1=value1
...
log4j.appender.appenderName.errorhandler.optionN=valueN
</pre>
<h3>Configuring loggers</h3>
<p>The syntax for configuring the root logger is:
<pre>
log4j.rootLogger=[level], appenderName, appenderName, ...
</pre>
<p>This syntax means that an optional <em>level</em> can be
supplied followed by appender names separated by commas.
<p>The level value can consist of the string values OFF, FATAL,
ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
custom level value can be specified in the form
<code>level#classname</code>.
<p>If a level value is specified, then the root level is set
to the corresponding level. If no level value is specified,
then the root level remains untouched.
<p>The root logger can be assigned multiple appenders.
<p>Each <i>appenderName</i> (separated by commas) will be added to
the root logger. The named appender is defined using the
appender syntax defined above.
<p>For non-root categories the syntax is almost the same:
<pre>
log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
</pre>
<p>The meaning of the optional level value is discussed above
in relation to the root logger. In addition however, the value
INHERITED can be specified meaning that the named logger should
inherit its level from the logger hierarchy.
<p>If no level value is supplied, then the level of the
named logger remains untouched.
<p>By default categories inherit their level from the
hierarchy. However, if you set the level of a logger and later
decide that that logger should inherit its level, then you should
specify INHERITED as the value for the level value. NULL is a
synonym for INHERITED.
<p>Similar to the root logger syntax, each <i>appenderName</i>
(separated by commas) will be attached to the named logger.
<p>See the <a href="../../../../manual.html#additivity">appender
additivity rule</a> in the user manual for the meaning of the
<code>additivity</code> flag.
<h3>ObjectRenderers</h3>
You can customize the way message objects of a given type are
converted to String before being logged. This is done by
specifying an {@link org.apache.log4j.or.ObjectRenderer ObjectRenderer}
for the object type would like to customize.
<p>The syntax is:
<pre>
log4j.renderer.fully.qualified.name.of.rendered.class=fully.qualified.name.of.rendering.class
</pre>
As in,
<pre>
log4j.renderer.my.Fruit=my.FruitRenderer
</pre>
<h3>ThrowableRenderer</h3>
You can customize the way an instance of Throwable is
converted to String before being logged. This is done by
specifying an {@link org.apache.log4j.spi.ThrowableRenderer ThrowableRenderer}.
<p>The syntax is:
<pre>
log4j.throwableRenderer=fully.qualified.name.of.rendering.class
log4j.throwableRenderer.paramName=paramValue
</pre>
As in,
<pre>
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
</pre>
<h3>Logger Factories</h3>
The usage of custom logger factories is discouraged and no longer
documented.
<h3>Resetting Hierarchy</h3>
The hierarchy will be reset before configuration when
log4j.reset=true is present in the properties file.
<h3>Example</h3>
<p>An example configuration is given below. Other configuration
file examples are given in the <code>examples</code> folder.
<pre>
# Set options for appender named "A1".
# Appender "A1" will be a SyslogAppender
log4j.appender.A1=org.apache.log4j.net.SyslogAppender
# The syslog daemon resides on www.abc.net
log4j.appender.A1.SyslogHost=www.abc.net
# A1's layout is a PatternLayout, using the conversion pattern
# <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
# include # the relative time since the start of the application in
# milliseconds, followed by the level of the log request,
# followed by the two rightmost components of the logger name,
# followed by the callers method name, followed by the line number,
# the nested disgnostic context and finally the message itself.
# Refer to the documentation of {@link PatternLayout} for further information
# on the syntax of the ConversionPattern key.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
# Set options for appender named "A2"
# A2 should be a RollingFileAppender, with maximum file size of 10 MB
# using at most one backup file. A2's layout is TTCC, using the
# ISO8061 date format with context printing enabled.
log4j.appender.A2=org.apache.log4j.RollingFileAppender
log4j.appender.A2.MaxFileSize=10MB
log4j.appender.A2.MaxBackupIndex=1
log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
log4j.appender.A2.layout.ContextPrinting=enabled
log4j.appender.A2.layout.DateFormat=ISO8601
# Root logger set to DEBUG using the A2 appender defined above.
log4j.rootLogger=DEBUG, A2
# Logger definitions:
# The SECURITY logger inherits is level from root. However, it's output
# will go to A1 appender defined above. It's additivity is non-cumulative.
log4j.logger.SECURITY=INHERIT, A1
log4j.additivity.SECURITY=false
# Only warnings or above will be logged for the logger "SECURITY.access".
# Output will go to A1.
log4j.logger.SECURITY.access=WARN
# The logger "class.of.the.day" inherits its level from the
# logger hierarchy. Output will go to the appender's of the root
# logger, A2 in this case.
log4j.logger.class.of.the.day=INHERIT
</pre>
<p>Refer to the <b>setOption</b> method in each Appender and
Layout for class specific options.
<p>Use the <code>#</code> or <code>!</code> characters at the
beginning of a line for comments.
<p>
@param configFileName The name of the configuration file where the
configuration information is stored.
*/
public
void doConfigure(String configFileName, LoggerRepository hierarchy) {
Properties props = new Properties();
FileInputStream istream = null;
try {
istream = new FileInputStream(configFileName);
props.load(istream);
istream.close();
}
catch (Exception e) {
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
LogLog.error("Could not read configuration file ["+configFileName+"].", e);
LogLog.error("Ignoring configuration file [" + configFileName+"].");
return;
} finally {
if(istream != null) {
try {
istream.close();
} catch(InterruptedIOException ignore) {
Thread.currentThread().interrupt();
} catch(Throwable ignore) {
}
}
}
// If we reach here, then the config file is alright.
doConfigure(props, hierarchy);
}
/**
*/
static
public
void configure(String configFilename) {
new PropertyConfigurator().doConfigure(configFilename,
LogManager.getLoggerRepository());
}
/**
Read configuration options from url <code>configURL</code>.
@since 0.8.2
*/
public
static
void configure(java.net.URL configURL) {
new PropertyConfigurator().doConfigure(configURL,
LogManager.getLoggerRepository());
}
/**
Read configuration options from <code>properties</code>.
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
*/
static
public
void configure(Properties properties) {
new PropertyConfigurator().doConfigure(properties,
LogManager.getLoggerRepository());
}
/**
Like {@link #configureAndWatch(String, long)} except that the
default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
used.
@param configFilename A file in key=value format.
*/
static
public
void configureAndWatch(String configFilename) {
configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
}
/**
Read the configuration file <code>configFilename</code> if it
exists. Moreover, a thread will be created that will periodically
check if <code>configFilename</code> has been created or
modified. The period is determined by the <code>delay</code>
argument. If a change or file creation is detected, then
<code>configFilename</code> is read to configure log4j.
@param configFilename A file in key=value format.
@param delay The delay in milliseconds to wait between each check.
*/
static
public
void configureAndWatch(String configFilename, long delay) {
PropertyWatchdog pdog = new PropertyWatchdog(configFilename);
pdog.setDelay(delay);
pdog.start();
}
/**
Read configuration options from <code>properties</code>.
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
*/
public
void doConfigure(Properties properties, LoggerRepository hierarchy) {
repository = hierarchy;
String value = properties.getProperty(LogLog.DEBUG_KEY);
if(value == null) {
value = properties.getProperty("log4j.configDebug");
if(value != null)
LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
}
if(value != null) {
LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
}
//
// if log4j.reset=true then
// reset hierarchy
String reset = properties.getProperty(RESET_KEY);
if (reset != null && OptionConverter.toBoolean(reset, false)) {
hierarchy.resetConfiguration();
}
String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
properties);
if(thresholdStr != null) {
hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
(Level) Level.ALL));
LogLog.debug("Hierarchy threshold set to ["+hierarchy.getThreshold()+"].");
}
configureRootCategory(properties, hierarchy);
configureLoggerFactory(properties);
parseCatsAndRenderers(properties, hierarchy);
LogLog.debug("Finished configuring.");
// We don't want to hold references to appenders preventing their
// garbage collection.
registry.clear();
}
/**
Read configuration options from url <code>configURL</code>.
*/
public
void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
Properties props = new Properties();
LogLog.debug("Reading configuration from URL " + configURL);
InputStream istream = null;
URLConnection uConn = null;
try {
uConn = configURL.openConnection();
uConn.setUseCaches(false);
istream = uConn.getInputStream();
props.load(istream);
}
catch (Exception e) {
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
LogLog.error("Could not read configuration file from URL [" + configURL
+ "].", e);
LogLog.error("Ignoring configuration file [" + configURL +"].");
return;
}
finally {
if (istream != null) {
try {
istream.close();
} catch(InterruptedIOException ignore) {
Thread.currentThread().interrupt();
} catch(IOException ignore) {
} catch(RuntimeException ignore) {
}
}
}
doConfigure(props, hierarchy);
}
// --------------------------------------------------------------------------
// Internal stuff
// --------------------------------------------------------------------------
/**
Check the provided <code>Properties</code> object for a
{@link org.apache.log4j.spi.LoggerFactory LoggerFactory}
entry specified by {@link #LOGGER_FACTORY_KEY}. If such an entry
exists, an attempt is made to create an instance using the default
constructor. This instance is used for subsequent Category creations
within this configurator.
@see #parseCatsAndRenderers
*/
protected void configureLoggerFactory(Properties props) {
String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY,
props);
if(factoryClassName != null) {
LogLog.debug("Setting category factory to ["+factoryClassName+"].");
loggerFactory = (LoggerFactory)
OptionConverter.instantiateByClassName(factoryClassName,
LoggerFactory.class,
loggerFactory);
PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
}
}
/*
void configureOptionHandler(OptionHandler oh, String prefix,
Properties props) {
String[] options = oh.getOptionStrings();
if(options == null)
return;
String value;
for(int i = 0; i < options.length; i++) {
value = OptionConverter.findAndSubst(prefix + options[i], props);
LogLog.debug(
"Option " + options[i] + "=[" + (value == null? "N/A" : value)+"].");
// Some option handlers assume that null value are not passed to them.
// So don't remove this check
if(value != null) {
oh.setOption(options[i], value);
}
}
oh.activateOptions();
}
*/
void configureRootCategory(Properties props, LoggerRepository hierarchy) {
String effectiveFrefix = ROOT_LOGGER_PREFIX;
String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
if(value == null) {
value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
effectiveFrefix = ROOT_CATEGORY_PREFIX;
}
if(value == null)
LogLog.debug("Could not find root logger information. Is this OK?");
else {
Logger root = hierarchy.getRootLogger();
synchronized(root) {
parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
}
}
}
/**
Parse non-root elements, such non-root categories and renderers.
*/
protected
void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) {
Enumeration enumeration = props.propertyNames();
while(enumeration.hasMoreElements()) {
String key = (String) enumeration.nextElement();
if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
String loggerName = null;
if(key.startsWith(CATEGORY_PREFIX)) {
loggerName = key.substring(CATEGORY_PREFIX.length());
} else if(key.startsWith(LOGGER_PREFIX)) {
loggerName = key.substring(LOGGER_PREFIX.length());
}
String value = OptionConverter.findAndSubst(key, props);
Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
synchronized(logger) {
parseCategory(props, logger, key, loggerName, value);
parseAdditivityForLogger(props, logger, loggerName);
}
} else if(key.startsWith(RENDERER_PREFIX)) {
String renderedClass = key.substring(RENDERER_PREFIX.length());
String renderingClass = OptionConverter.findAndSubst(key, props);
if(hierarchy instanceof RendererSupport) {
RendererMap.addRenderer((RendererSupport) hierarchy, renderedClass,
renderingClass);
}
} else if (key.equals(THROWABLE_RENDERER_PREFIX)) {
if (hierarchy instanceof ThrowableRendererSupport) {
ThrowableRenderer tr = (ThrowableRenderer)
OptionConverter.instantiateByKey(props,
THROWABLE_RENDERER_PREFIX,
org.apache.log4j.spi.ThrowableRenderer.class,
null);
if(tr == null) {
LogLog.error(
"Could not instantiate throwableRenderer.");
} else {
PropertySetter setter = new PropertySetter(tr);
setter.setProperties(props, THROWABLE_RENDERER_PREFIX + ".");
((ThrowableRendererSupport) hierarchy).setThrowableRenderer(tr);
}
}
}
}
}
/**
Parse the additivity option for a non-root category.
*/
void parseAdditivityForLogger(Properties props, Logger cat,
String loggerName) {
String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX + loggerName,
props);
LogLog.debug("Handling "+ADDITIVITY_PREFIX + loggerName+"=["+value+"]");
// touch additivity only if necessary
if((value != null) && (!value.equals(""))) {
boolean additivity = OptionConverter.toBoolean(value, true);
LogLog.debug("Setting additivity for \""+loggerName+"\" to "+
additivity);
cat.setAdditivity(additivity);
}
}
/**
This method must work for the root category as well.
*/
void parseCategory(Properties props, Logger logger, String optionKey,
String loggerName, String value) {
LogLog.debug("Parsing for [" +loggerName +"] with value=[" + value+"].");
// We must skip over ',' but not white space
StringTokenizer st = new StringTokenizer(value, ",");
// If value is not in the form ", appender.." or "", then we should set
// the level of the loggeregory.
if(!(value.startsWith(",") || value.equals(""))) {
// just to be on the safe side...
if(!st.hasMoreTokens())
return;
String levelStr = st.nextToken();
LogLog.debug("Level token is [" + levelStr + "].");
// If the level value is inherited, set category level value to
// null. We also check that the user has not specified inherited for the
// root category.
if(INHERITED.equalsIgnoreCase(levelStr) ||
NULL.equalsIgnoreCase(levelStr)) {
if(loggerName.equals(INTERNAL_ROOT_NAME)) {
LogLog.warn("The root logger cannot be set to null.");
} else {
logger.setLevel(null);
}
} else {
logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
}
LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
}
// Begin by removing all existing appenders.
logger.removeAllAppenders();
Appender appender;
String appenderName;
while(st.hasMoreTokens()) {
appenderName = st.nextToken().trim();
if(appenderName == null || appenderName.equals(","))
continue;
LogLog.debug("Parsing appender named \"" + appenderName +"\".");
appender = parseAppender(props, appenderName);
if(appender != null) {
logger.addAppender(appender);
}
}
}
Appender parseAppender(Properties props, String appenderName) {
Appender appender = registryGet(appenderName);
if((appender != null)) {
LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
return appender;
}
// Appender was not previously initialized.
String prefix = APPENDER_PREFIX + appenderName;
String layoutPrefix = prefix + ".layout";
appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
org.apache.log4j.Appender.class,
null);
if(appender == null) {
LogLog.error(
"Could not instantiate appender named \"" + appenderName+"\".");
return null;
}
appender.setName(appenderName);
if(appender instanceof OptionHandler) {
if(appender.requiresLayout()) {
Layout layout = (Layout) OptionConverter.instantiateByKey(props,
layoutPrefix,
Layout.class,
null);
if(layout != null) {
appender.setLayout(layout);
LogLog.debug("Parsing layout options for \"" + appenderName +"\".");
//configureOptionHandler(layout, layoutPrefix + ".", props);
PropertySetter.setProperties(layout, props, layoutPrefix + ".");
LogLog.debug("End of parsing for \"" + appenderName +"\".");
}
}
final String errorHandlerPrefix = prefix + ".errorhandler";
String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
if (errorHandlerClass != null) {
ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByKey(props,
errorHandlerPrefix,
ErrorHandler.class,
null);
if (eh != null) {
appender.setErrorHandler(eh);
LogLog.debug("Parsing errorhandler options for \"" + appenderName +"\".");
parseErrorHandler(eh, errorHandlerPrefix, props, repository);
final Properties edited = new Properties();
final String[] keys = new String[] {
errorHandlerPrefix + "." + ROOT_REF,
errorHandlerPrefix + "." + LOGGER_REF,
errorHandlerPrefix + "." + APPENDER_REF_TAG
};
for(Iterator iter = props.entrySet().iterator();iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
int i = 0;
for(; i < keys.length; i++) {
if(keys[i].equals(entry.getKey())) break;
}
if (i == keys.length) {
edited.put(entry.getKey(), entry.getValue());
}
}
PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
LogLog.debug("End of errorhandler parsing for \"" + appenderName +"\".");
}
}
//configureOptionHandler((OptionHandler) appender, prefix + ".", props);
PropertySetter.setProperties(appender, props, prefix + ".");
LogLog.debug("Parsed \"" + appenderName +"\" options.");
}
parseAppenderFilters(props, appenderName, appender);
registryPut(appender);
return appender;
}
private void parseErrorHandler(
final ErrorHandler eh,
final String errorHandlerPrefix,
final Properties props,
final LoggerRepository hierarchy) {
boolean rootRef = OptionConverter.toBoolean(
OptionConverter.findAndSubst(errorHandlerPrefix + ROOT_REF, props), false);
if (rootRef) {
eh.setLogger(hierarchy.getRootLogger());
}
String loggerName = OptionConverter.findAndSubst(errorHandlerPrefix + LOGGER_REF , props);
if (loggerName != null) {
Logger logger = (loggerFactory == null) ? hierarchy.getLogger(loggerName)
: hierarchy.getLogger(loggerName, loggerFactory);
eh.setLogger(logger);
}
String appenderName = OptionConverter.findAndSubst(errorHandlerPrefix + APPENDER_REF_TAG, props);
if (appenderName != null) {
Appender backup = parseAppender(props, appenderName);
if (backup != null) {
eh.setBackupAppender(backup);
}
}
}
void parseAppenderFilters(Properties props, String appenderName, Appender appender) {
// extract filters and filter options from props into a hashtable mapping
// the property name defining the filter class to a list of pre-parsed
// name-value pairs associated to that filter
final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
int fIdx = filterPrefix.length();
Hashtable filters = new Hashtable();
Enumeration e = props.keys();
String name = "";
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
if (key.startsWith(filterPrefix)) {
int dotIdx = key.indexOf('.', fIdx);
String filterKey = key;
if (dotIdx != -1) {
filterKey = key.substring(0, dotIdx);
name = key.substring(dotIdx+1);
}
Vector filterOpts = (Vector) filters.get(filterKey);
if (filterOpts == null) {
filterOpts = new Vector();
filters.put(filterKey, filterOpts);
}
if (dotIdx != -1) {
String value = OptionConverter.findAndSubst(key, props);
filterOpts.add(new NameValue(name, value));
}
}
}
// sort filters by IDs, insantiate filters, set filter options,
// add filters to the appender
Enumeration g = new SortedKeyEnumeration(filters);
while (g.hasMoreElements()) {
String key = (String) g.nextElement();
String clazz = props.getProperty(key);
if (clazz != null) {
LogLog.debug("Filter key: ["+key+"] class: ["+props.getProperty(key) +"] props: "+filters.get(key));
Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null);
if (filter != null) {
PropertySetter propSetter = new PropertySetter(filter);
Vector v = (Vector)filters.get(key);
Enumeration filterProps = v.elements();
while (filterProps.hasMoreElements()) {
NameValue kv = (NameValue)filterProps.nextElement();
propSetter.setProperty(kv.key, kv.value);
}
propSetter.activate();
LogLog.debug("Adding filter of type ["+filter.getClass()
+"] to appender named ["+appender.getName()+"].");
appender.addFilter(filter);
}
} else {
LogLog.warn("Missing class definition for filter: ["+key+"]");
}
}
}
void registryPut(Appender appender) {
registry.put(appender.getName(), appender);
}
Appender registryGet(String name) {
return (Appender) registry.get(name);
}
}
class PropertyWatchdog extends FileWatchdog {
PropertyWatchdog(String filename) {
super(filename);
}
/**
Call {@link PropertyConfigurator#configure(String)} with the
<code>filename</code> to reconfigure log4j. */
public
void doOnChange() {
new PropertyConfigurator().doConfigure(filename,
LogManager.getLoggerRepository());
}
}
class NameValue {
String key, value;
public NameValue(String key, String value) {
this.key = key;
this.value = value;
}
public String toString() {
return key + "=" + value;
}
}
class SortedKeyEnumeration implements Enumeration {
private Enumeration e;
public SortedKeyEnumeration(Hashtable ht) {
Enumeration f = ht.keys();
Vector keys = new Vector(ht.size());
for (int i, last = 0; f.hasMoreElements(); ++last) {
String key = (String) f.nextElement();
for (i = 0; i < last; ++i) {
String s = (String) keys.get(i);
if (key.compareTo(s) <= 0) break;
}
keys.add(i, key);
}
e = keys.elements();
}
public boolean hasMoreElements() {
return e.hasMoreElements();
}
public Object nextElement() {
return e.nextElement();
}
}

View File

@@ -1,29 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.util.Vector;
class ProvisionNode extends Vector {
private static final long serialVersionUID = -4479121426311014469L;
ProvisionNode(Logger logger) {
super();
this.addElement(logger);
}
}

View File

@@ -1,284 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.IOException;
import java.io.Writer;
import java.io.File;
import java.io.InterruptedIOException;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.spi.LoggingEvent;
/**
RollingFileAppender extends FileAppender to backup the log files when
they reach a certain size.
The log4j extras companion includes alternatives which should be considered
for new deployments and which are discussed in the documentation
for org.apache.log4j.rolling.RollingFileAppender.
@author Heinz Richter
@author Ceki G&uuml;lc&uuml;
*/
public class RollingFileAppender extends FileAppender {
/**
The default maximum file size is 10MB.
*/
protected long maxFileSize = 10*1024*1024;
/**
There is one backup file by default.
*/
protected int maxBackupIndex = 1;
private long nextRollover = 0;
/**
The default constructor simply calls its {@link
FileAppender#FileAppender parents constructor}. */
public
RollingFileAppender() {
super();
}
/**
Instantiate a RollingFileAppender and open the file designated by
<code>filename</code>. The opened filename will become the ouput
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file desginated by
<code>filename</code> will be truncated before being opened.
*/
public
RollingFileAppender(Layout layout, String filename, boolean append)
throws IOException {
super(layout, filename, append);
}
/**
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>The file will be appended to. */
public
RollingFileAppender(Layout layout, String filename) throws IOException {
super(layout, filename);
}
/**
Returns the value of the <b>MaxBackupIndex</b> option.
*/
public
int getMaxBackupIndex() {
return maxBackupIndex;
}
/**
Get the maximum size that the output file is allowed to reach
before being rolled over to backup files.
@since 1.1
*/
public
long getMaximumFileSize() {
return maxFileSize;
}
/**
Implements the usual roll over behaviour.
<p>If <code>MaxBackupIndex</code> is positive, then files
{<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
are renamed to {<code>File.2</code>, ...,
<code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
renamed <code>File.1</code> and closed. A new <code>File</code> is
created to receive further log output.
<p>If <code>MaxBackupIndex</code> is equal to zero, then the
<code>File</code> is truncated with no backup files created.
*/
public // synchronization not necessary since doAppend is alreasy synched
void rollOver() {
File target;
File file;
if (qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
LogLog.debug("rolling over count=" + size);
// if operation fails, do not roll again until
// maxFileSize more bytes are written
nextRollover = size + maxFileSize;
}
LogLog.debug("maxBackupIndex="+maxBackupIndex);
boolean renameSucceeded = true;
// If maxBackups <= 0, then there is no file renaming to be done.
if(maxBackupIndex > 0) {
// Delete the oldest file, to keep Windows happy.
file = new File(fileName + '.' + maxBackupIndex);
if (file.exists())
renameSucceeded = file.delete();
// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
file = new File(fileName + "." + i);
if (file.exists()) {
target = new File(fileName + '.' + (i + 1));
LogLog.debug("Renaming file " + file + " to " + target);
renameSucceeded = file.renameTo(target);
}
}
if(renameSucceeded) {
// Rename fileName to fileName.1
target = new File(fileName + "." + 1);
this.closeFile(); // keep windows happy.
file = new File(fileName);
LogLog.debug("Renaming file " + file + " to " + target);
renameSucceeded = file.renameTo(target);
//
// if file rename failed, reopen file with append = true
//
if (!renameSucceeded) {
try {
this.setFile(fileName, true, bufferedIO, bufferSize);
}
catch(IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("setFile("+fileName+", true) call failed.", e);
}
}
}
}
//
// if all renames were successful, then
//
if (renameSucceeded) {
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
this.setFile(fileName, false, bufferedIO, bufferSize);
nextRollover = 0;
}
catch(IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("setFile("+fileName+", false) call failed.", e);
}
}
}
public
synchronized
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
throws IOException {
super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
if(append) {
File f = new File(fileName);
((CountingQuietWriter) qw).setCount(f.length());
}
}
/**
Set the maximum number of backup files to keep around.
<p>The <b>MaxBackupIndex</b> option determines how many backup
files are kept before the oldest is erased. This option takes
a positive integer value. If set to zero, then there will be no
backup files and the log file will be truncated when it reaches
<code>MaxFileSize</code>.
*/
public
void setMaxBackupIndex(int maxBackups) {
this.maxBackupIndex = maxBackups;
}
/**
Set the maximum size that the output file is allowed to reach
before being rolled over to backup files.
<p>This method is equivalent to {@link #setMaxFileSize} except
that it is required for differentiating the setter taking a
<code>long</code> argument from the setter taking a
<code>String</code> argument by the JavaBeans {@link
java.beans.Introspector Introspector}.
@see #setMaxFileSize(String)
*/
public
void setMaximumFileSize(long maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
Set the maximum size that the output file is allowed to reach
before being rolled over to backup files.
<p>In configuration files, the <b>MaxFileSize</b> option takes an
long integer in the range 0 - 2^63. You can specify the value
with the suffixes "KB", "MB" or "GB" so that the integer is
interpreted being expressed respectively in kilobytes, megabytes
or gigabytes. For example, the value "10KB" will be interpreted
as 10240.
*/
public
void setMaxFileSize(String value) {
maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
}
protected
void setQWForFiles(Writer writer) {
this.qw = new CountingQuietWriter(writer, errorHandler);
}
/**
This method differentiates RollingFileAppender from its super
class.
@since 0.9.0
*/
protected
void subAppend(LoggingEvent event) {
super.subAppend(event);
if(fileName != null && qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size >= maxFileSize && size >= nextRollover) {
rollOver();
}
}
}
}

View File

@@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import org.apache.log4j.spi.LoggingEvent;
/**
SimpleLayout consists of the level of the log statement,
followed by " - " and then the log message itself. For example,
<pre>
DEBUG - Hello world
</pre>
<p>
@author Ceki G&uuml;lc&uuml;
@since version 0.7.0
<p>{@link PatternLayout} offers a much more powerful alternative.
*/
public class SimpleLayout extends Layout {
StringBuffer sbuf = new StringBuffer(128);
public SimpleLayout() {
}
public
void activateOptions() {
}
/**
Returns the log statement in a format consisting of the
<code>level</code>, followed by " - " and then the
<code>message</code>. For example, <pre> INFO - "A message"
</pre>
<p>The <code>category</code> parameter is ignored.
<p>
@return A byte array in SimpleLayout format.
*/
public
String format(LoggingEvent event) {
sbuf.setLength(0);
sbuf.append(event.getLevel().toString());
sbuf.append(" - ");
sbuf.append(event.getRenderedMessage());
sbuf.append(LINE_SEP);
return sbuf.toString();
}
/**
The SimpleLayout does not handle the throwable contained within
{@link LoggingEvent LoggingEvents}. Thus, it returns
<code>true</code>.
@since version 0.8.4 */
public
boolean ignoresThrowable() {
return true;
}
}

View File

@@ -1,217 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Christopher Williams
// Mathias Bogaert
package org.apache.log4j;
import org.apache.log4j.helpers.DateLayout;
import org.apache.log4j.spi.LoggingEvent;
/**
TTCC layout format consists of time, thread, category and nested
diagnostic context information, hence the name.
<p>Each of the four fields can be individually enabled or
disabled. The time format depends on the <code>DateFormat</code>
used.
<p>Here is an example TTCCLayout output with the
{@link org.apache.log4j.helpers.RelativeTimeDateFormat}.
<pre>
176 [main] INFO org.apache.log4j.examples.Sort - Populating an array of 2 elements in reverse order.
225 [main] INFO org.apache.log4j.examples.SortAlgo - Entered the sort method.
262 [main] DEBUG org.apache.log4j.examples.SortAlgo.OUTER i=1 - Outer loop.
276 [main] DEBUG org.apache.log4j.examples.SortAlgo.SWAP i=1 j=0 - Swapping intArray[0] = 1 and intArray[1] = 0
290 [main] DEBUG org.apache.log4j.examples.SortAlgo.OUTER i=0 - Outer loop.
304 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Dump of interger array:
317 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Element [0] = 0
331 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Element [1] = 1
343 [main] INFO org.apache.log4j.examples.Sort - The next log statement should be an error message.
346 [main] ERROR org.apache.log4j.examples.SortAlgo.DUMP - Tried to dump an uninitialized array.
at org.apache.log4j.examples.SortAlgo.dump(SortAlgo.java:58)
at org.apache.log4j.examples.Sort.main(Sort.java:64)
467 [main] INFO org.apache.log4j.examples.Sort - Exiting main method.
</pre>
<p>The first field is the number of milliseconds elapsed since the
start of the program. The second field is the thread outputting the
log statement. The third field is the level, the fourth field is
the category to which the statement belongs.
<p>The fifth field (just before the '-') is the nested diagnostic
context. Note the nested diagnostic context may be empty as in the
first two statements. The text after the '-' is the message of the
statement.
<p><b>WARNING</b> Do not use the same TTCCLayout instance from
within different appenders. The TTCCLayout is not thread safe when
used in his way. However, it is perfectly safe to use a TTCCLayout
instance from just one appender.
<p>{@link PatternLayout} offers a much more flexible alternative.
@author Ceki G&uuml;lc&uuml;
@author <A HREF="mailto:heinz.richter@ecmwf.int">Heinz Richter</a>
*/
public class TTCCLayout extends DateLayout {
// Internal representation of options
private boolean threadPrinting = true;
private boolean categoryPrefixing = true;
private boolean contextPrinting = true;
protected final StringBuffer buf = new StringBuffer(256);
/**
Instantiate a TTCCLayout object with {@link
org.apache.log4j.helpers.RelativeTimeDateFormat} as the date
formatter in the local time zone.
@since 0.7.5 */
public TTCCLayout() {
this.setDateFormat(RELATIVE_TIME_DATE_FORMAT, null);
}
/**
Instantiate a TTCCLayout object using the local time zone. The
DateFormat used will depend on the <code>dateFormatType</code>.
<p>This constructor just calls the {@link
DateLayout#setDateFormat} method.
*/
public TTCCLayout(String dateFormatType) {
this.setDateFormat(dateFormatType);
}
/**
The <b>ThreadPrinting</b> option specifies whether the name of the
current thread is part of log output or not. This is true by default.
*/
public
void setThreadPrinting(boolean threadPrinting) {
this.threadPrinting = threadPrinting;
}
/**
Returns value of the <b>ThreadPrinting</b> option.
*/
public
boolean getThreadPrinting() {
return threadPrinting;
}
/**
The <b>CategoryPrefixing</b> option specifies whether {@link Category}
name is part of log output or not. This is true by default.
*/
public
void setCategoryPrefixing(boolean categoryPrefixing) {
this.categoryPrefixing = categoryPrefixing;
}
/**
Returns value of the <b>CategoryPrefixing</b> option.
*/
public
boolean getCategoryPrefixing() {
return categoryPrefixing;
}
/**
The <b>ContextPrinting</b> option specifies log output will include
the nested context information belonging to the current thread.
This is true by default.
*/
public
void setContextPrinting(boolean contextPrinting) {
this.contextPrinting = contextPrinting;
}
/**
Returns value of the <b>ContextPrinting</b> option.
*/
public
boolean getContextPrinting() {
return contextPrinting;
}
/**
In addition to the level of the statement and message, the
returned byte array includes time, thread, category and {@link NDC}
information.
<p>Time, thread, category and diagnostic context are printed
depending on options.
@param event The event to format
*/
public
String format(LoggingEvent event) {
// Reset buf
buf.setLength(0);
dateFormat(buf, event);
if(this.threadPrinting) {
buf.append('[');
buf.append(event.getThreadName());
buf.append("] ");
}
buf.append(event.getLevel().toString());
buf.append(' ');
if(this.categoryPrefixing) {
buf.append(event.getLoggerName());
buf.append(' ');
}
if(this.contextPrinting) {
String ndc = event.getNDC();
if(ndc != null) {
buf.append(ndc);
buf.append(' ');
}
}
buf.append("- ");
buf.append(event.getRenderedMessage());
buf.append(LINE_SEP);
return buf.toString();
}
/**
The TTCCLayout does not handle the throwable contained within
{@link LoggingEvent LoggingEvents}. Thus, it returns
<code>true</code>.
@since version 0.8.4 */
public
boolean ignoresThrowable() {
return true;
}
}

View File

@@ -1,387 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.LoggingEvent;
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
// Ben Sandee
/**
WriterAppender appends log events to a {@link java.io.Writer} or an
{@link java.io.OutputStream} depending on the user's choice.
@author Ceki G&uuml;lc&uuml;
@since 1.1 */
public class WriterAppender extends AppenderSkeleton {
/**
Immediate flush means that the underlying writer or output stream
will be flushed at the end of each append operation unless shouldFlush()
is overridden. Immediate
flush is slower but ensures that each append request is actually
written. If <code>immediateFlush</code> is set to
<code>false</code>, then there is a good chance that the last few
logs events are not actually written to persistent media if and
when the application crashes.
<p>The <code>immediateFlush</code> variable is set to
<code>true</code> by default.
*/
protected boolean immediateFlush = true;
/**
The encoding to use when writing. <p>The
<code>encoding</code> variable is set to <code>null</null> by
default which results in the utilization of the system's default
encoding. */
protected String encoding;
/**
This is the {@link QuietWriter quietWriter} where we will write
to.
*/
protected QuietWriter qw;
/**
This default constructor does nothing. */
public
WriterAppender() {
}
/**
Instantiate a WriterAppender and set the output destination to a
new {@link OutputStreamWriter} initialized with <code>os</code>
as its {@link OutputStream}. */
public
WriterAppender(Layout layout, OutputStream os) {
this(layout, new OutputStreamWriter(os));
}
/**
Instantiate a WriterAppender and set the output destination to
<code>writer</code>.
<p>The <code>writer</code> must have been previously opened by
the user. */
public
WriterAppender(Layout layout, Writer writer) {
this.layout = layout;
this.setWriter(writer);
}
/**
If the <b>ImmediateFlush</b> option is set to
<code>true</code>, the appender will flush at the end of each
write. This is the default behavior. If the option is set to
<code>false</code>, then the underlying stream can defer writing
to physical medium to a later time.
<p>Avoiding the flush operation at the end of each append results in
a performance gain of 10 to 20 percent. However, there is safety
tradeoff involved in skipping flushing. Indeed, when flushing is
skipped, then it is likely that the last few log events will not
be recorded on disk when the application exits. This is a high
price to pay even for a 20% performance gain.
*/
public
void setImmediateFlush(boolean value) {
immediateFlush = value;
}
/**
Returns value of the <b>ImmediateFlush</b> option.
*/
public
boolean getImmediateFlush() {
return immediateFlush;
}
/**
Does nothing.
*/
public
void activateOptions() {
}
/**
This method is called by the {@link AppenderSkeleton#doAppend}
method.
<p>If the output stream exists and is writable then write a log
statement to the output stream. Otherwise, write a single warning
message to <code>System.err</code>.
<p>The format of the output will depend on this appender's
layout.
*/
public
void append(LoggingEvent event) {
// Reminder: the nesting of calls is:
//
// doAppend()
// - check threshold
// - filter
// - append();
// - checkEntryConditions();
// - subAppend();
if(!checkEntryConditions()) {
return;
}
subAppend(event);
}
/**
This method determines if there is a sense in attempting to append.
<p>It checks whether there is a set output target and also if
there is a set layout. If these checks fail, then the boolean
value <code>false</code> is returned. */
protected
boolean checkEntryConditions() {
if(this.closed) {
LogLog.warn("Not allowed to write to a closed appender.");
return false;
}
if(this.qw == null) {
errorHandler.error("No output stream or file set for the appender named ["+
name+"].");
return false;
}
if(this.layout == null) {
errorHandler.error("No layout set for the appender named ["+ name+"].");
return false;
}
return true;
}
/**
Close this appender instance. The underlying stream or writer is
also closed.
<p>Closed appenders cannot be reused.
@see #setWriter
@since 0.8.4 */
public
synchronized
void close() {
if(this.closed)
return;
this.closed = true;
writeFooter();
reset();
}
/**
* Close the underlying {@link java.io.Writer}.
* */
protected void closeWriter() {
if(qw != null) {
try {
qw.close();
} catch(IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
// There is do need to invoke an error handler at this late
// stage.
LogLog.error("Could not close " + qw, e);
}
}
}
/**
Returns an OutputStreamWriter when passed an OutputStream. The
encoding used will depend on the value of the
<code>encoding</code> property. If the encoding value is
specified incorrectly the writer will be opened using the default
system encoding (an error message will be printed to the loglog. */
protected
OutputStreamWriter createWriter(OutputStream os) {
OutputStreamWriter retval = null;
String enc = getEncoding();
if(enc != null) {
try {
retval = new OutputStreamWriter(os, enc);
} catch(IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.warn("Error initializing output writer.");
LogLog.warn("Unsupported encoding?");
}
}
if(retval == null) {
retval = new OutputStreamWriter(os);
}
return retval;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String value) {
encoding = value;
}
/**
Set the {@link ErrorHandler} for this WriterAppender and also the
underlying {@link QuietWriter} if any. */
public synchronized void setErrorHandler(ErrorHandler eh) {
if(eh == null) {
LogLog.warn("You have tried to set a null error-handler.");
} else {
this.errorHandler = eh;
if(this.qw != null) {
this.qw.setErrorHandler(eh);
}
}
}
/**
<p>Sets the Writer where the log output will go. The
specified Writer must be opened by the user and be
writable.
<p>The <code>java.io.Writer</code> will be closed when the
appender instance is closed.
<p><b>WARNING:</b> Logging to an unopened Writer will fail.
<p>
@param writer An already opened Writer. */
public synchronized void setWriter(Writer writer) {
reset();
this.qw = new QuietWriter(writer, errorHandler);
//this.tp = new TracerPrintWriter(qw);
writeHeader();
}
/**
Actual writing occurs here.
<p>Most subclasses of <code>WriterAppender</code> will need to
override this method.
@since 0.9.0 */
protected
void subAppend(LoggingEvent event) {
this.qw.write(this.layout.format(event));
if(layout.ignoresThrowable()) {
String[] s = event.getThrowableStrRep();
if (s != null) {
int len = s.length;
for(int i = 0; i < len; i++) {
this.qw.write(s[i]);
this.qw.write(Layout.LINE_SEP);
}
}
}
if(shouldFlush(event)) {
this.qw.flush();
}
}
/**
The WriterAppender requires a layout. Hence, this method returns
<code>true</code>.
*/
public
boolean requiresLayout() {
return true;
}
/**
Clear internal references to the writer and other variables.
Subclasses can override this method for an alternate closing
behavior. */
protected
void reset() {
closeWriter();
this.qw = null;
//this.tp = null;
}
/**
Write a footer as produced by the embedded layout's {@link
Layout#getFooter} method. */
protected
void writeFooter() {
if(layout != null) {
String f = layout.getFooter();
if(f != null && this.qw != null) {
this.qw.write(f);
this.qw.flush();
}
}
}
/**
Write a header as produced by the embedded layout's {@link
Layout#getHeader} method. */
protected
void writeHeader() {
if(layout != null) {
String h = layout.getHeader();
if(h != null && this.qw != null)
this.qw.write(h);
}
}
/**
* Determines whether the writer should be flushed after
* this event is written.
*
* @since 1.2.16
*/
protected boolean shouldFlush(final LoggingEvent event) {
return immediateFlush;
}
}

View File

@@ -1,222 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;
import org.apache.log4j.Level;
/**
* Represents the controls for filtering, pausing, exiting, etc.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
class ControlPanel extends JPanel {
/** use the log messages **/
private static final Logger LOG =
Logger.getLogger(ControlPanel.class);
/**
* Creates a new <code>ControlPanel</code> instance.
*
* @param aModel the model to control
*/
ControlPanel(final MyTableModel aModel) {
setBorder(BorderFactory.createTitledBorder("Controls: "));
final GridBagLayout gridbag = new GridBagLayout();
final GridBagConstraints c = new GridBagConstraints();
setLayout(gridbag);
// Pad everything
c.ipadx = 5;
c.ipady = 5;
// Add the 1st column of labels
c.gridx = 0;
c.anchor = GridBagConstraints.EAST;
c.gridy = 0;
JLabel label = new JLabel("Filter Level:");
gridbag.setConstraints(label, c);
add(label);
c.gridy++;
label = new JLabel("Filter Thread:");
gridbag.setConstraints(label, c);
add(label);
c.gridy++;
label = new JLabel("Filter Logger:");
gridbag.setConstraints(label, c);
add(label);
c.gridy++;
label = new JLabel("Filter NDC:");
gridbag.setConstraints(label, c);
add(label);
c.gridy++;
label = new JLabel("Filter Message:");
gridbag.setConstraints(label, c);
add(label);
// Add the 2nd column of filters
c.weightx = 1;
//c.weighty = 1;
c.gridx = 1;
c.anchor = GridBagConstraints.WEST;
c.gridy = 0;
final Level[] allPriorities = new Level[] {Level.FATAL,
Level.ERROR,
Level.WARN,
Level.INFO,
Level.DEBUG,
Level.TRACE };
final JComboBox priorities = new JComboBox(allPriorities);
final Level lowest = allPriorities[allPriorities.length - 1];
priorities.setSelectedItem(lowest);
aModel.setPriorityFilter(lowest);
gridbag.setConstraints(priorities, c);
add(priorities);
priorities.setEditable(false);
priorities.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
aModel.setPriorityFilter(
(Priority) priorities.getSelectedItem());
}
});
c.fill = GridBagConstraints.HORIZONTAL;
c.gridy++;
final JTextField threadField = new JTextField("");
threadField.getDocument().addDocumentListener(new DocumentListener () {
public void insertUpdate(DocumentEvent aEvent) {
aModel.setThreadFilter(threadField.getText());
}
public void removeUpdate(DocumentEvent aEvente) {
aModel.setThreadFilter(threadField.getText());
}
public void changedUpdate(DocumentEvent aEvent) {
aModel.setThreadFilter(threadField.getText());
}
});
gridbag.setConstraints(threadField, c);
add(threadField);
c.gridy++;
final JTextField catField = new JTextField("");
catField.getDocument().addDocumentListener(new DocumentListener () {
public void insertUpdate(DocumentEvent aEvent) {
aModel.setCategoryFilter(catField.getText());
}
public void removeUpdate(DocumentEvent aEvent) {
aModel.setCategoryFilter(catField.getText());
}
public void changedUpdate(DocumentEvent aEvent) {
aModel.setCategoryFilter(catField.getText());
}
});
gridbag.setConstraints(catField, c);
add(catField);
c.gridy++;
final JTextField ndcField = new JTextField("");
ndcField.getDocument().addDocumentListener(new DocumentListener () {
public void insertUpdate(DocumentEvent aEvent) {
aModel.setNDCFilter(ndcField.getText());
}
public void removeUpdate(DocumentEvent aEvent) {
aModel.setNDCFilter(ndcField.getText());
}
public void changedUpdate(DocumentEvent aEvent) {
aModel.setNDCFilter(ndcField.getText());
}
});
gridbag.setConstraints(ndcField, c);
add(ndcField);
c.gridy++;
final JTextField msgField = new JTextField("");
msgField.getDocument().addDocumentListener(new DocumentListener () {
public void insertUpdate(DocumentEvent aEvent) {
aModel.setMessageFilter(msgField.getText());
}
public void removeUpdate(DocumentEvent aEvent) {
aModel.setMessageFilter(msgField.getText());
}
public void changedUpdate(DocumentEvent aEvent) {
aModel.setMessageFilter(msgField.getText());
}
});
gridbag.setConstraints(msgField, c);
add(msgField);
// Add the 3rd column of buttons
c.weightx = 0;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.EAST;
c.gridx = 2;
c.gridy = 0;
final JButton exitButton = new JButton("Exit");
exitButton.setMnemonic('x');
exitButton.addActionListener(ExitAction.INSTANCE);
gridbag.setConstraints(exitButton, c);
add(exitButton);
c.gridy++;
final JButton clearButton = new JButton("Clear");
clearButton.setMnemonic('c');
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
aModel.clear();
}
});
gridbag.setConstraints(clearButton, c);
add(clearButton);
c.gridy++;
final JButton toggleButton = new JButton("Pause");
toggleButton.setMnemonic('p');
toggleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
aModel.toggle();
toggleButton.setText(
aModel.isPaused() ? "Resume" : "Pause");
}
});
gridbag.setConstraints(toggleButton, c);
add(toggleButton);
}
}

View File

@@ -1,170 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.awt.BorderLayout;
import java.text.MessageFormat;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.log4j.Logger;
/**
* A panel for showing a stack trace.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
class DetailPanel
extends JPanel
implements ListSelectionListener
{
/** used to log events **/
private static final Logger LOG =
Logger.getLogger(DetailPanel.class);
/** used to format the logging event **/
private static final MessageFormat FORMATTER = new MessageFormat(
"<b>Time:</b> <code>{0,time,medium}</code>" +
"&nbsp;&nbsp;<b>Priority:</b> <code>{1}</code>" +
"&nbsp;&nbsp;<b>Thread:</b> <code>{2}</code>" +
"&nbsp;&nbsp;<b>NDC:</b> <code>{3}</code>" +
"<br><b>Logger:</b> <code>{4}</code>" +
"<br><b>Location:</b> <code>{5}</code>" +
"<br><b>Message:</b>" +
"<pre>{6}</pre>" +
"<b>Throwable:</b>" +
"<pre>{7}</pre>");
/** the model for the data to render **/
private final MyTableModel mModel;
/** pane for rendering detail **/
private final JEditorPane mDetails;
/**
* Creates a new <code>DetailPanel</code> instance.
*
* @param aTable the table to listen for selections on
* @param aModel the model backing the table
*/
DetailPanel(JTable aTable, final MyTableModel aModel) {
mModel = aModel;
setLayout(new BorderLayout());
setBorder(BorderFactory.createTitledBorder("Details: "));
mDetails = new JEditorPane();
mDetails.setEditable(false);
mDetails.setContentType("text/html");
add(new JScrollPane(mDetails), BorderLayout.CENTER);
final ListSelectionModel rowSM = aTable.getSelectionModel();
rowSM.addListSelectionListener(this);
}
/** @see ListSelectionListener **/
public void valueChanged(ListSelectionEvent aEvent) {
//Ignore extra messages.
if (aEvent.getValueIsAdjusting()) {
return;
}
final ListSelectionModel lsm = (ListSelectionModel) aEvent.getSource();
if (lsm.isSelectionEmpty()) {
mDetails.setText("Nothing selected");
} else {
final int selectedRow = lsm.getMinSelectionIndex();
final EventDetails e = mModel.getEventDetails(selectedRow);
final Object[] args =
{
new Date(e.getTimeStamp()),
e.getPriority(),
escape(e.getThreadName()),
escape(e.getNDC()),
escape(e.getCategoryName()),
escape(e.getLocationDetails()),
escape(e.getMessage()),
escape(getThrowableStrRep(e))
};
mDetails.setText(FORMATTER.format(args));
mDetails.setCaretPosition(0);
}
}
////////////////////////////////////////////////////////////////////////////
// Private methods
////////////////////////////////////////////////////////////////////////////
/**
* Returns a string representation of a throwable.
*
* @param aEvent contains the throwable information
* @return a <code>String</code> value
*/
private static String getThrowableStrRep(EventDetails aEvent) {
final String[] strs = aEvent.getThrowableStrRep();
if (strs == null) {
return null;
}
final StringBuffer sb = new StringBuffer();
for (int i = 0; i < strs.length; i++) {
sb.append(strs[i]).append("\n");
}
return sb.toString();
}
/**
* Escape &lt;, &gt; &amp; and &quot; as their entities. It is very
* dumb about &amp; handling.
* @param aStr the String to escape.
* @return the escaped String
*/
private String escape(String aStr) {
if (aStr == null) {
return null;
}
final StringBuffer buf = new StringBuffer();
for (int i = 0; i < aStr.length(); i++) {
char c = aStr.charAt(i);
switch (c) {
case '<':
buf.append("&lt;");
break;
case '>':
buf.append("&gt;");
break;
case '\"':
buf.append("&quot;");
break;
case '&':
buf.append("&amp;");
break;
default:
buf.append(c);
break;
}
}
return buf.toString();
}
}

View File

@@ -1,135 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import org.apache.log4j.Priority;
import org.apache.log4j.spi.LoggingEvent;
/**
* Represents the details of a logging event. It is intended to overcome the
* problem that a LoggingEvent cannot be constructed with purely fake data.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
* @version 1.0
*/
class EventDetails {
/** the time of the event **/
private final long mTimeStamp;
/** the priority of the event **/
private final Priority mPriority;
/** the category of the event **/
private final String mCategoryName;
/** the NDC for the event **/
private final String mNDC;
/** the thread for the event **/
private final String mThreadName;
/** the msg for the event **/
private final String mMessage;
/** the throwable details the event **/
private final String[] mThrowableStrRep;
/** the location details for the event **/
private final String mLocationDetails;
/**
* Creates a new <code>EventDetails</code> instance.
* @param aTimeStamp a <code>long</code> value
* @param aPriority a <code>Priority</code> value
* @param aCategoryName a <code>String</code> value
* @param aNDC a <code>String</code> value
* @param aThreadName a <code>String</code> value
* @param aMessage a <code>String</code> value
* @param aThrowableStrRep a <code>String[]</code> value
* @param aLocationDetails a <code>String</code> value
*/
EventDetails(long aTimeStamp,
Priority aPriority,
String aCategoryName,
String aNDC,
String aThreadName,
String aMessage,
String[] aThrowableStrRep,
String aLocationDetails)
{
mTimeStamp = aTimeStamp;
mPriority = aPriority;
mCategoryName = aCategoryName;
mNDC = aNDC;
mThreadName = aThreadName;
mMessage = aMessage;
mThrowableStrRep = aThrowableStrRep;
mLocationDetails = aLocationDetails;
}
/**
* Creates a new <code>EventDetails</code> instance.
*
* @param aEvent a <code>LoggingEvent</code> value
*/
EventDetails(LoggingEvent aEvent) {
this(aEvent.timeStamp,
aEvent.getLevel(),
aEvent.getLoggerName(),
aEvent.getNDC(),
aEvent.getThreadName(),
aEvent.getRenderedMessage(),
aEvent.getThrowableStrRep(),
(aEvent.getLocationInformation() == null)
? null : aEvent.getLocationInformation().fullInfo);
}
/** @see #mTimeStamp **/
long getTimeStamp() {
return mTimeStamp;
}
/** @see #mPriority **/
Priority getPriority() {
return mPriority;
}
/** @see #mCategoryName **/
String getCategoryName() {
return mCategoryName;
}
/** @see #mNDC **/
String getNDC() {
return mNDC;
}
/** @see #mThreadName **/
String getThreadName() {
return mThreadName;
}
/** @see #mMessage **/
String getMessage() {
return mMessage;
}
/** @see #mLocationDetails **/
String getLocationDetails(){
return mLocationDetails;
}
/** @see #mThrowableStrRep **/
String[] getThrowableStrRep() {
return mThrowableStrRep;
}
}

View File

@@ -1,48 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.apache.log4j.Logger;
/**
* Encapsulates the action to exit.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
* @version 1.0
*/
class ExitAction
extends AbstractAction
{
/** use to log messages **/
private static final Logger LOG = Logger.getLogger(ExitAction.class);
/** The instance to share **/
public static final ExitAction INSTANCE = new ExitAction();
/** Stop people creating instances **/
private ExitAction() {}
/**
* Will shutdown the application.
* @param aIgnore ignored
*/
public void actionPerformed(ActionEvent aIgnore) {
LOG.info("shutting down");
System.exit(0);
}
}

View File

@@ -1,139 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.apache.log4j.Logger;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
* Encapsulates the action to load an XML file.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
* @version 1.0
*/
class LoadXMLAction
extends AbstractAction
{
/** use to log messages **/
private static final Logger LOG = Logger.getLogger(LoadXMLAction.class);
/** the parent frame **/
private final JFrame mParent;
/**
* the file chooser - configured to allow only the selection of a
* single file.
*/
private final JFileChooser mChooser = new JFileChooser();
{
mChooser.setMultiSelectionEnabled(false);
mChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
}
/** parser to read XML files **/
private final XMLReader mParser;
/** the content handler **/
private final XMLFileHandler mHandler;
/**
* Creates a new <code>LoadXMLAction</code> instance.
*
* @param aParent the parent frame
* @param aModel the model to add events to
* @exception SAXException if an error occurs
* @throws ParserConfigurationException if an error occurs
*/
LoadXMLAction(JFrame aParent, MyTableModel aModel)
throws SAXException, ParserConfigurationException
{
mParent = aParent;
mHandler = new XMLFileHandler(aModel);
mParser = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
mParser.setContentHandler(mHandler);
}
/**
* Prompts the user for a file to load events from.
* @param aIgnore an <code>ActionEvent</code> value
*/
public void actionPerformed(ActionEvent aIgnore) {
LOG.info("load file called");
if (mChooser.showOpenDialog(mParent) == JFileChooser.APPROVE_OPTION) {
LOG.info("Need to load a file");
final File chosen = mChooser.getSelectedFile();
LOG.info("loading the contents of " + chosen.getAbsolutePath());
try {
final int num = loadFile(chosen.getAbsolutePath());
JOptionPane.showMessageDialog(
mParent,
"Loaded " + num + " events.",
"CHAINSAW",
JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
LOG.warn("caught an exception loading the file", e);
JOptionPane.showMessageDialog(
mParent,
"Error parsing file - " + e.getMessage(),
"CHAINSAW",
JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* Loads the contents of file into the model
*
* @param aFile the file to extract events from
* @return the number of events loaded
* @throws SAXException if an error occurs
* @throws IOException if an error occurs
*/
private int loadFile(String aFile)
throws SAXException, IOException
{
synchronized (mParser) {
// Create a dummy document to parse the file
final StringBuffer buf = new StringBuffer();
buf.append("<?xml version=\"1.0\" standalone=\"yes\"?>\n");
buf.append("<!DOCTYPE log4j:eventSet ");
buf.append("[<!ENTITY data SYSTEM \"file:///");
buf.append(aFile);
buf.append("\">]>\n");
buf.append("<log4j:eventSet xmlns:log4j=\"Claira\">\n");
buf.append("&data;\n");
buf.append("</log4j:eventSet>\n");
final InputSource is =
new InputSource(new StringReader(buf.toString()));
mParser.parse(is);
return mHandler.getNumEvents();
}
}
}

View File

@@ -1,121 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
/**
* A daemon thread the processes connections from a
* <code>org.apache.log4j.net.SocketAppender.html</code>.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
class LoggingReceiver extends Thread {
/** used to log messages **/
private static final Logger LOG = Logger.getLogger(LoggingReceiver.class);
/**
* Helper that actually processes a client connection. It receives events
* and adds them to the supplied model.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
private class Slurper implements Runnable {
/** socket connection to read events from **/
private final Socket mClient;
/**
* Creates a new <code>Slurper</code> instance.
*
* @param aClient socket to receive events from
*/
Slurper(Socket aClient) {
mClient = aClient;
}
/** loops getting the events **/
public void run() {
LOG.debug("Starting to get data");
try {
final ObjectInputStream ois =
new ObjectInputStream(mClient.getInputStream());
while (true) {
final LoggingEvent event = (LoggingEvent) ois.readObject();
mModel.addEvent(new EventDetails(event));
}
} catch (EOFException e) {
LOG.info("Reached EOF, closing connection");
} catch (SocketException e) {
LOG.info("Caught SocketException, closing connection");
} catch (IOException e) {
LOG.warn("Got IOException, closing connection", e);
} catch (ClassNotFoundException e) {
LOG.warn("Got ClassNotFoundException, closing connection", e);
}
try {
mClient.close();
} catch (IOException e) {
LOG.warn("Error closing connection", e);
}
}
}
/** where to put the events **/
private MyTableModel mModel;
/** server for listening for connections **/
private ServerSocket mSvrSock;
/**
* Creates a new <code>LoggingReceiver</code> instance.
*
* @param aModel model to place put received into
* @param aPort port to listen on
* @throws IOException if an error occurs
*/
LoggingReceiver(MyTableModel aModel, int aPort) throws IOException {
setDaemon(true);
mModel = aModel;
mSvrSock = new ServerSocket(aPort);
}
/** Listens for client connections **/
public void run() {
LOG.info("Thread started");
try {
while (true) {
LOG.debug("Waiting for a connection");
final Socket client = mSvrSock.accept();
LOG.debug("Got a connection from " +
client.getInetAddress().getHostName());
final Thread t = new Thread(new Slurper(client));
t.setDaemon(true);
t.start();
}
} catch (IOException e) {
LOG.error("Error in accepting connections, stopping.", e);
}
}
}

View File

@@ -1,192 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Properties;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
/**
* The main application.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
public class Main
extends JFrame
{
/** the default port number to listen on **/
private static final int DEFAULT_PORT = 4445;
/** name of property for port name **/
public static final String PORT_PROP_NAME = "chainsaw.port";
/** use to log messages **/
private static final Logger LOG = Logger.getLogger(Main.class);
/**
* Creates a new <code>NetworkClient</code> instance.
*/
private Main() {
super("CHAINSAW - Log4J Log Viewer");
// create the all important model
final MyTableModel model = new MyTableModel();
//Create the menu bar.
final JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
final JMenu menu = new JMenu("File");
menuBar.add(menu);
try {
final LoadXMLAction lxa = new LoadXMLAction(this, model);
final JMenuItem loadMenuItem = new JMenuItem("Load file...");
menu.add(loadMenuItem);
loadMenuItem.addActionListener(lxa);
} catch (NoClassDefFoundError e) {
LOG.info("Missing classes for XML parser", e);
JOptionPane.showMessageDialog(
this,
"XML parser not in classpath - unable to load XML events.",
"CHAINSAW",
JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
LOG.info("Unable to create the action to load XML files", e);
JOptionPane.showMessageDialog(
this,
"Unable to create a XML parser - unable to load XML events.",
"CHAINSAW",
JOptionPane.ERROR_MESSAGE);
}
final JMenuItem exitMenuItem = new JMenuItem("Exit");
menu.add(exitMenuItem);
exitMenuItem.addActionListener(ExitAction.INSTANCE);
// Add control panel
final ControlPanel cp = new ControlPanel(model);
getContentPane().add(cp, BorderLayout.NORTH);
// Create the table
final JTable table = new JTable(model);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
scrollPane.setPreferredSize(new Dimension(900, 300));
// Create the details
final JPanel details = new DetailPanel(table, model);
details.setPreferredSize(new Dimension(900, 300));
// Add the table and stack trace into a splitter
final JSplitPane jsp =
new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
getContentPane().add(jsp, BorderLayout.CENTER);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent aEvent) {
ExitAction.INSTANCE.actionPerformed(null);
}
});
pack();
setVisible(true);
setupReceiver(model);
}
/**
* Setup recieving messages.
*
* @param aModel a <code>MyTableModel</code> value
*/
private void setupReceiver(MyTableModel aModel) {
int port = DEFAULT_PORT;
final String strRep = System.getProperty(PORT_PROP_NAME);
if (strRep != null) {
try {
port = Integer.parseInt(strRep);
} catch (NumberFormatException nfe) {
LOG.fatal("Unable to parse " + PORT_PROP_NAME +
" property with value " + strRep + ".");
JOptionPane.showMessageDialog(
this,
"Unable to parse port number from '" + strRep +
"', quitting.",
"CHAINSAW",
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
try {
final LoggingReceiver lr = new LoggingReceiver(aModel, port);
lr.start();
} catch (IOException e) {
LOG.fatal("Unable to connect to socket server, quiting", e);
JOptionPane.showMessageDialog(
this,
"Unable to create socket on port " + port + ", quitting.",
"CHAINSAW",
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
////////////////////////////////////////////////////////////////////////////
// static methods
////////////////////////////////////////////////////////////////////////////
/** initialise log4j **/
private static void initLog4J() {
final Properties props = new Properties();
props.setProperty("log4j.rootLogger", "DEBUG, A1");
props.setProperty("log4j.appender.A1",
"org.apache.log4j.ConsoleAppender");
props.setProperty("log4j.appender.A1.layout",
"org.apache.log4j.TTCCLayout");
PropertyConfigurator.configure(props);
}
/**
* The main method.
*
* @param aArgs ignored
*/
public static void main(String[] aArgs) {
initLog4J();
new Main();
}
}

View File

@@ -1,390 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Priority;
import org.apache.log4j.Logger;
/**
* Represents a list of <code>EventDetails</code> objects that are sorted on
* logging time. Methods are provided to filter the events that are visible.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
class MyTableModel
extends AbstractTableModel
{
/** used to log messages **/
private static final Logger LOG = Logger.getLogger(MyTableModel.class);
/** use the compare logging events **/
private static final Comparator MY_COMP = new Comparator()
{
/** @see Comparator **/
public int compare(Object aObj1, Object aObj2) {
if ((aObj1 == null) && (aObj2 == null)) {
return 0; // treat as equal
} else if (aObj1 == null) {
return -1; // null less than everything
} else if (aObj2 == null) {
return 1; // think about it. :->
}
// will assume only have LoggingEvent
final EventDetails le1 = (EventDetails) aObj1;
final EventDetails le2 = (EventDetails) aObj2;
if (le1.getTimeStamp() < le2.getTimeStamp()) {
return 1;
}
// assume not two events are logged at exactly the same time
return -1;
}
};
/**
* Helper that actually processes incoming events.
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
private class Processor
implements Runnable
{
/** loops getting the events **/
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore
}
synchronized (mLock) {
if (mPaused) {
continue;
}
boolean toHead = true; // were events added to head
boolean needUpdate = false;
final Iterator it = mPendingEvents.iterator();
while (it.hasNext()) {
final EventDetails event = (EventDetails) it.next();
mAllEvents.add(event);
toHead = toHead && (event == mAllEvents.first());
needUpdate = needUpdate || matchFilter(event);
}
mPendingEvents.clear();
if (needUpdate) {
updateFilteredEvents(toHead);
}
}
}
}
}
/** names of the columns in the table **/
private static final String[] COL_NAMES = {
"Time", "Priority", "Trace", "Category", "NDC", "Message"};
/** definition of an empty list **/
private static final EventDetails[] EMPTY_LIST = new EventDetails[] {};
/** used to format dates **/
private static final DateFormat DATE_FORMATTER =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
/** the lock to control access **/
private final Object mLock = new Object();
/** set of all logged events - not filtered **/
private final SortedSet mAllEvents = new TreeSet(MY_COMP);
/** events that are visible after filtering **/
private EventDetails[] mFilteredEvents = EMPTY_LIST;
/** list of events that are buffered for processing **/
private final List mPendingEvents = new ArrayList();
/** indicates whether event collection is paused to the UI **/
private boolean mPaused = false;
/** filter for the thread **/
private String mThreadFilter = "";
/** filter for the message **/
private String mMessageFilter = "";
/** filter for the NDC **/
private String mNDCFilter = "";
/** filter for the category **/
private String mCategoryFilter = "";
/** filter for the priority **/
private Priority mPriorityFilter = Priority.DEBUG;
/**
* Creates a new <code>MyTableModel</code> instance.
*
*/
MyTableModel() {
final Thread t = new Thread(new Processor());
t.setDaemon(true);
t.start();
}
////////////////////////////////////////////////////////////////////////////
// Table Methods
////////////////////////////////////////////////////////////////////////////
/** @see javax.swing.table.TableModel **/
public int getRowCount() {
synchronized (mLock) {
return mFilteredEvents.length;
}
}
/** @see javax.swing.table.TableModel **/
public int getColumnCount() {
// does not need to be synchronized
return COL_NAMES.length;
}
/** @see javax.swing.table.TableModel **/
public String getColumnName(int aCol) {
// does not need to be synchronized
return COL_NAMES[aCol];
}
/** @see javax.swing.table.TableModel **/
public Class getColumnClass(int aCol) {
// does not need to be synchronized
return (aCol == 2) ? Boolean.class : Object.class;
}
/** @see javax.swing.table.TableModel **/
public Object getValueAt(int aRow, int aCol) {
synchronized (mLock) {
final EventDetails event = mFilteredEvents[aRow];
if (aCol == 0) {
return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
} else if (aCol == 1) {
return event.getPriority();
} else if (aCol == 2) {
return (event.getThrowableStrRep() == null)
? Boolean.FALSE : Boolean.TRUE;
} else if (aCol == 3) {
return event.getCategoryName();
} else if (aCol == 4) {
return event.getNDC();
}
return event.getMessage();
}
}
////////////////////////////////////////////////////////////////////////////
// Public Methods
////////////////////////////////////////////////////////////////////////////
/**
* Sets the priority to filter events on. Only events of equal or higher
* property are now displayed.
*
* @param aPriority the priority to filter on
*/
public void setPriorityFilter(Priority aPriority) {
synchronized (mLock) {
mPriorityFilter = aPriority;
updateFilteredEvents(false);
}
}
/**
* Set the filter for the thread field.
*
* @param aStr the string to match
*/
public void setThreadFilter(String aStr) {
synchronized (mLock) {
mThreadFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the message field.
*
* @param aStr the string to match
*/
public void setMessageFilter(String aStr) {
synchronized (mLock) {
mMessageFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the NDC field.
*
* @param aStr the string to match
*/
public void setNDCFilter(String aStr) {
synchronized (mLock) {
mNDCFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the category field.
*
* @param aStr the string to match
*/
public void setCategoryFilter(String aStr) {
synchronized (mLock) {
mCategoryFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Add an event to the list.
*
* @param aEvent a <code>EventDetails</code> value
*/
public void addEvent(EventDetails aEvent) {
synchronized (mLock) {
mPendingEvents.add(aEvent);
}
}
/**
* Clear the list of all events.
*/
public void clear() {
synchronized (mLock) {
mAllEvents.clear();
mFilteredEvents = new EventDetails[0];
mPendingEvents.clear();
fireTableDataChanged();
}
}
/** Toggle whether collecting events **/
public void toggle() {
synchronized (mLock) {
mPaused = !mPaused;
}
}
/** @return whether currently paused collecting events **/
public boolean isPaused() {
synchronized (mLock) {
return mPaused;
}
}
/**
* Get the throwable information at a specified row in the filtered events.
*
* @param aRow the row index of the event
* @return the throwable information
*/
public EventDetails getEventDetails(int aRow) {
synchronized (mLock) {
return mFilteredEvents[aRow];
}
}
////////////////////////////////////////////////////////////////////////////
// Private methods
////////////////////////////////////////////////////////////////////////////
/**
* Update the filtered events data structure.
* @param aInsertedToFront indicates whether events were added to front of
* the events. If true, then the current first event must still exist
* in the list after the filter is applied.
*/
private void updateFilteredEvents(boolean aInsertedToFront) {
final long start = System.currentTimeMillis();
final List filtered = new ArrayList();
final int size = mAllEvents.size();
final Iterator it = mAllEvents.iterator();
while (it.hasNext()) {
final EventDetails event = (EventDetails) it.next();
if (matchFilter(event)) {
filtered.add(event);
}
}
final EventDetails lastFirst = (mFilteredEvents.length == 0)
? null
: mFilteredEvents[0];
mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
if (aInsertedToFront && (lastFirst != null)) {
final int index = filtered.indexOf(lastFirst);
if (index < 1) {
LOG.warn("In strange state");
fireTableDataChanged();
} else {
fireTableRowsInserted(0, index - 1);
}
} else {
fireTableDataChanged();
}
final long end = System.currentTimeMillis();
LOG.debug("Total time [ms]: " + (end - start)
+ " in update, size: " + size);
}
/**
* Returns whether an event matches the filters.
*
* @param aEvent the event to check for a match
* @return whether the event matches
*/
private boolean matchFilter(EventDetails aEvent) {
if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
(aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
(aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
((mNDCFilter.length() == 0) ||
((aEvent.getNDC() != null) &&
(aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
{
final String rm = aEvent.getMessage();
if (rm == null) {
// only match if we have not filtering in place
return (mMessageFilter.length() == 0);
} else {
return (rm.indexOf(mMessageFilter) >= 0);
}
}
return false; // by default not match
}
}

View File

@@ -1,170 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.chainsaw;
import java.util.StringTokenizer;
import org.apache.log4j.Level;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A content handler for document containing Log4J events logged using the
* XMLLayout class. It will create events and add them to a supplied model.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
* @version 1.0
*/
class XMLFileHandler
extends DefaultHandler
{
/** represents the event tag **/
private static final String TAG_EVENT = "log4j:event";
/** represents the message tag **/
private static final String TAG_MESSAGE = "log4j:message";
/** represents the ndc tag **/
private static final String TAG_NDC = "log4j:NDC";
/** represents the throwable tag **/
private static final String TAG_THROWABLE = "log4j:throwable";
/** represents the location info tag **/
private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
/** where to put the events **/
private final MyTableModel mModel;
/** the number of events in the document **/
private int mNumEvents;
/** the time of the event **/
private long mTimeStamp;
/** the priority (level) of the event **/
private Level mLevel;
/** the category of the event **/
private String mCategoryName;
/** the NDC for the event **/
private String mNDC;
/** the thread for the event **/
private String mThreadName;
/** the msg for the event **/
private String mMessage;
/** the throwable details the event **/
private String[] mThrowableStrRep;
/** the location details for the event **/
private String mLocationDetails;
/** buffer for collecting text **/
private final StringBuffer mBuf = new StringBuffer();
/**
* Creates a new <code>XMLFileHandler</code> instance.
*
* @param aModel where to add the events
*/
XMLFileHandler(MyTableModel aModel) {
mModel = aModel;
}
/** @see DefaultHandler **/
public void startDocument()
throws SAXException
{
mNumEvents = 0;
}
/** @see DefaultHandler **/
public void characters(char[] aChars, int aStart, int aLength) {
mBuf.append(String.valueOf(aChars, aStart, aLength));
}
/** @see DefaultHandler **/
public void endElement(String aNamespaceURI,
String aLocalName,
String aQName)
{
if (TAG_EVENT.equals(aQName)) {
addEvent();
resetData();
} else if (TAG_NDC.equals(aQName)) {
mNDC = mBuf.toString();
} else if (TAG_MESSAGE.equals(aQName)) {
mMessage = mBuf.toString();
} else if (TAG_THROWABLE.equals(aQName)) {
final StringTokenizer st =
new StringTokenizer(mBuf.toString(), "\n\t");
mThrowableStrRep = new String[st.countTokens()];
if (mThrowableStrRep.length > 0) {
mThrowableStrRep[0] = st.nextToken();
for (int i = 1; i < mThrowableStrRep.length; i++) {
mThrowableStrRep[i] = "\t" + st.nextToken();
}
}
}
}
/** @see DefaultHandler **/
public void startElement(String aNamespaceURI,
String aLocalName,
String aQName,
Attributes aAtts)
{
mBuf.setLength(0);
if (TAG_EVENT.equals(aQName)) {
mThreadName = aAtts.getValue("thread");
mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
mCategoryName = aAtts.getValue("logger");
mLevel = Level.toLevel(aAtts.getValue("level"));
} else if (TAG_LOCATION_INFO.equals(aQName)) {
mLocationDetails = aAtts.getValue("class") + "."
+ aAtts.getValue("method")
+ "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
+ ")";
}
}
/** @return the number of events in the document **/
int getNumEvents() {
return mNumEvents;
}
////////////////////////////////////////////////////////////////////////////
// Private methods
////////////////////////////////////////////////////////////////////////////
/** Add an event to the model **/
private void addEvent() {
mModel.addEvent(new EventDetails(mTimeStamp,
mLevel,
mCategoryName,
mNDC,
mThreadName,
mMessage,
mThrowableStrRep,
mLocationDetails));
mNumEvents++;
}
/** Reset the data for an event **/
private void resetData() {
mTimeStamp = 0;
mLevel = null;
mCategoryName = null;
mNDC = null;
mThreadName = null;
mMessage = null;
mThrowableStrRep = null;
mLocationDetails = null;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1,118 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<HTML>
<HEAD>
<TITLE>Chainsaw Tool</TITLE>
</head>
<BODY>
<P>Chainsaw is a GUI log viewer and filter for the log4j
package. By default it listens for <a
href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
the <A href="../net/SocketAppender.html">SocketAppender</A> and
displays them in a table. The events can be filtered based on:</P>
<UL>
<LI>Level </li>
<LI>Thread name</li>
<LI>Logger</li>
<LI>Message</li>
<LI>NDC</LI>
</UL>
<P>All the details for each event can be displayed by selecting
the event in the table.</P>
<P>Chainsaw also supports loading a events logged to a file using
the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
is great for analysing log files, and means you do not need to
keep Chainsaw running continously. It is easy to add support
for loading events from other sources like JDBC.</P>
<P>A picture is worth a thousand words: </P>
<P align=center><A
href="doc-files/screen_01.png"><IMG
height="50%" alt="Screen shot of chainsaw"
src="doc-files/screen_01.png"
width="50%"></A>.</P>
<P>Finally, why is it called chainsaw?
Because it cuts your log (file) down to size. :-)
</P>
<H2>Requirements</H2>
<P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
<H2>Running chainsaw</H2>
<H3>Setup</H3>
<P>You need to include the <code>log4j.jar</code> in the classpath.
<H3>Usage</H3>
<P>The command line usage is:</P>
<PRE> java -D&lt;property&gt;=&lt;value&gt; org.apache.log4j.chainsaw.Main </PRE>
<P>The default behaviour of chainsaw can be changed by setting system properties
using the <CODE>-D&lt;property&gt;=&lt;value&gt;</CODE> arguments to java. The
following table describes what properties can be set:</P>
<TABLE cellSpacing=0 cellPadding=2 border=1>
<TR>
<TD vAlign=top><B>Property</B></TD>
<TD vAlign=top><B>Description</B></TD></TR>
<TR>
<TD vAlign=top>chainsaw.port</TD>
<TD vAlign=top>Indicates which port to listen for connections on. Defaults
to <SPAN class=default>"4445"</SPAN>.
</TD>
</TR>
</TBODY>
</TABLE>
<H2>Configuring Log4J</H2>
<P>You will need to configure log4j to send logging events to
Chainsaw. Here is a sample <CODE>log4j.properties</CODE> file
for sending logging events to Chainsaw.</P>
<PRE>
log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
log4j.appender.CHAINSAW_CLIENT.Port=4445
log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
</PRE>
</body>
</html>

View File

@@ -1,108 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.config;
import org.apache.log4j.Priority;
import org.apache.log4j.helpers.LogLog;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.InterruptedIOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
Used for inferring configuration information for a log4j's component.
@author Anders Kristensen
*/
public class PropertyGetter {
protected static final Object[] NULL_ARG = new Object[] {};
protected Object obj;
protected PropertyDescriptor[] props;
public interface PropertyCallback {
void foundProperty(Object obj, String prefix, String name, Object value);
}
/**
Create a new PropertyGetter for the specified Object. This is done
in prepartion for invoking {@link
#getProperties(PropertyGetter.PropertyCallback, String)} one or
more times.
@param obj the object for which to set properties */
public
PropertyGetter(Object obj) throws IntrospectionException {
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
props = bi.getPropertyDescriptors();
this.obj = obj;
}
public
static
void getProperties(Object obj, PropertyCallback callback, String prefix) {
try {
new PropertyGetter(obj).getProperties(callback, prefix);
} catch (IntrospectionException ex) {
LogLog.error("Failed to introspect object " + obj, ex);
}
}
public
void getProperties(PropertyCallback callback, String prefix) {
for (int i = 0; i < props.length; i++) {
Method getter = props[i].getReadMethod();
if (getter == null) continue;
if (!isHandledType(getter.getReturnType())) {
//System.err.println("Ignoring " + props[i].getName() +" " + getter.getReturnType());
continue;
}
String name = props[i].getName();
try {
Object result = getter.invoke(obj, NULL_ARG);
//System.err.println("PROP " + name +": " + result);
if (result != null) {
callback.foundProperty(obj, prefix, name, result);
}
} catch (IllegalAccessException ex) {
LogLog.warn("Failed to get value of property " + name);
} catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof InterruptedException
|| ex.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.warn("Failed to get value of property " + name);
} catch (RuntimeException ex) {
LogLog.warn("Failed to get value of property " + name);
}
}
}
protected
boolean isHandledType(Class type) {
return String.class.isAssignableFrom(type) ||
Integer.TYPE.isAssignableFrom(type) ||
Long.TYPE.isAssignableFrom(type) ||
Boolean.TYPE.isAssignableFrom(type) ||
Priority.class.isAssignableFrom(type);
}
}

View File

@@ -1,168 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.config;
import org.apache.log4j.Appender;
import org.apache.log4j.Category;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Hashtable;
/**
Prints the configuration of the log4j default hierarchy
(which needs to be auto-initialized) as a propoperties file
on a {@link PrintWriter}.
@author Anders Kristensen
*/
public class PropertyPrinter implements PropertyGetter.PropertyCallback {
protected int numAppenders = 0;
protected Hashtable appenderNames = new Hashtable();
protected Hashtable layoutNames = new Hashtable();
protected PrintWriter out;
protected boolean doCapitalize;
public
PropertyPrinter(PrintWriter out) {
this(out, false);
}
public
PropertyPrinter(PrintWriter out, boolean doCapitalize) {
this.out = out;
this.doCapitalize = doCapitalize;
print(out);
out.flush();
}
protected
String genAppName() {
return "A" + numAppenders++;
}
/**
* Returns true if the specified appender name is considered to have
* been generated, that is, if it is of the form A[0-9]+.
*/
protected
boolean isGenAppName(String name) {
if (name.length() < 2 || name.charAt(0) != 'A') return false;
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) < '0' || name.charAt(i) > '9') return false;
}
return true;
}
/**
* Prints the configuration of the default log4j hierarchy as a Java
* properties file on the specified Writer.
*
* <p>N.B. print() can be invoked only once!
*/
public
void print(PrintWriter out) {
printOptions(out, Logger.getRootLogger());
Enumeration cats = LogManager.getCurrentLoggers();
while (cats.hasMoreElements()) {
printOptions(out, (Logger) cats.nextElement());
}
}
/**
* @since 1.2.15
*/
protected
void printOptions(PrintWriter out, Category cat) {
Enumeration appenders = cat.getAllAppenders();
Level prio = cat.getLevel();
String appenderString = (prio == null ? "" : prio.toString());
while (appenders.hasMoreElements()) {
Appender app = (Appender) appenders.nextElement();
String name;
if ((name = (String) appenderNames.get(app)) == null) {
// first assign name to the appender
if ((name = app.getName()) == null || isGenAppName(name)) {
name = genAppName();
}
appenderNames.put(app, name);
printOptions(out, app, "log4j.appender."+name);
if (app.getLayout() != null) {
printOptions(out, app.getLayout(), "log4j.appender."+name+".layout");
}
}
appenderString += ", " + name;
}
String catKey = (cat == Logger.getRootLogger())
? "log4j.rootLogger"
: "log4j.logger." + cat.getName();
if (appenderString != "") {
out.println(catKey + "=" + appenderString);
}
if (!cat.getAdditivity() && cat != Logger.getRootLogger()) {
out.println("log4j.additivity." + cat.getName() + "=false");
}
}
protected void printOptions(PrintWriter out, Logger cat) {
printOptions(out, (Category) cat);
}
protected
void printOptions(PrintWriter out, Object obj, String fullname) {
out.println(fullname + "=" + obj.getClass().getName());
PropertyGetter.getProperties(obj, this, fullname + ".");
}
public void foundProperty(Object obj, String prefix, String name, Object value) {
// XXX: Properties encode value.toString()
if (obj instanceof Appender && "name".equals(name)) {
return;
}
if (doCapitalize) {
name = capitalize(name);
}
out.println(prefix + name + "=" + value.toString());
}
public static String capitalize(String name) {
if (Character.isLowerCase(name.charAt(0))) {
if (name.length() == 1 || Character.isLowerCase(name.charAt(1))) {
StringBuffer newname = new StringBuffer(name);
newname.setCharAt(0, Character.toUpperCase(name.charAt(0)));
return newname.toString();
}
}
return name;
}
// for testing
public static void main(String[] args) {
new PropertyPrinter(new PrintWriter(System.out));
}
}

View File

@@ -1,310 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Georg Lundesgaard
package org.apache.log4j.config;
import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.Priority;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.OptionHandler;
import org.apache.log4j.spi.ErrorHandler;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.InterruptedIOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Properties;
/**
General purpose Object property setter. Clients repeatedly invokes
{@link #setProperty setProperty(name,value)} in order to invoke setters
on the Object specified in the constructor. This class relies on the
JavaBeans {@link Introspector} to analyze the given Object Class using
reflection.
<p>Usage:
<pre>
PropertySetter ps = new PropertySetter(anObject);
ps.set("name", "Joe");
ps.set("age", "32");
ps.set("isMale", "true");
</pre>
will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
and setMale(true) if such methods exist with those signatures.
Otherwise an {@link IntrospectionException} are thrown.
@author Anders Kristensen
@since 1.1
*/
public class PropertySetter {
protected Object obj;
protected PropertyDescriptor[] props;
/**
Create a new PropertySetter for the specified Object. This is done
in prepartion for invoking {@link #setProperty} one or more times.
@param obj the object for which to set properties
*/
public
PropertySetter(Object obj) {
this.obj = obj;
}
/**
Uses JavaBeans {@link Introspector} to computer setters of object to be
configured.
*/
protected
void introspect() {
try {
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
props = bi.getPropertyDescriptors();
} catch (IntrospectionException ex) {
LogLog.error("Failed to introspect "+obj+": " + ex.getMessage());
props = new PropertyDescriptor[0];
}
}
/**
Set the properties of an object passed as a parameter in one
go. The <code>properties</code> are parsed relative to a
<code>prefix</code>.
@param obj The object to configure.
@param properties A java.util.Properties containing keys and values.
@param prefix Only keys having the specified prefix will be set.
*/
public
static
void setProperties(Object obj, Properties properties, String prefix) {
new PropertySetter(obj).setProperties(properties, prefix);
}
/**
Set the properites for the object that match the
<code>prefix</code> passed as parameter.
*/
public
void setProperties(Properties properties, String prefix) {
int len = prefix.length();
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
String key = (String) e.nextElement();
// handle only properties that start with the desired frefix.
if (key.startsWith(prefix)) {
// ignore key if it contains dots after the prefix
if (key.indexOf('.', len + 1) > 0) {
//System.err.println("----------Ignoring---["+key
// +"], prefix=["+prefix+"].");
continue;
}
String value = OptionConverter.findAndSubst(key, properties);
key = key.substring(len);
if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
continue;
}
//
// if the property type is an OptionHandler
// (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
if (prop != null
&& OptionHandler.class.isAssignableFrom(prop.getPropertyType())
&& prop.getWriteMethod() != null) {
OptionHandler opt = (OptionHandler)
OptionConverter.instantiateByKey(properties, prefix + key,
prop.getPropertyType(),
null);
PropertySetter setter = new PropertySetter(opt);
setter.setProperties(properties, prefix + key + ".");
try {
prop.getWriteMethod().invoke(this.obj, new Object[] { opt });
} catch(IllegalAccessException ex) {
LogLog.warn("Failed to set property [" + key +
"] to value \"" + value + "\". ", ex);
} catch(InvocationTargetException ex) {
if (ex.getTargetException() instanceof InterruptedException
|| ex.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.warn("Failed to set property [" + key +
"] to value \"" + value + "\". ", ex);
} catch(RuntimeException ex) {
LogLog.warn("Failed to set property [" + key +
"] to value \"" + value + "\". ", ex);
}
continue;
}
setProperty(key, value);
}
}
activate();
}
/**
Set a property on this PropertySetter's Object. If successful, this
method will invoke a setter method on the underlying Object. The
setter is the one for the specified property name and the value is
determined partly from the setter argument type and partly from the
value specified in the call to this method.
<p>If the setter expects a String no conversion is necessary.
If it expects an int, then an attempt is made to convert 'value'
to an int using new Integer(value). If the setter expects a boolean,
the conversion is by new Boolean(value).
@param name name of the property
@param value String value of the property
*/
public
void setProperty(String name, String value) {
if (value == null) return;
name = Introspector.decapitalize(name);
PropertyDescriptor prop = getPropertyDescriptor(name);
//LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
if (prop == null) {
LogLog.warn("No such property [" + name + "] in "+
obj.getClass().getName()+"." );
} else {
try {
setProperty(prop, name, value);
} catch (PropertySetterException ex) {
LogLog.warn("Failed to set property [" + name +
"] to value \"" + value + "\". ", ex.rootCause);
}
}
}
/**
Set the named property given a {@link PropertyDescriptor}.
@param prop A PropertyDescriptor describing the characteristics
of the property to set.
@param name The named of the property to set.
@param value The value of the property.
*/
public
void setProperty(PropertyDescriptor prop, String name, String value)
throws PropertySetterException {
Method setter = prop.getWriteMethod();
if (setter == null) {
throw new PropertySetterException("No setter for property ["+name+"].");
}
Class[] paramTypes = setter.getParameterTypes();
if (paramTypes.length != 1) {
throw new PropertySetterException("#params for setter != 1");
}
Object arg;
try {
arg = convertArg(value, paramTypes[0]);
} catch (Throwable t) {
throw new PropertySetterException("Conversion to type ["+paramTypes[0]+
"] failed. Reason: "+t);
}
if (arg == null) {
throw new PropertySetterException(
"Conversion to type ["+paramTypes[0]+"] failed.");
}
LogLog.debug("Setting property [" + name + "] to [" +arg+"].");
try {
setter.invoke(obj, new Object[] { arg });
} catch (IllegalAccessException ex) {
throw new PropertySetterException(ex);
} catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof InterruptedException
|| ex.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
throw new PropertySetterException(ex);
} catch (RuntimeException ex) {
throw new PropertySetterException(ex);
}
}
/**
Convert <code>val</code> a String parameter to an object of a
given type.
*/
protected
Object convertArg(String val, Class type) {
if(val == null)
return null;
String v = val.trim();
if (String.class.isAssignableFrom(type)) {
return val;
} else if (Integer.TYPE.isAssignableFrom(type)) {
return new Integer(v);
} else if (Long.TYPE.isAssignableFrom(type)) {
return new Long(v);
} else if (Boolean.TYPE.isAssignableFrom(type)) {
if ("true".equalsIgnoreCase(v)) {
return Boolean.TRUE;
} else if ("false".equalsIgnoreCase(v)) {
return Boolean.FALSE;
}
} else if (Priority.class.isAssignableFrom(type)) {
return OptionConverter.toLevel(v, (Level) Level.DEBUG);
} else if (ErrorHandler.class.isAssignableFrom(type)) {
return OptionConverter.instantiateByClassName(v,
ErrorHandler.class, null);
}
return null;
}
protected
PropertyDescriptor getPropertyDescriptor(String name) {
if (props == null) introspect();
for (int i = 0; i < props.length; i++) {
if (name.equals(props[i].getName())) {
return props[i];
}
}
return null;
}
public
void activate() {
if (obj instanceof OptionHandler) {
((OptionHandler) obj).activateOptions();
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.config;
/**
* Thrown when an error is encountered whilst attempting to set a property
* using the {@link PropertySetter} utility class.
*
* @author Anders Kristensen
* @since 1.1
*/
public class PropertySetterException extends Exception {
private static final long serialVersionUID = -1352613734254235861L;
protected Throwable rootCause;
public
PropertySetterException(String msg) {
super(msg);
}
public
PropertySetterException(Throwable rootCause)
{
super();
this.rootCause = rootCause;
}
/**
Returns descriptive text on the cause of this exception.
*/
public
String getMessage() {
String msg = super.getMessage();
if (msg == null && rootCause != null) {
msg = rootCause.getMessage();
}
return msg;
}
}

View File

@@ -1,23 +0,0 @@
<html>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<body>
Package used in getting/setting component properties.
</body>
</html>

View File

@@ -1,145 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Date;
import java.util.Calendar;
import java.util.TimeZone;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.DateFormat;
/**
Formats a {@link Date} in the format "HH:mm:ss,SSS" for example,
"15:49:37,459".
@author Ceki G&uuml;lc&uuml;
@author Andrew Vajoczki
@since 0.7.5
*/
public class AbsoluteTimeDateFormat extends DateFormat {
private static final long serialVersionUID = -388856345976723342L;
/**
String constant used to specify {@link
org.apache.log4j.helpers.AbsoluteTimeDateFormat} in layouts. Current
value is <b>ABSOLUTE</b>. */
public final static String ABS_TIME_DATE_FORMAT = "ABSOLUTE";
/**
String constant used to specify {@link
org.apache.log4j.helpers.DateTimeDateFormat} in layouts. Current
value is <b>DATE</b>.
*/
public final static String DATE_AND_TIME_DATE_FORMAT = "DATE";
/**
String constant used to specify {@link
org.apache.log4j.helpers.ISO8601DateFormat} in layouts. Current
value is <b>ISO8601</b>.
*/
public final static String ISO8601_DATE_FORMAT = "ISO8601";
public
AbsoluteTimeDateFormat() {
setCalendar(Calendar.getInstance());
}
public
AbsoluteTimeDateFormat(TimeZone timeZone) {
setCalendar(Calendar.getInstance(timeZone));
}
private static long previousTime;
private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss."
/**
Appends to <code>sbuf</code> the time in the format
"HH:mm:ss,SSS" for example, "15:49:37,459"
@param date the date to format
@param sbuf the string buffer to write to
@param fieldPosition remains untouched
*/
public
StringBuffer format(Date date, StringBuffer sbuf,
FieldPosition fieldPosition) {
long now = date.getTime();
int millis = (int)(now % 1000);
if ((now - millis) != previousTime || previousTimeWithoutMillis[0] == 0) {
// We reach this point at most once per second
// across all threads instead of each time format()
// is called. This saves considerable CPU time.
calendar.setTime(date);
int start = sbuf.length();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if(hour < 10) {
sbuf.append('0');
}
sbuf.append(hour);
sbuf.append(':');
int mins = calendar.get(Calendar.MINUTE);
if(mins < 10) {
sbuf.append('0');
}
sbuf.append(mins);
sbuf.append(':');
int secs = calendar.get(Calendar.SECOND);
if(secs < 10) {
sbuf.append('0');
}
sbuf.append(secs);
sbuf.append(',');
// store the time string for next time to avoid recomputation
sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
previousTime = now - millis;
}
else {
sbuf.append(previousTimeWithoutMillis);
}
if(millis < 100)
sbuf.append('0');
if(millis < 10)
sbuf.append('0');
sbuf.append(millis);
return sbuf;
}
/**
This method does not do anything but return <code>null</code>.
*/
public
Date parse(String s, ParsePosition pos) {
return null;
}
}

View File

@@ -1,176 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.spi.AppenderAttachable;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Appender;
import java.util.Vector;
import java.util.Enumeration;
/**
A straightforward implementation of the {@link AppenderAttachable}
interface.
@author Ceki G&uuml;lc&uuml;
@since version 0.9.1 */
public class AppenderAttachableImpl implements AppenderAttachable {
/** Array of appenders. */
protected Vector appenderList;
/**
Attach an appender. If the appender is already in the list in
won't be added again.
*/
public
void addAppender(Appender newAppender) {
// Null values for newAppender parameter are strictly forbidden.
if(newAppender == null)
return;
if(appenderList == null) {
appenderList = new Vector(1);
}
if(!appenderList.contains(newAppender))
appenderList.addElement(newAppender);
}
/**
Call the <code>doAppend</code> method on all attached appenders. */
public
int appendLoopOnAppenders(LoggingEvent event) {
int size = 0;
Appender appender;
if(appenderList != null) {
size = appenderList.size();
for(int i = 0; i < size; i++) {
appender = (Appender) appenderList.elementAt(i);
appender.doAppend(event);
}
}
return size;
}
/**
Get all attached appenders as an Enumeration. If there are no
attached appenders <code>null</code> is returned.
@return Enumeration An enumeration of attached appenders.
*/
public
Enumeration getAllAppenders() {
if(appenderList == null)
return null;
else
return appenderList.elements();
}
/**
Look for an attached appender named as <code>name</code>.
<p>Return the appender with that name if in the list. Return null
otherwise.
*/
public
Appender getAppender(String name) {
if(appenderList == null || name == null)
return null;
int size = appenderList.size();
Appender appender;
for(int i = 0; i < size; i++) {
appender = (Appender) appenderList.elementAt(i);
if(name.equals(appender.getName()))
return appender;
}
return null;
}
/**
Returns <code>true</code> if the specified appender is in the
list of attached appenders, <code>false</code> otherwise.
@since 1.2 */
public
boolean isAttached(Appender appender) {
if(appenderList == null || appender == null)
return false;
int size = appenderList.size();
Appender a;
for(int i = 0; i < size; i++) {
a = (Appender) appenderList.elementAt(i);
if(a == appender)
return true;
}
return false;
}
/**
* Remove and close all previously attached appenders.
* */
public
void removeAllAppenders() {
if(appenderList != null) {
int len = appenderList.size();
for(int i = 0; i < len; i++) {
Appender a = (Appender) appenderList.elementAt(i);
a.close();
}
appenderList.removeAllElements();
appenderList = null;
}
}
/**
Remove the appender passed as parameter form the list of attached
appenders. */
public
void removeAppender(Appender appender) {
if(appender == null || appenderList == null)
return;
appenderList.removeElement(appender);
}
/**
Remove the appender with the name passed as parameter form the
list of appenders.
*/
public
void removeAppender(String name) {
if(name == null || appenderList == null) return;
int size = appenderList.size();
for(int i = 0; i < size; i++) {
if(name.equals(((Appender)appenderList.elementAt(i)).getName())) {
appenderList.removeElementAt(i);
break;
}
}
}
}

View File

@@ -1,181 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Mathias Bogaert
// joelr@viair.com
package org.apache.log4j.helpers;
import org.apache.log4j.spi.LoggingEvent;
/**
<code>BoundedFIFO</code> serves as the bounded first-in-first-out
buffer heavily used by the {@link org.apache.log4j.AsyncAppender}.
@author Ceki G&uuml;lc&uuml;
@since version 0.9.1 */
public class BoundedFIFO {
LoggingEvent[] buf;
int numElements = 0;
int first = 0;
int next = 0;
int maxSize;
/**
Instantiate a new BoundedFIFO with a maximum size passed as argument.
*/
public
BoundedFIFO(int maxSize) {
if(maxSize < 1) {
throw new IllegalArgumentException("The maxSize argument ("+maxSize+
") is not a positive integer.");
}
this.maxSize = maxSize;
buf = new LoggingEvent[maxSize];
}
/**
Get the first element in the buffer. Returns <code>null</code> if
there are no elements in the buffer. */
public
LoggingEvent get() {
if(numElements == 0)
return null;
LoggingEvent r = buf[first];
buf[first] = null; // help garbage collection
if(++first == maxSize) {
first = 0;
}
numElements--;
return r;
}
/**
Place a {@link LoggingEvent} in the buffer. If the buffer is full
then the event is <b>silently dropped</b>. It is the caller's
responsability to make sure that the buffer has free space. */
public
void put(LoggingEvent o) {
if(numElements != maxSize) {
buf[next] = o;
if(++next == maxSize) {
next = 0;
}
numElements++;
}
}
/**
Get the maximum size of the buffer.
*/
public
int getMaxSize() {
return maxSize;
}
/**
Return <code>true</code> if the buffer is full, that is, whether
the number of elements in the buffer equals the buffer size. */
public
boolean isFull() {
return numElements == maxSize;
}
/**
Get the number of elements in the buffer. This number is
guaranteed to be in the range 0 to <code>maxSize</code>
(inclusive).
*/
public
int length() {
return numElements;
}
int min(int a, int b) {
return a < b ? a : b;
}
/**
Resize the buffer to a new size. If the new size is smaller than
the old size events might be lost.
@since 1.1
*/
synchronized
public
void resize(int newSize) {
if(newSize == maxSize)
return;
LoggingEvent[] tmp = new LoggingEvent[newSize];
// we should not copy beyond the buf array
int len1 = maxSize - first;
// we should not copy beyond the tmp array
len1 = min(len1, newSize);
// er.. how much do we actually need to copy?
// We should not copy more than the actual number of elements.
len1 = min(len1, numElements);
// Copy from buf starting a first, to tmp, starting at position 0, len1 elements.
System.arraycopy(buf, first, tmp, 0, len1);
// Are there any uncopied elements and is there still space in the new array?
int len2 = 0;
if((len1 < numElements) && (len1 < newSize)) {
len2 = numElements - len1;
len2 = min(len2, newSize - len1);
System.arraycopy(buf, 0, tmp, len1, len2);
}
this.buf = tmp;
this.maxSize = newSize;
this.first=0;
this.numElements = len1+len2;
this.next = this.numElements;
if(this.next == this.maxSize) // this should never happen, but again, it just might.
this.next = 0;
}
/**
Returns <code>true</code> if there is just one element in the
buffer. In other words, if there were no elements before the last
{@link #put} operation completed. */
public
boolean wasEmpty() {
return numElements == 1;
}
/**
Returns <code>true</code> if the number of elements in the
buffer plus 1 equals the maximum buffer size, returns
<code>false</code> otherwise. */
public
boolean wasFull() {
return (numElements+1 == maxSize);
}
}

View File

@@ -1,63 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.io.Writer;
import java.io.IOException;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.ErrorCode;
/**
Counts the number of bytes written.
@author Heinz Richter, heinz.richter@frogdot.com
@since 0.8.1
*/
public class CountingQuietWriter extends QuietWriter {
protected long count;
public
CountingQuietWriter(Writer writer, ErrorHandler eh) {
super(writer, eh);
}
public
void write(String string) {
try {
out.write(string);
count += string.length();
}
catch(IOException e) {
errorHandler.error("Write failure.", e, ErrorCode.WRITE_FAILURE);
}
}
public
long getCount() {
return count;
}
public
void setCount(long count) {
this.count = count;
}
}

View File

@@ -1,159 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.spi.LoggingEvent;
/**
CyclicBuffer is used by other appenders to hold {@link LoggingEvent
LoggingEvents} for immediate or differed display.
<p>This buffer gives read access to any element in the buffer not
just the first or last element.
@author Ceki G&uuml;lc&uuml;
@since 0.9.0
*/
public class CyclicBuffer {
LoggingEvent[] ea;
int first;
int last;
int numElems;
int maxSize;
/**
Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
The <code>maxSize</code> argument must a positive integer.
@param maxSize The maximum number of elements in the buffer.
*/
public CyclicBuffer(int maxSize) throws IllegalArgumentException {
if(maxSize < 1) {
throw new IllegalArgumentException("The maxSize argument ("+maxSize+
") is not a positive integer.");
}
this.maxSize = maxSize;
ea = new LoggingEvent[maxSize];
first = 0;
last = 0;
numElems = 0;
}
/**
Add an <code>event</code> as the last event in the buffer.
*/
public
void add(LoggingEvent event) {
ea[last] = event;
if(++last == maxSize)
last = 0;
if(numElems < maxSize)
numElems++;
else if(++first == maxSize)
first = 0;
}
/**
Get the <i>i</i>th oldest event currently in the buffer. If
<em>i</em> is outside the range 0 to the number of elements
currently in the buffer, then <code>null</code> is returned.
*/
public
LoggingEvent get(int i) {
if(i < 0 || i >= numElems)
return null;
return ea[(first + i) % maxSize];
}
public
int getMaxSize() {
return maxSize;
}
/**
Get the oldest (first) element in the buffer. The oldest element
is removed from the buffer.
*/
public
LoggingEvent get() {
LoggingEvent r = null;
if(numElems > 0) {
numElems--;
r = ea[first];
ea[first] = null;
if(++first == maxSize)
first = 0;
}
return r;
}
/**
Get the number of elements in the buffer. This number is
guaranteed to be in the range 0 to <code>maxSize</code>
(inclusive).
*/
public
int length() {
return numElems;
}
/**
Resize the cyclic buffer to <code>newSize</code>.
@throws IllegalArgumentException if <code>newSize</code> is negative.
*/
public
void resize(int newSize) {
if(newSize < 0) {
throw new IllegalArgumentException("Negative array size ["+newSize+
"] not allowed.");
}
if(newSize == numElems)
return; // nothing to do
LoggingEvent[] temp = new LoggingEvent[newSize];
int loopLen = newSize < numElems ? newSize : numElems;
for(int i = 0; i < loopLen; i++) {
temp[i] = ea[first];
ea[first] = null;
if(++first == numElems)
first = 0;
}
ea = temp;
first = 0;
numElems = loopLen;
maxSize = newSize;
if (loopLen == newSize) {
last = 0;
} else {
last = loopLen;
}
}
}

View File

@@ -1,200 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.text.FieldPosition;
/**
This abstract layout takes care of all the date related options and
formatting work.
@author Ceki G&uuml;lc&uuml;
*/
abstract public class DateLayout extends Layout {
/**
String constant designating no time information. Current value of
this constant is <b>NULL</b>.
*/
public final static String NULL_DATE_FORMAT = "NULL";
/**
String constant designating relative time. Current value of
this constant is <b>RELATIVE</b>.
*/
public final static String RELATIVE_TIME_DATE_FORMAT = "RELATIVE";
protected FieldPosition pos = new FieldPosition(0);
/**
@deprecated Options are now handled using the JavaBeans paradigm.
This constant is not longer needed and will be removed in the
<em>near</em> term.
*/
final static public String DATE_FORMAT_OPTION = "DateFormat";
/**
@deprecated Options are now handled using the JavaBeans paradigm.
This constant is not longer needed and will be removed in the
<em>near</em> term.
*/
final static public String TIMEZONE_OPTION = "TimeZone";
private String timeZoneID;
private String dateFormatOption;
protected DateFormat dateFormat;
protected Date date = new Date();
/**
@deprecated Use the setter method for the option directly instead
of the generic <code>setOption</code> method.
*/
public
String[] getOptionStrings() {
return new String[] {DATE_FORMAT_OPTION, TIMEZONE_OPTION};
}
/**
@deprecated Use the setter method for the option directly instead
of the generic <code>setOption</code> method.
*/
public
void setOption(String option, String value) {
if(option.equalsIgnoreCase(DATE_FORMAT_OPTION)) {
dateFormatOption = value.toUpperCase();
} else if(option.equalsIgnoreCase(TIMEZONE_OPTION)) {
timeZoneID = value;
}
}
/**
The value of the <b>DateFormat</b> option should be either an
argument to the constructor of {@link SimpleDateFormat} or one of
the srings "NULL", "RELATIVE", "ABSOLUTE", "DATE" or "ISO8601.
*/
public
void setDateFormat(String dateFormat) {
if (dateFormat != null) {
dateFormatOption = dateFormat;
}
setDateFormat(dateFormatOption, TimeZone.getDefault());
}
/**
Returns value of the <b>DateFormat</b> option.
*/
public
String getDateFormat() {
return dateFormatOption;
}
/**
The <b>TimeZoneID</b> option is a time zone ID string in the format
expected by the {@link TimeZone#getTimeZone} method.
*/
public
void setTimeZone(String timeZone) {
this.timeZoneID = timeZone;
}
/**
Returns value of the <b>TimeZone</b> option.
*/
public
String getTimeZone() {
return timeZoneID;
}
public
void activateOptions() {
setDateFormat(dateFormatOption);
if(timeZoneID != null && dateFormat != null) {
dateFormat.setTimeZone(TimeZone.getTimeZone(timeZoneID));
}
}
public
void dateFormat(StringBuffer buf, LoggingEvent event) {
if(dateFormat != null) {
date.setTime(event.timeStamp);
dateFormat.format(date, buf, this.pos);
buf.append(' ');
}
}
/**
Sets the {@link DateFormat} used to format time and date in the
zone determined by <code>timeZone</code>.
*/
public
void setDateFormat(DateFormat dateFormat, TimeZone timeZone) {
this.dateFormat = dateFormat;
this.dateFormat.setTimeZone(timeZone);
}
/**
Sets the DateFormat used to format date and time in the time zone
determined by <code>timeZone</code> parameter. The {@link DateFormat} used
will depend on the <code>dateFormatType</code>.
<p>The recognized types are {@link #NULL_DATE_FORMAT}, {@link
#RELATIVE_TIME_DATE_FORMAT} {@link
AbsoluteTimeDateFormat#ABS_TIME_DATE_FORMAT}, {@link
AbsoluteTimeDateFormat#DATE_AND_TIME_DATE_FORMAT} and {@link
AbsoluteTimeDateFormat#ISO8601_DATE_FORMAT}. If the
<code>dateFormatType</code> is not one of the above, then the
argument is assumed to be a date pattern for {@link
SimpleDateFormat}.
*/
public
void setDateFormat(String dateFormatType, TimeZone timeZone) {
if(dateFormatType == null) {
this.dateFormat = null;
return;
}
if(dateFormatType.equalsIgnoreCase(NULL_DATE_FORMAT)) {
this.dateFormat = null;
} else if (dateFormatType.equalsIgnoreCase(RELATIVE_TIME_DATE_FORMAT)) {
this.dateFormat = new RelativeTimeDateFormat();
} else if(dateFormatType.equalsIgnoreCase(
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT)) {
this.dateFormat = new AbsoluteTimeDateFormat(timeZone);
} else if(dateFormatType.equalsIgnoreCase(
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT)) {
this.dateFormat = new DateTimeDateFormat(timeZone);
} else if(dateFormatType.equalsIgnoreCase(
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT)) {
this.dateFormat = new ISO8601DateFormat(timeZone);
} else {
this.dateFormat = new SimpleDateFormat(dateFormatType);
this.dateFormat.setTimeZone(timeZone);
}
}
}

View File

@@ -1,85 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.Date;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.DateFormatSymbols;
/**
Formats a {@link Date} in the format "dd MMM yyyy HH:mm:ss,SSS" for example,
"06 Nov 1994 15:49:37,459".
@author Ceki G&uuml;lc&uuml;
@since 0.7.5
*/
public class DateTimeDateFormat extends AbsoluteTimeDateFormat {
private static final long serialVersionUID = 5547637772208514971L;
String[] shortMonths;
public
DateTimeDateFormat() {
super();
shortMonths = new DateFormatSymbols().getShortMonths();
}
public
DateTimeDateFormat(TimeZone timeZone) {
this();
setCalendar(Calendar.getInstance(timeZone));
}
/**
Appends to <code>sbuf</code> the date in the format "dd MMM yyyy
HH:mm:ss,SSS" for example, "06 Nov 1994 08:49:37,459".
@param sbuf the string buffer to write to
*/
public
StringBuffer format(Date date, StringBuffer sbuf,
FieldPosition fieldPosition) {
calendar.setTime(date);
int day = calendar.get(Calendar.DAY_OF_MONTH);
if(day < 10)
sbuf.append('0');
sbuf.append(day);
sbuf.append(' ');
sbuf.append(shortMonths[calendar.get(Calendar.MONTH)]);
sbuf.append(' ');
int year = calendar.get(Calendar.YEAR);
sbuf.append(year);
sbuf.append(' ');
return super.format(date, sbuf, fieldPosition);
}
/**
This method does not do anything but return <code>null</code>.
*/
public
Date parse(java.lang.String s, ParsePosition pos) {
return null;
}
}

View File

@@ -1,111 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Contributors: Mathias Bogaert
package org.apache.log4j.helpers;
import java.io.File;
/**
Check every now and then that a certain file has not changed. If it
has, then call the {@link #doOnChange} method.
@author Ceki G&uuml;lc&uuml;
@since version 0.9.1 */
public abstract class FileWatchdog extends Thread {
/**
The default delay between every file modification check, set to 60
seconds. */
static final public long DEFAULT_DELAY = 60000;
/**
The name of the file to observe for changes.
*/
protected String filename;
/**
The delay to observe between every check. By default set {@link
#DEFAULT_DELAY}. */
protected long delay = DEFAULT_DELAY;
File file;
long lastModif = 0;
boolean warnedAlready = false;
boolean interrupted = false;
protected
FileWatchdog(String filename) {
super("FileWatchdog");
this.filename = filename;
file = new File(filename);
setDaemon(true);
checkAndConfigure();
}
/**
Set the delay to observe between each check of the file changes.
*/
public
void setDelay(long delay) {
this.delay = delay;
}
abstract
protected
void doOnChange();
protected
void checkAndConfigure() {
boolean fileExists;
try {
fileExists = file.exists();
} catch(SecurityException e) {
LogLog.warn("Was not allowed to read check file existance, file:["+
filename+"].");
interrupted = true; // there is no point in continuing
return;
}
if(fileExists) {
long l = file.lastModified(); // this can also throw a SecurityException
if(l > lastModif) { // however, if we reached this point this
lastModif = l; // is very unlikely.
doOnChange();
warnedAlready = false;
}
} else {
if(!warnedAlready) {
LogLog.debug("["+filename+"] does not exist.");
warnedAlready = true;
}
}
}
public
void run() {
while(!interrupted) {
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
// no interruption expected
}
checkAndConfigure();
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
/**
FormattingInfo instances contain the information obtained when parsing
formatting modifiers in conversion modifiers.
@author <a href=mailto:jim_cakalic@na.biomerieux.com>Jim Cakalic</a>
@author Ceki G&uuml;lc&uuml;
@since 0.8.2
*/
public class FormattingInfo {
int min = -1;
int max = 0x7FFFFFFF;
boolean leftAlign = false;
void reset() {
min = -1;
max = 0x7FFFFFFF;
leftAlign = false;
}
void dump() {
LogLog.debug("min="+min+", max="+max+", leftAlign="+leftAlign);
}
}

View File

@@ -1,155 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.Date;
import java.text.FieldPosition;
import java.text.ParsePosition;
// Contributors: Arndt Schoenewald <arndt@ibm23093i821.mc.schoenewald.de>
/**
Formats a {@link Date} in the format "yyyy-MM-dd HH:mm:ss,SSS" for example
"1999-11-27 15:49:37,459".
<p>Refer to the <a
href=http://www.cl.cam.ac.uk/~mgk25/iso-time.html>summary of the
International Standard Date and Time Notation</a> for more
information on this format.
@author Ceki G&uuml;lc&uuml;
@author Andrew Vajoczki
@since 0.7.5
*/
public class ISO8601DateFormat extends AbsoluteTimeDateFormat {
private static final long serialVersionUID = -759840745298755296L;
public
ISO8601DateFormat() {
}
public
ISO8601DateFormat(TimeZone timeZone) {
super(timeZone);
}
static private long lastTime;
static private char[] lastTimeString = new char[20];
/**
Appends a date in the format "YYYY-mm-dd HH:mm:ss,SSS"
to <code>sbuf</code>. For example: "1999-11-27 15:49:37,459".
@param sbuf the <code>StringBuffer</code> to write to
*/
public
StringBuffer format(Date date, StringBuffer sbuf,
FieldPosition fieldPosition) {
long now = date.getTime();
int millis = (int)(now % 1000);
if ((now - millis) != lastTime || lastTimeString[0] == 0) {
// We reach this point at most once per second
// across all threads instead of each time format()
// is called. This saves considerable CPU time.
calendar.setTime(date);
int start = sbuf.length();
int year = calendar.get(Calendar.YEAR);
sbuf.append(year);
String month;
switch(calendar.get(Calendar.MONTH)) {
case Calendar.JANUARY: month = "-01-"; break;
case Calendar.FEBRUARY: month = "-02-"; break;
case Calendar.MARCH: month = "-03-"; break;
case Calendar.APRIL: month = "-04-"; break;
case Calendar.MAY: month = "-05-"; break;
case Calendar.JUNE: month = "-06-"; break;
case Calendar.JULY: month = "-07-"; break;
case Calendar.AUGUST: month = "-08-"; break;
case Calendar.SEPTEMBER: month = "-09-"; break;
case Calendar.OCTOBER: month = "-10-"; break;
case Calendar.NOVEMBER: month = "-11-"; break;
case Calendar.DECEMBER: month = "-12-"; break;
default: month = "-NA-"; break;
}
sbuf.append(month);
int day = calendar.get(Calendar.DAY_OF_MONTH);
if(day < 10)
sbuf.append('0');
sbuf.append(day);
sbuf.append(' ');
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if(hour < 10) {
sbuf.append('0');
}
sbuf.append(hour);
sbuf.append(':');
int mins = calendar.get(Calendar.MINUTE);
if(mins < 10) {
sbuf.append('0');
}
sbuf.append(mins);
sbuf.append(':');
int secs = calendar.get(Calendar.SECOND);
if(secs < 10) {
sbuf.append('0');
}
sbuf.append(secs);
sbuf.append(',');
// store the time string for next time to avoid recomputation
sbuf.getChars(start, sbuf.length(), lastTimeString, 0);
lastTime = now - millis;
}
else {
sbuf.append(lastTimeString);
}
if (millis < 100)
sbuf.append('0');
if (millis < 10)
sbuf.append('0');
sbuf.append(millis);
return sbuf;
}
/**
This method does not do anything but return <code>null</code>.
*/
public
Date parse(java.lang.String s, ParsePosition pos) {
return null;
}
}

View File

@@ -1,200 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.net.URL;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.InterruptedIOException;
/**
Load resources (or images) from various sources.
@author Ceki G&uuml;lc&uuml;
*/
public class Loader {
static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
// We conservatively assume that we are running under Java 1.x
static private boolean java1 = true;
static private boolean ignoreTCL = false;
static {
String prop = OptionConverter.getSystemProperty("java.version", null);
if(prop != null) {
int i = prop.indexOf('.');
if(i != -1) {
if(prop.charAt(i+1) != '1')
java1 = false;
}
}
String ignoreTCLProp = OptionConverter.getSystemProperty("log4j.ignoreTCL", null);
if(ignoreTCLProp != null) {
ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
}
}
/**
* Get a resource by delegating to getResource(String).
* @param resource resource name
* @param clazz class, ignored.
* @return URL to resource or null.
* @deprecated as of 1.2.
*/
public static URL getResource(String resource, Class clazz) {
return getResource(resource);
}
/**
This method will search for <code>resource</code> in different
places. The search order is as follows:
<ol>
<p><li>Search for <code>resource</code> using the thread context
class loader under Java2. If that fails, search for
<code>resource</code> using the class loader that loaded this
class (<code>Loader</code>). Under JDK 1.1, only the the class
loader that loaded this class (<code>Loader</code>) is used.
<p><li>Try one last time with
<code>ClassLoader.getSystemResource(resource)</code>, that is is
using the system class loader in JDK 1.2 and virtual machine's
built-in class loader in JDK 1.1.
</ol>
*/
static public URL getResource(String resource) {
ClassLoader classLoader = null;
URL url = null;
try {
if(!java1 && !ignoreTCL) {
classLoader = getTCL();
if(classLoader != null) {
LogLog.debug("Trying to find ["+resource+"] using context classloader "
+classLoader+".");
url = classLoader.getResource(resource);
if(url != null) {
return url;
}
}
}
// We could not find resource. Ler us now try with the
// classloader that loaded this class.
classLoader = Loader.class.getClassLoader();
if(classLoader != null) {
LogLog.debug("Trying to find ["+resource+"] using "+classLoader
+" class loader.");
url = classLoader.getResource(resource);
if(url != null) {
return url;
}
}
} catch(IllegalAccessException t) {
LogLog.warn(TSTR, t);
} catch(InvocationTargetException t) {
if (t.getTargetException() instanceof InterruptedException
|| t.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.warn(TSTR, t);
} catch(Throwable t) {
//
// can't be InterruptedException or InterruptedIOException
// since not declared, must be error or RuntimeError.
LogLog.warn(TSTR, t);
}
// Last ditch attempt: get the resource from the class path. It
// may be the case that clazz was loaded by the Extentsion class
// loader which the parent of the system class loader. Hence the
// code below.
LogLog.debug("Trying to find ["+resource+
"] using ClassLoader.getSystemResource().");
return ClassLoader.getSystemResource(resource);
}
/**
Are we running under JDK 1.x?
*/
public
static
boolean isJava1() {
return java1;
}
/**
* Get the Thread Context Loader which is a JDK 1.2 feature. If we
* are running under JDK 1.1 or anything else goes wrong the method
* returns <code>null<code>.
*
* */
private static ClassLoader getTCL() throws IllegalAccessException,
InvocationTargetException {
// Are we running on a JDK 1.2 or later system?
Method method = null;
try {
method = Thread.class.getMethod("getContextClassLoader", null);
} catch (NoSuchMethodException e) {
// We are running on JDK 1.1
return null;
}
return (ClassLoader) method.invoke(Thread.currentThread(), null);
}
/**
* If running under JDK 1.2 load the specified class using the
* <code>Thread</code> <code>contextClassLoader</code> if that
* fails try Class.forname. Under JDK 1.1 only Class.forName is
* used.
*
*/
static public Class loadClass (String clazz) throws ClassNotFoundException {
// Just call Class.forName(clazz) if we are running under JDK 1.1
// or if we are instructed to ignore the TCL.
if(java1 || ignoreTCL) {
return Class.forName(clazz);
} else {
try {
return getTCL().loadClass(clazz);
}
// we reached here because tcl was null or because of a
// security exception, or because clazz could not be loaded...
// In any case we now try one more time
catch(InvocationTargetException e) {
if (e.getTargetException() instanceof InterruptedException
|| e.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
} catch(Throwable t) {
}
}
return Class.forName(clazz);
}
}

View File

@@ -1,189 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
/**
This class used to output log statements from within the log4j package.
<p>Log4j components cannot make log4j logging calls. However, it is
sometimes useful for the user to learn about what log4j is
doing. You can enable log4j internal logging by defining the
<b>log4j.configDebug</b> variable.
<p>All log4j internal debug calls go to <code>System.out</code>
where as internal error messages are sent to
<code>System.err</code>. All internal messages are prepended with
the string "log4j: ".
@since 0.8.2
@author Ceki G&uuml;lc&uuml;
*/
public class LogLog {
/**
Defining this value makes log4j print log4j-internal debug
statements to <code>System.out</code>.
<p> The value of this string is <b>log4j.debug</b>.
<p>Note that the search for all option names is case sensitive. */
public static final String DEBUG_KEY="log4j.debug";
/**
Defining this value makes log4j components print log4j-internal
debug statements to <code>System.out</code>.
<p> The value of this string is <b>log4j.configDebug</b>.
<p>Note that the search for all option names is case sensitive.
@deprecated Use {@link #DEBUG_KEY} instead.
*/
public static final String CONFIG_DEBUG_KEY="log4j.configDebug";
protected static boolean debugEnabled = false;
/**
In quietMode not even errors generate any output.
*/
private static boolean quietMode = false;
private static final String PREFIX = "log4j: ";
private static final String ERR_PREFIX = "log4j:ERROR ";
private static final String WARN_PREFIX = "log4j:WARN ";
static {
String key = OptionConverter.getSystemProperty(DEBUG_KEY, null);
if(key == null) {
key = OptionConverter.getSystemProperty(CONFIG_DEBUG_KEY, null);
}
if(key != null) {
debugEnabled = OptionConverter.toBoolean(key, true);
}
}
/**
Allows to enable/disable log4j internal logging.
*/
static
public
void setInternalDebugging(boolean enabled) {
debugEnabled = enabled;
}
/**
This method is used to output log4j internal debug
statements. Output goes to <code>System.out</code>.
*/
public
static
void debug(String msg) {
if(debugEnabled && !quietMode) {
System.out.println(PREFIX+msg);
}
}
/**
This method is used to output log4j internal debug
statements. Output goes to <code>System.out</code>.
*/
public
static
void debug(String msg, Throwable t) {
if(debugEnabled && !quietMode) {
System.out.println(PREFIX+msg);
if(t != null)
t.printStackTrace(System.out);
}
}
/**
This method is used to output log4j internal error
statements. There is no way to disable error statements.
Output goes to <code>System.err</code>.
*/
public
static
void error(String msg) {
if(quietMode)
return;
System.err.println(ERR_PREFIX+msg);
}
/**
This method is used to output log4j internal error
statements. There is no way to disable error statements.
Output goes to <code>System.err</code>.
*/
public
static
void error(String msg, Throwable t) {
if(quietMode)
return;
System.err.println(ERR_PREFIX+msg);
if(t != null) {
t.printStackTrace();
}
}
/**
In quite mode no LogLog generates strictly no output, not even
for errors.
@param quietMode A true for not
*/
public
static
void setQuietMode(boolean quietMode) {
LogLog.quietMode = quietMode;
}
/**
This method is used to output log4j internal warning
statements. There is no way to disable warning statements.
Output goes to <code>System.err</code>. */
public
static
void warn(String msg) {
if(quietMode)
return;
System.err.println(WARN_PREFIX+msg);
}
/**
This method is used to output log4j internal warnings. There is
no way to disable warning statements. Output goes to
<code>System.err</code>. */
public
static
void warn(String msg, Throwable t) {
if(quietMode)
return;
System.err.println(WARN_PREFIX+msg);
if(t != null) {
t.printStackTrace();
}
}
}

View File

@@ -1,92 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.pattern.LogEvent;
import java.lang.reflect.Method;
import java.util.Set;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
public final class MDCKeySetExtractor {
private final Method getKeySetMethod;
public static final MDCKeySetExtractor INSTANCE =
new MDCKeySetExtractor();
private MDCKeySetExtractor() {
//
// log4j 1.2.15 and later will have method to get names
// of all keys in MDC
//
Method getMethod = null;
try {
getMethod = LoggingEvent.class.getMethod(
"getPropertyKeySet", null);
} catch(Exception ex) {
getMethod = null;
}
getKeySetMethod = getMethod;
}
public Set getPropertyKeySet(final LoggingEvent event) throws Exception {
//
// MDC keys are not visible prior to log4j 1.2.15
//
Set keySet = null;
if (getKeySetMethod != null) {
keySet = (Set) getKeySetMethod.invoke(event, null);
} else {
//
// for 1.2.14 and earlier could serialize and
// extract MDC content
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(outBytes);
os.writeObject(event);
os.close();
byte[] raw = outBytes.toByteArray();
//
// bytes 6 and 7 should be the length of the original classname
// should be the same as our substitute class name
final String subClassName = LogEvent.class.getName();
if (raw[6] == 0 || raw[7] == subClassName.length()) {
//
// manipulate stream to use our class name
//
for (int i = 0; i < subClassName.length(); i++) {
raw[8 + i] = (byte) subClassName.charAt(i);
}
ByteArrayInputStream inBytes = new ByteArrayInputStream(raw);
ObjectInputStream is = new ObjectInputStream(inBytes);
Object cracked = is.readObject();
if (cracked instanceof LogEvent) {
keySet = ((LogEvent) cracked).getPropertyKeySet();
}
is.close();
}
}
return keySet;
}
}

View File

@@ -1,50 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Enumeration;
import java.util.NoSuchElementException;
/**
An always-empty Enumerator.
@author Anders Kristensen
@since version 1.0
*/
public class NullEnumeration implements Enumeration {
private static final NullEnumeration instance = new NullEnumeration();
private
NullEnumeration() {
}
public static NullEnumeration getInstance() {
return instance;
}
public
boolean hasMoreElements() {
return false;
}
public
Object nextElement() {
throw new NoSuchElementException();
}
}

View File

@@ -1,114 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Logger;
import org.apache.log4j.Appender;
import java.io.InterruptedIOException;
/**
The <code>OnlyOnceErrorHandler</code> implements log4j's default
error handling policy which consists of emitting a message for the
first error in an appender and ignoring all following errors.
<p>The error message is printed on <code>System.err</code>.
<p>This policy aims at protecting an otherwise working application
from being flooded with error messages when logging fails.
@author Ceki G&uuml;lc&uuml;
@since 0.9.0 */
public class OnlyOnceErrorHandler implements ErrorHandler {
final String WARN_PREFIX = "log4j warning: ";
final String ERROR_PREFIX = "log4j error: ";
boolean firstTime = true;
/**
Does not do anything.
*/
public
void setLogger(Logger logger) {
}
/**
No options to activate.
*/
public
void activateOptions() {
}
/**
Prints the message and the stack trace of the exception on
<code>System.err</code>. */
public
void error(String message, Exception e, int errorCode) {
error(message, e, errorCode, null);
}
/**
Prints the message and the stack trace of the exception on
<code>System.err</code>.
*/
public
void error(String message, Exception e, int errorCode, LoggingEvent event) {
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
if(firstTime) {
LogLog.error(message, e);
firstTime = false;
}
}
/**
Print a the error message passed as parameter on
<code>System.err</code>.
*/
public
void error(String message) {
if(firstTime) {
LogLog.error(message);
firstTime = false;
}
}
/**
Does not do anything.
*/
public
void setAppender(Appender appender) {
}
/**
Does not do anything.
*/
public
void setBackupAppender(Appender appender) {
}
}

View File

@@ -1,485 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Properties;
import java.net.URL;
import java.io.InterruptedIOException;
import org.apache.log4j.Level;
import org.apache.log4j.spi.Configurator;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.PropertyConfigurator;
// Contributors: Avy Sharell (sharell@online.fr)
// Matthieu Verbert (mve@zurich.ibm.com)
// Colin Sampaleanu
/**
A convenience class to convert property values to specific types.
@author Ceki G&uuml;lc&uuml;
@author Simon Kitching;
@author Anders Kristensen
*/
public class OptionConverter {
static String DELIM_START = "${";
static char DELIM_STOP = '}';
static int DELIM_START_LEN = 2;
static int DELIM_STOP_LEN = 1;
/** OptionConverter is a static class. */
private OptionConverter() {}
public
static
String[] concatanateArrays(String[] l, String[] r) {
int len = l.length + r.length;
String[] a = new String[len];
System.arraycopy(l, 0, a, 0, l.length);
System.arraycopy(r, 0, a, l.length, r.length);
return a;
}
public
static
String convertSpecialChars(String s) {
char c;
int len = s.length();
StringBuffer sbuf = new StringBuffer(len);
int i = 0;
while(i < len) {
c = s.charAt(i++);
if (c == '\\') {
c = s.charAt(i++);
if(c == 'n') c = '\n';
else if(c == 'r') c = '\r';
else if(c == 't') c = '\t';
else if(c == 'f') c = '\f';
else if(c == '\b') c = '\b';
else if(c == '\"') c = '\"';
else if(c == '\'') c = '\'';
else if(c == '\\') c = '\\';
}
sbuf.append(c);
}
return sbuf.toString();
}
/**
Very similar to <code>System.getProperty</code> except
that the {@link SecurityException} is hidden.
@param key The key to search for.
@param def The default value to return.
@return the string value of the system property, or the default
value if there is no property with that key.
@since 1.1 */
public
static
String getSystemProperty(String key, String def) {
try {
return System.getProperty(key, def);
} catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
LogLog.debug("Was not allowed to read system property \""+key+"\".");
return def;
}
}
public
static
Object instantiateByKey(Properties props, String key, Class superClass,
Object defaultValue) {
// Get the value of the property in string form
String className = findAndSubst(key, props);
if(className == null) {
LogLog.error("Could not find value for key " + key);
return defaultValue;
}
// Trim className to avoid trailing spaces that cause problems.
return OptionConverter.instantiateByClassName(className.trim(), superClass,
defaultValue);
}
/**
If <code>value</code> is "true", then <code>true</code> is
returned. If <code>value</code> is "false", then
<code>true</code> is returned. Otherwise, <code>default</code> is
returned.
<p>Case of value is unimportant. */
public
static
boolean toBoolean(String value, boolean dEfault) {
if(value == null)
return dEfault;
String trimmedVal = value.trim();
if("true".equalsIgnoreCase(trimmedVal))
return true;
if("false".equalsIgnoreCase(trimmedVal))
return false;
return dEfault;
}
public
static
int toInt(String value, int dEfault) {
if(value != null) {
String s = value.trim();
try {
return Integer.valueOf(s).intValue();
}
catch (NumberFormatException e) {
LogLog.error("[" + s + "] is not in proper int form.");
e.printStackTrace();
}
}
return dEfault;
}
/**
Converts a standard or custom priority level to a Level
object. <p> If <code>value</code> is of form
"level#classname", then the specified class' toLevel method
is called to process the specified level string; if no '#'
character is present, then the default {@link org.apache.log4j.Level}
class is used to process the level value.
<p>As a special case, if the <code>value</code> parameter is
equal to the string "NULL", then the value <code>null</code> will
be returned.
<p> If any error occurs while converting the value to a level,
the <code>defaultValue</code> parameter, which may be
<code>null</code>, is returned.
<p> Case of <code>value</code> is insignificant for the level level, but is
significant for the class name part, if present.
@since 1.1 */
public
static
Level toLevel(String value, Level defaultValue) {
if(value == null)
return defaultValue;
value = value.trim();
int hashIndex = value.indexOf('#');
if (hashIndex == -1) {
if("NULL".equalsIgnoreCase(value)) {
return null;
} else {
// no class name specified : use standard Level class
return(Level) Level.toLevel(value, defaultValue);
}
}
Level result = defaultValue;
String clazz = value.substring(hashIndex+1);
String levelName = value.substring(0, hashIndex);
// This is degenerate case but you never know.
if("NULL".equalsIgnoreCase(levelName)) {
return null;
}
LogLog.debug("toLevel" + ":class=[" + clazz + "]"
+ ":pri=[" + levelName + "]");
try {
Class customLevel = Loader.loadClass(clazz);
// get a ref to the specified class' static method
// toLevel(String, org.apache.log4j.Level)
Class[] paramTypes = new Class[] { String.class,
org.apache.log4j.Level.class
};
java.lang.reflect.Method toLevelMethod =
customLevel.getMethod("toLevel", paramTypes);
// now call the toLevel method, passing level string + default
Object[] params = new Object[] {levelName, defaultValue};
Object o = toLevelMethod.invoke(null, params);
result = (Level) o;
} catch(ClassNotFoundException e) {
LogLog.warn("custom level class [" + clazz + "] not found.");
} catch(NoSuchMethodException e) {
LogLog.warn("custom level class [" + clazz + "]"
+ " does not have a class function toLevel(String, Level)", e);
} catch(java.lang.reflect.InvocationTargetException e) {
if (e.getTargetException() instanceof InterruptedException
|| e.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.warn("custom level class [" + clazz + "]"
+ " could not be instantiated", e);
} catch(ClassCastException e) {
LogLog.warn("class [" + clazz
+ "] is not a subclass of org.apache.log4j.Level", e);
} catch(IllegalAccessException e) {
LogLog.warn("class ["+clazz+
"] cannot be instantiated due to access restrictions", e);
} catch(RuntimeException e) {
LogLog.warn("class ["+clazz+"], level ["+levelName+
"] conversion failed.", e);
}
return result;
}
public
static
long toFileSize(String value, long dEfault) {
if(value == null)
return dEfault;
String s = value.trim().toUpperCase();
long multiplier = 1;
int index;
if((index = s.indexOf("KB")) != -1) {
multiplier = 1024;
s = s.substring(0, index);
}
else if((index = s.indexOf("MB")) != -1) {
multiplier = 1024*1024;
s = s.substring(0, index);
}
else if((index = s.indexOf("GB")) != -1) {
multiplier = 1024*1024*1024;
s = s.substring(0, index);
}
if(s != null) {
try {
return Long.valueOf(s).longValue() * multiplier;
}
catch (NumberFormatException e) {
LogLog.error("[" + s + "] is not in proper int form.");
LogLog.error("[" + value + "] not in expected format.", e);
}
}
return dEfault;
}
/**
Find the value corresponding to <code>key</code> in
<code>props</code>. Then perform variable substitution on the
found value.
*/
public
static
String findAndSubst(String key, Properties props) {
String value = props.getProperty(key);
if(value == null)
return null;
try {
return substVars(value, props);
} catch(IllegalArgumentException e) {
LogLog.error("Bad option value ["+value+"].", e);
return value;
}
}
/**
Instantiate an object given a class name. Check that the
<code>className</code> is a subclass of
<code>superClass</code>. If that test fails or the object could
not be instantiated, then <code>defaultValue</code> is returned.
@param className The fully qualified class name of the object to instantiate.
@param superClass The class to which the new object should belong.
@param defaultValue The object to return in case of non-fulfillment
*/
public
static
Object instantiateByClassName(String className, Class superClass,
Object defaultValue) {
if(className != null) {
try {
Class classObj = Loader.loadClass(className);
if(!superClass.isAssignableFrom(classObj)) {
LogLog.error("A \""+className+"\" object is not assignable to a \""+
superClass.getName() + "\" variable.");
LogLog.error("The class \""+ superClass.getName()+"\" was loaded by ");
LogLog.error("["+superClass.getClassLoader()+"] whereas object of type ");
LogLog.error("\"" +classObj.getName()+"\" was loaded by ["
+classObj.getClassLoader()+"].");
return defaultValue;
}
return classObj.newInstance();
} catch (ClassNotFoundException e) {
LogLog.error("Could not instantiate class [" + className + "].", e);
} catch (IllegalAccessException e) {
LogLog.error("Could not instantiate class [" + className + "].", e);
} catch (InstantiationException e) {
LogLog.error("Could not instantiate class [" + className + "].", e);
} catch (RuntimeException e) {
LogLog.error("Could not instantiate class [" + className + "].", e);
}
}
return defaultValue;
}
/**
Perform variable substitution in string <code>val</code> from the
values of keys found in the system propeties.
<p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
<p>For example, if the System properties contains "key=value", then
the call
<pre>
String s = OptionConverter.substituteVars("Value of key is ${key}.");
</pre>
will set the variable <code>s</code> to "Value of key is value.".
<p>If no value could be found for the specified key, then the
<code>props</code> parameter is searched, if the value could not
be found there, then substitution defaults to the empty string.
<p>For example, if system propeties contains no value for the key
"inexistentKey", then the call
<pre>
String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
</pre>
will set <code>s</code> to "Value of inexistentKey is []"
<p>An {@link java.lang.IllegalArgumentException} is thrown if
<code>val</code> contains a start delimeter "${" which is not
balanced by a stop delimeter "}". </p>
<p><b>Author</b> Avy Sharell</a></p>
@param val The string on which variable substitution is performed.
@throws IllegalArgumentException if <code>val</code> is malformed.
*/
public static
String substVars(String val, Properties props) throws
IllegalArgumentException {
StringBuffer sbuf = new StringBuffer();
int i = 0;
int j, k;
while(true) {
j=val.indexOf(DELIM_START, i);
if(j == -1) {
// no more variables
if(i==0) { // this is a simple string
return val;
} else { // add the tail string which contails no variables and return the result.
sbuf.append(val.substring(i, val.length()));
return sbuf.toString();
}
} else {
sbuf.append(val.substring(i, j));
k = val.indexOf(DELIM_STOP, j);
if(k == -1) {
throw new IllegalArgumentException('"'+val+
"\" has no closing brace. Opening brace at position " + j
+ '.');
} else {
j += DELIM_START_LEN;
String key = val.substring(j, k);
// first try in System properties
String replacement = getSystemProperty(key, null);
// then try props parameter
if(replacement == null && props != null) {
replacement = props.getProperty(key);
}
if(replacement != null) {
// Do variable substitution on the replacement string
// such that we can solve "Hello ${x2}" as "Hello p1"
// the where the properties are
// x1=p1
// x2=${x1}
String recursiveReplacement = substVars(replacement, props);
sbuf.append(recursiveReplacement);
}
i = k + DELIM_STOP_LEN;
}
}
}
}
/**
Configure log4j given a URL.
<p>The url must point to a file or resource which will be interpreted by
a new instance of a log4j configurator.
<p>All configurations steps are taken on the
<code>hierarchy</code> passed as a parameter.
<p>
@param url The location of the configuration file or resource.
@param clazz The classname, of the log4j configurator which will parse
the file or resource at <code>url</code>. This must be a subclass of
{@link Configurator}, or null. If this value is null then a default
configurator of {@link PropertyConfigurator} is used, unless the
filename pointed to by <code>url</code> ends in '.xml', in which case
{@link org.apache.log4j.xml.DOMConfigurator} is used.
@param hierarchy The {@link org.apache.log4j.Hierarchy} to act on.
@since 1.1.4 */
static
public
void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
Configurator configurator = null;
String filename = url.getFile();
if(clazz == null && filename != null && filename.endsWith(".xml")) {
clazz = "org.apache.log4j.xml.DOMConfigurator";
}
if(clazz != null) {
LogLog.debug("Preferred configurator class: " + clazz);
configurator = (Configurator) instantiateByClassName(clazz,
Configurator.class,
null);
if(configurator == null) {
LogLog.error("Could not instantiate configurator ["+clazz+"].");
return;
}
} else {
configurator = new PropertyConfigurator();
}
configurator.doConfigure(url, hierarchy);
}
}

View File

@@ -1,111 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.spi.LoggingEvent;
/**
<p>PatternConverter is an abtract class that provides the
formatting functionality that derived classes need.
<p>Conversion specifiers in a conversion patterns are parsed to
individual PatternConverters. Each of which is responsible for
converting a logging event in a converter specific manner.
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
@author Ceki G&uuml;lc&uuml;
@since 0.8.2
*/
public abstract class PatternConverter {
public PatternConverter next;
int min = -1;
int max = 0x7FFFFFFF;
boolean leftAlign = false;
protected
PatternConverter() { }
protected
PatternConverter(FormattingInfo fi) {
min = fi.min;
max = fi.max;
leftAlign = fi.leftAlign;
}
/**
Derived pattern converters must override this method in order to
convert conversion specifiers in the correct way.
*/
abstract
protected
String convert(LoggingEvent event);
/**
A template method for formatting in a converter specific way.
*/
public
void format(StringBuffer sbuf, LoggingEvent e) {
String s = convert(e);
if(s == null) {
if(0 < min)
spacePad(sbuf, min);
return;
}
int len = s.length();
if(len > max)
sbuf.append(s.substring(len-max));
else if(len < min) {
if(leftAlign) {
sbuf.append(s);
spacePad(sbuf, min-len);
}
else {
spacePad(sbuf, min-len);
sbuf.append(s);
}
}
else
sbuf.append(s);
}
static String[] SPACES = {" ", " ", " ", " ", //1,2,4,8 spaces
" ", // 16 spaces
" " }; // 32 spaces
/**
Fast space padding method.
*/
public
void spacePad(StringBuffer sbuf, int length) {
while(length >= 32) {
sbuf.append(SPACES[5]);
length -= 32;
}
for(int i = 4; i >= 0; i--) {
if((length & (1<<i)) != 0) {
sbuf.append(SPACES[i]);
}
}
}
}

View File

@@ -1,570 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LocationInfo;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Arrays;
// Contributors: Nelson Minar <(nelson@monkey.org>
// Igor E. Poteryaev <jah@mail.ru>
// Reinhard Deschler <reinhard.deschler@web.de>
/**
Most of the work of the {@link org.apache.log4j.PatternLayout} class
is delegated to the PatternParser class.
<p>It is this class that parses conversion patterns and creates
a chained list of {@link OptionConverter OptionConverters}.
@author <a href=mailto:"cakalijp@Maritz.com">James P. Cakalic</a>
@author Ceki G&uuml;lc&uuml;
@author Anders Kristensen
@since 0.8.2
*/
public class PatternParser {
private static final char ESCAPE_CHAR = '%';
private static final int LITERAL_STATE = 0;
private static final int CONVERTER_STATE = 1;
private static final int DOT_STATE = 3;
private static final int MIN_STATE = 4;
private static final int MAX_STATE = 5;
static final int FULL_LOCATION_CONVERTER = 1000;
static final int METHOD_LOCATION_CONVERTER = 1001;
static final int CLASS_LOCATION_CONVERTER = 1002;
static final int LINE_LOCATION_CONVERTER = 1003;
static final int FILE_LOCATION_CONVERTER = 1004;
static final int RELATIVE_TIME_CONVERTER = 2000;
static final int THREAD_CONVERTER = 2001;
static final int LEVEL_CONVERTER = 2002;
static final int NDC_CONVERTER = 2003;
static final int MESSAGE_CONVERTER = 2004;
int state;
protected StringBuffer currentLiteral = new StringBuffer(32);
protected int patternLength;
protected int i;
PatternConverter head;
PatternConverter tail;
protected FormattingInfo formattingInfo = new FormattingInfo();
protected String pattern;
public
PatternParser(String pattern) {
this.pattern = pattern;
patternLength = pattern.length();
state = LITERAL_STATE;
}
private
void addToList(PatternConverter pc) {
if(head == null) {
head = tail = pc;
} else {
tail.next = pc;
tail = pc;
}
}
protected
String extractOption() {
if((i < patternLength) && (pattern.charAt(i) == '{')) {
int end = pattern.indexOf('}', i);
if (end > i) {
String r = pattern.substring(i + 1, end);
i = end+1;
return r;
}
}
return null;
}
/**
The option is expected to be in decimal and positive. In case of
error, zero is returned. */
protected
int extractPrecisionOption() {
String opt = extractOption();
int r = 0;
if(opt != null) {
try {
r = Integer.parseInt(opt);
if(r <= 0) {
LogLog.error(
"Precision option (" + opt + ") isn't a positive integer.");
r = 0;
}
}
catch (NumberFormatException e) {
LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
}
}
return r;
}
public
PatternConverter parse() {
char c;
i = 0;
while(i < patternLength) {
c = pattern.charAt(i++);
switch(state) {
case LITERAL_STATE:
// In literal state, the last char is always a literal.
if(i == patternLength) {
currentLiteral.append(c);
continue;
}
if(c == ESCAPE_CHAR) {
// peek at the next char.
switch(pattern.charAt(i)) {
case ESCAPE_CHAR:
currentLiteral.append(c);
i++; // move pointer
break;
case 'n':
currentLiteral.append(Layout.LINE_SEP);
i++; // move pointer
break;
default:
if(currentLiteral.length() != 0) {
addToList(new LiteralPatternConverter(
currentLiteral.toString()));
//LogLog.debug("Parsed LITERAL converter: \""
// +currentLiteral+"\".");
}
currentLiteral.setLength(0);
currentLiteral.append(c); // append %
state = CONVERTER_STATE;
formattingInfo.reset();
}
}
else {
currentLiteral.append(c);
}
break;
case CONVERTER_STATE:
currentLiteral.append(c);
switch(c) {
case '-':
formattingInfo.leftAlign = true;
break;
case '.':
state = DOT_STATE;
break;
default:
if(c >= '0' && c <= '9') {
formattingInfo.min = c - '0';
state = MIN_STATE;
}
else
finalizeConverter(c);
} // switch
break;
case MIN_STATE:
currentLiteral.append(c);
if(c >= '0' && c <= '9')
formattingInfo.min = formattingInfo.min*10 + (c - '0');
else if(c == '.')
state = DOT_STATE;
else {
finalizeConverter(c);
}
break;
case DOT_STATE:
currentLiteral.append(c);
if(c >= '0' && c <= '9') {
formattingInfo.max = c - '0';
state = MAX_STATE;
}
else {
LogLog.error("Error occured in position "+i
+".\n Was expecting digit, instead got char \""+c+"\".");
state = LITERAL_STATE;
}
break;
case MAX_STATE:
currentLiteral.append(c);
if(c >= '0' && c <= '9')
formattingInfo.max = formattingInfo.max*10 + (c - '0');
else {
finalizeConverter(c);
state = LITERAL_STATE;
}
break;
} // switch
} // while
if(currentLiteral.length() != 0) {
addToList(new LiteralPatternConverter(currentLiteral.toString()));
//LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
}
return head;
}
protected
void finalizeConverter(char c) {
PatternConverter pc = null;
switch(c) {
case 'c':
pc = new CategoryPatternConverter(formattingInfo,
extractPrecisionOption());
//LogLog.debug("CATEGORY converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'C':
pc = new ClassNamePatternConverter(formattingInfo,
extractPrecisionOption());
//LogLog.debug("CLASS_NAME converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'd':
String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
DateFormat df;
String dOpt = extractOption();
if(dOpt != null)
dateFormatStr = dOpt;
if(dateFormatStr.equalsIgnoreCase(
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
df = new ISO8601DateFormat();
else if(dateFormatStr.equalsIgnoreCase(
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
df = new AbsoluteTimeDateFormat();
else if(dateFormatStr.equalsIgnoreCase(
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
df = new DateTimeDateFormat();
else {
try {
df = new SimpleDateFormat(dateFormatStr);
}
catch (IllegalArgumentException e) {
LogLog.error("Could not instantiate SimpleDateFormat with " +
dateFormatStr, e);
df = (DateFormat) OptionConverter.instantiateByClassName(
"org.apache.log4j.helpers.ISO8601DateFormat",
DateFormat.class, null);
}
}
pc = new DatePatternConverter(formattingInfo, df);
//LogLog.debug("DATE converter {"+dateFormatStr+"}.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'F':
pc = new LocationPatternConverter(formattingInfo,
FILE_LOCATION_CONVERTER);
//LogLog.debug("File name converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'l':
pc = new LocationPatternConverter(formattingInfo,
FULL_LOCATION_CONVERTER);
//LogLog.debug("Location converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'L':
pc = new LocationPatternConverter(formattingInfo,
LINE_LOCATION_CONVERTER);
//LogLog.debug("LINE NUMBER converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'm':
pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
//LogLog.debug("MESSAGE converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'M':
pc = new LocationPatternConverter(formattingInfo,
METHOD_LOCATION_CONVERTER);
//LogLog.debug("METHOD converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'p':
pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
//LogLog.debug("LEVEL converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 'r':
pc = new BasicPatternConverter(formattingInfo,
RELATIVE_TIME_CONVERTER);
//LogLog.debug("RELATIVE time converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
case 't':
pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
//LogLog.debug("THREAD converter.");
//formattingInfo.dump();
currentLiteral.setLength(0);
break;
/*case 'u':
if(i < patternLength) {
char cNext = pattern.charAt(i);
if(cNext >= '0' && cNext <= '9') {
pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
LogLog.debug("USER converter ["+cNext+"].");
formattingInfo.dump();
currentLiteral.setLength(0);
i++;
}
else
LogLog.error("Unexpected char" +cNext+" at position "+i);
}
break;*/
case 'x':
pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
//LogLog.debug("NDC converter.");
currentLiteral.setLength(0);
break;
case 'X':
String xOpt = extractOption();
pc = new MDCPatternConverter(formattingInfo, xOpt);
currentLiteral.setLength(0);
break;
default:
LogLog.error("Unexpected char [" +c+"] at position "+i
+" in conversion patterrn.");
pc = new LiteralPatternConverter(currentLiteral.toString());
currentLiteral.setLength(0);
}
addConverter(pc);
}
protected
void addConverter(PatternConverter pc) {
currentLiteral.setLength(0);
// Add the pattern converter to the list.
addToList(pc);
// Next pattern is assumed to be a literal.
state = LITERAL_STATE;
// Reset formatting info
formattingInfo.reset();
}
// ---------------------------------------------------------------------
// PatternConverters
// ---------------------------------------------------------------------
private static class BasicPatternConverter extends PatternConverter {
int type;
BasicPatternConverter(FormattingInfo formattingInfo, int type) {
super(formattingInfo);
this.type = type;
}
public
String convert(LoggingEvent event) {
switch(type) {
case RELATIVE_TIME_CONVERTER:
return (Long.toString(event.timeStamp - LoggingEvent.getStartTime()));
case THREAD_CONVERTER:
return event.getThreadName();
case LEVEL_CONVERTER:
return event.getLevel().toString();
case NDC_CONVERTER:
return event.getNDC();
case MESSAGE_CONVERTER: {
return event.getRenderedMessage();
}
default: return null;
}
}
}
private static class LiteralPatternConverter extends PatternConverter {
private String literal;
LiteralPatternConverter(String value) {
literal = value;
}
public
final
void format(StringBuffer sbuf, LoggingEvent event) {
sbuf.append(literal);
}
public
String convert(LoggingEvent event) {
return literal;
}
}
private static class DatePatternConverter extends PatternConverter {
private DateFormat df;
private Date date;
DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
super(formattingInfo);
date = new Date();
this.df = df;
}
public
String convert(LoggingEvent event) {
date.setTime(event.timeStamp);
String converted = null;
try {
converted = df.format(date);
}
catch (Exception ex) {
LogLog.error("Error occured while converting date.", ex);
}
return converted;
}
}
private static class MDCPatternConverter extends PatternConverter {
private String key;
MDCPatternConverter(FormattingInfo formattingInfo, String key) {
super(formattingInfo);
this.key = key;
}
public
String convert(LoggingEvent event) {
if (key == null) {
StringBuffer buf = new StringBuffer("{");
Map properties = event.getProperties();
if (properties.size() > 0) {
Object[] keys = properties.keySet().toArray();
Arrays.sort(keys);
for (int i = 0; i < keys.length; i++) {
buf.append('{');
buf.append(keys[i]);
buf.append(',');
buf.append(properties.get(keys[i]));
buf.append('}');
}
}
buf.append('}');
return buf.toString();
} else {
Object val = event.getMDC(key);
if(val == null) {
return null;
} else {
return val.toString();
}
}
}
}
private class LocationPatternConverter extends PatternConverter {
int type;
LocationPatternConverter(FormattingInfo formattingInfo, int type) {
super(formattingInfo);
this.type = type;
}
public
String convert(LoggingEvent event) {
LocationInfo locationInfo = event.getLocationInformation();
switch(type) {
case FULL_LOCATION_CONVERTER:
return locationInfo.fullInfo;
case METHOD_LOCATION_CONVERTER:
return locationInfo.getMethodName();
case LINE_LOCATION_CONVERTER:
return locationInfo.getLineNumber();
case FILE_LOCATION_CONVERTER:
return locationInfo.getFileName();
default: return null;
}
}
}
private static abstract class NamedPatternConverter extends PatternConverter {
int precision;
NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
super(formattingInfo);
this.precision = precision;
}
abstract
String getFullyQualifiedName(LoggingEvent event);
public
String convert(LoggingEvent event) {
String n = getFullyQualifiedName(event);
if(precision <= 0)
return n;
else {
int len = n.length();
// We substract 1 from 'len' when assigning to 'end' to avoid out of
// bounds exception in return r.substring(end+1, len). This can happen if
// precision is 1 and the category name ends with a dot.
int end = len -1 ;
for(int i = precision; i > 0; i--) {
end = n.lastIndexOf('.', end-1);
if(end == -1)
return n;
}
return n.substring(end+1, len);
}
}
}
private class ClassNamePatternConverter extends NamedPatternConverter {
ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
super(formattingInfo, precision);
}
String getFullyQualifiedName(LoggingEvent event) {
return event.getLocationInformation().getClassName();
}
}
private class CategoryPatternConverter extends NamedPatternConverter {
CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
super(formattingInfo, precision);
}
String getFullyQualifiedName(LoggingEvent event) {
return event.getLoggerName();
}
}
}

View File

@@ -1,76 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.io.Writer;
import java.io.FilterWriter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.ErrorCode;
/**
QuietWriter does not throw exceptions when things go
wrong. Instead, it delegates error handling to its {@link ErrorHandler}.
@author Ceki G&uuml;lc&uuml;
@since 0.7.3
*/
public class QuietWriter extends FilterWriter {
protected ErrorHandler errorHandler;
public
QuietWriter(Writer writer, ErrorHandler errorHandler) {
super(writer);
setErrorHandler(errorHandler);
}
public
void write(String string) {
if (string != null) {
try {
out.write(string);
} catch(Exception e) {
errorHandler.error("Failed to write ["+string+"].", e,
ErrorCode.WRITE_FAILURE);
}
}
}
public
void flush() {
try {
out.flush();
} catch(Exception e) {
errorHandler.error("Failed to flush writer,", e,
ErrorCode.FLUSH_FAILURE);
}
}
public
void setErrorHandler(ErrorHandler eh) {
if(eh == null) {
// This is a programming error on the part of the enclosing appender.
throw new IllegalArgumentException("Attempted to set null ErrorHandler.");
} else {
this.errorHandler = eh;
}
}
}

View File

@@ -1,65 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Date;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.DateFormat;
/**
Formats a {@link Date} by printing the number of milliseconds
elapsed since construction of the format. This is the fastest
printing DateFormat in the package.
@author Ceki G&uuml;lc&uuml;
@since 0.7.5
*/
public class RelativeTimeDateFormat extends DateFormat {
private static final long serialVersionUID = 7055751607085611984L;
protected final long startTime;
public
RelativeTimeDateFormat() {
this.startTime = System.currentTimeMillis();
}
/**
Appends to <code>sbuf</code> the number of milliseconds elapsed
since the start of the application.
@since 0.7.5
*/
public
StringBuffer format(Date date, StringBuffer sbuf,
FieldPosition fieldPosition) {
//System.err.println(":"+ date.getTime() + " - " + startTime);
return sbuf.append((date.getTime() - startTime));
}
/**
This method does not do anything but return <code>null</code>.
*/
public
Date parse(java.lang.String s, ParsePosition pos) {
return null;
}
}

View File

@@ -1,56 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.io.Writer;
import org.apache.log4j.spi.ErrorHandler;
/**
SyslogQuietWriter extends QuietWriter by prepending the syslog
level code before each printed String.
@since 0.7.3
*/
public class SyslogQuietWriter extends QuietWriter {
int syslogFacility;
int level;
public
SyslogQuietWriter(Writer writer, int syslogFacility, ErrorHandler eh) {
super(writer, eh);
this.syslogFacility = syslogFacility;
}
public
void setLevel(int level) {
this.level = level;
}
public
void setSyslogFacility(int syslogFacility) {
this.syslogFacility = syslogFacility;
}
public
void write(String string) {
super.write("<"+(syslogFacility | level)+">" + string);
}
}

View File

@@ -1,145 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.io.Writer;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.DatagramPacket;
import java.net.UnknownHostException;
import java.net.SocketException;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
/**
SyslogWriter is a wrapper around the java.net.DatagramSocket class
so that it behaves like a java.io.Writer.
@since 0.7.3
*/
public class SyslogWriter extends Writer {
final int SYSLOG_PORT = 514;
/**
* Host string from last constructed SyslogWriter.
* @deprecated
*/
static String syslogHost;
private InetAddress address;
private final int port;
private DatagramSocket ds;
/**
* Constructs a new instance of SyslogWriter.
* @param syslogHost host name, may not be null. A port
* may be specified by following the name or IPv4 literal address with
* a colon and a decimal port number. To specify a port with an IPv6
* address, enclose the IPv6 address in square brackets before appending
* the colon and decimal port number.
*/
public
SyslogWriter(final String syslogHost) {
SyslogWriter.syslogHost = syslogHost;
if (syslogHost == null) {
throw new NullPointerException("syslogHost");
}
String host = syslogHost;
int urlPort = -1;
//
// If not an unbracketed IPv6 address then
// parse as a URL
//
if (host.indexOf("[") != -1 || host.indexOf(':') == host.lastIndexOf(':')) {
try {
URL url = new URL("http://" + host);
if (url.getHost() != null) {
host = url.getHost();
// if host is a IPv6 literal, strip off the brackets
if(host.startsWith("[") && host.charAt(host.length() - 1) == ']') {
host = host.substring(1, host.length() - 1);
}
urlPort = url.getPort();
}
} catch(MalformedURLException e) {
LogLog.error("Malformed URL: will attempt to interpret as InetAddress.", e);
}
}
if (urlPort == -1) {
urlPort = SYSLOG_PORT;
}
port = urlPort;
try {
this.address = InetAddress.getByName(host);
}
catch (UnknownHostException e) {
LogLog.error("Could not find " + host +
". All logging will FAIL.", e);
}
try {
this.ds = new DatagramSocket();
}
catch (SocketException e) {
e.printStackTrace();
LogLog.error("Could not instantiate DatagramSocket to " + host +
". All logging will FAIL.", e);
}
}
public
void write(char[] buf, int off, int len) throws IOException {
this.write(new String(buf, off, len));
}
public
void write(final String string) throws IOException {
if(this.ds != null && this.address != null) {
byte[] bytes = string.getBytes();
//
// syslog packets must be less than 1024 bytes
//
int bytesLength = bytes.length;
if (bytesLength >= 1024) {
bytesLength = 1024;
}
DatagramPacket packet = new DatagramPacket(bytes, bytesLength,
address, port);
ds.send(packet);
}
}
public
void flush() {}
public void close() {
if (ds != null) {
ds.close();
}
}
}

View File

@@ -1,42 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
import java.util.Hashtable;
/**
<code>ThreadLocalMap</code> extends {@link InheritableThreadLocal}
to bequeath a copy of the hashtable of the MDC of the parent
thread.
@author Ceki G&uuml;lc&uuml;
@since 1.2
*/
final public class ThreadLocalMap extends InheritableThreadLocal {
public
final
Object childValue(Object parentValue) {
Hashtable ht = (Hashtable) parentValue;
if(ht != null) {
return ht.clone();
} else {
return null;
}
}
}

View File

@@ -1,113 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
/**
Utility class for transforming strings.
@author Ceki G&uuml;lc&uuml;
@author Michael A. McAngus
*/
public class Transform {
private static final String CDATA_START = "<![CDATA[";
private static final String CDATA_END = "]]>";
private static final String CDATA_PSEUDO_END = "]]&gt;";
private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END + CDATA_START;
private static final int CDATA_END_LEN = CDATA_END.length();
/**
* This method takes a string which may contain HTML tags (ie,
* &lt;b&gt;, &lt;table&gt;, etc) and replaces any
* '<', '>' , '&' or '"'
* characters with respective predefined entity references.
*
* @param input The text to be converted.
* @return The input string with the special characters replaced.
* */
static public String escapeTags(final String input) {
//Check if the string is null, zero length or devoid of special characters
// if so, return what was sent in.
if(input == null
|| input.length() == 0
|| (input.indexOf('"') == -1 &&
input.indexOf('&') == -1 &&
input.indexOf('<') == -1 &&
input.indexOf('>') == -1)) {
return input;
}
//Use a StringBuffer in lieu of String concatenation -- it is
//much more efficient this way.
StringBuffer buf = new StringBuffer(input.length() + 6);
char ch = ' ';
int len = input.length();
for(int i=0; i < len; i++) {
ch = input.charAt(i);
if (ch > '>') {
buf.append(ch);
} else if(ch == '<') {
buf.append("&lt;");
} else if(ch == '>') {
buf.append("&gt;");
} else if(ch == '&') {
buf.append("&amp;");
} else if(ch == '"') {
buf.append("&quot;");
} else {
buf.append(ch);
}
}
return buf.toString();
}
/**
* Ensures that embeded CDEnd strings (]]>) are handled properly
* within message, NDC and throwable tag text.
*
* @param buf StringBuffer holding the XML data to this point. The
* initial CDStart (<![CDATA[) and final CDEnd (]]>) of the CDATA
* section are the responsibility of the calling method.
* @param str The String that is inserted into an existing CDATA Section within buf.
* */
static public void appendEscapingCDATA(final StringBuffer buf,
final String str) {
if (str != null) {
int end = str.indexOf(CDATA_END);
if (end < 0) {
buf.append(str);
} else {
int start = 0;
while (end > -1) {
buf.append(str.substring(start, end));
buf.append(CDATA_EMBEDED_END);
start = end + CDATA_END_LEN;
if (start < str.length()) {
end = str.indexOf(CDATA_END, start);
} else {
return;
}
}
buf.append(str.substring(start));
}
}
}
}

View File

@@ -1,33 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html> <head>
<title></title>
</head>
<body>
<p>This package is used internally.
<hr>
<address></address>
<!-- hhmts start -->
Last modified: Sat Jul 3 15:12:58 MDT 1999
<!-- hhmts end -->
</body> </html>

View File

@@ -1,398 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
/**
The JDBCAppender provides for sending log events to a database.
<p><b><font color="#FF2222">WARNING: This version of JDBCAppender
is very likely to be completely replaced in the future. Moreoever,
it does not log exceptions</font></b>.
<p>Each append call adds to an <code>ArrayList</code> buffer. When
the buffer is filled each log event is placed in a sql statement
(configurable) and executed.
<b>BufferSize</b>, <b>db URL</b>, <b>User</b>, & <b>Password</b> are
configurable options in the standard log4j ways.
<p>The <code>setSql(String sql)</code> sets the SQL statement to be
used for logging -- this statement is sent to a
<code>PatternLayout</code> (either created automaticly by the
appender or added by the user). Therefore by default all the
conversion patterns in <code>PatternLayout</code> can be used
inside of the statement. (see the test cases for examples)
<p>Overriding the {@link #getLogStatement} method allows more
explicit control of the statement used for logging.
<p>For use as a base class:
<ul>
<li>Override <code>getConnection()</code> to pass any connection
you want. Typically this is used to enable application wide
connection pooling.
<li>Override <code>closeConnection(Connection con)</code> -- if
you override getConnection make sure to implement
<code>closeConnection</code> to handle the connection you
generated. Typically this would return the connection to the
pool it came from.
<li>Override <code>getLogStatement(LoggingEvent event)</code> to
produce specialized or dynamic statements. The default uses the
sql option value.
</ul>
@author Kevin Steppe (<A HREF="mailto:ksteppe@pacbell.net">ksteppe@pacbell.net</A>)
*/
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
implements org.apache.log4j.Appender {
/**
* URL of the DB for default connection handling
*/
protected String databaseURL = "jdbc:odbc:myDB";
/**
* User to connect as for default connection handling
*/
protected String databaseUser = "me";
/**
* User to use for default connection handling
*/
protected String databasePassword = "mypassword";
/**
* Connection used by default. The connection is opened the first time it
* is needed and then held open until the appender is closed (usually at
* garbage collection). This behavior is best modified by creating a
* sub-class and overriding the <code>getConnection</code> and
* <code>closeConnection</code> methods.
*/
protected Connection connection = null;
/**
* Stores the string given to the pattern layout for conversion into a SQL
* statement, eg: insert into LogTable (Thread, Class, Message) values
* ("%t", "%c", "%m").
*
* Be careful of quotes in your messages!
*
* Also see PatternLayout.
*/
protected String sqlStatement = "";
/**
* size of LoggingEvent buffer before writting to the database.
* Default is 1.
*/
protected int bufferSize = 1;
/**
* ArrayList holding the buffer of Logging Events.
*/
protected ArrayList buffer;
/**
* Helper object for clearing out the buffer
*/
protected ArrayList removes;
private boolean locationInfo = false;
public JDBCAppender() {
super();
buffer = new ArrayList(bufferSize);
removes = new ArrayList(bufferSize);
}
/**
* Gets whether the location of the logging request call
* should be captured.
*
* @since 1.2.16
* @return the current value of the <b>LocationInfo</b> option.
*/
public boolean getLocationInfo() {
return locationInfo;
}
/**
* The <b>LocationInfo</b> option takes a boolean value. By default, it is
* set to false which means there will be no effort to extract the location
* information related to the event. As a result, the event that will be
* ultimately logged will likely to contain the wrong location information
* (if present in the log format).
* <p/>
* <p/>
* Location information extraction is comparatively very slow and should be
* avoided unless performance is not a concern.
* </p>
* @since 1.2.16
* @param flag true if location information should be extracted.
*/
public void setLocationInfo(final boolean flag) {
locationInfo = flag;
}
/**
* Adds the event to the buffer. When full the buffer is flushed.
*/
public void append(LoggingEvent event) {
event.getNDC();
event.getThreadName();
// Get a copy of this thread's MDC.
event.getMDCCopy();
if (locationInfo) {
event.getLocationInformation();
}
event.getRenderedMessage();
event.getThrowableStrRep();
buffer.add(event);
if (buffer.size() >= bufferSize)
flushBuffer();
}
/**
* By default getLogStatement sends the event to the required Layout object.
* The layout will format the given pattern into a workable SQL string.
*
* Overriding this provides direct access to the LoggingEvent
* when constructing the logging statement.
*
*/
protected String getLogStatement(LoggingEvent event) {
return getLayout().format(event);
}
/**
*
* Override this to provide an alertnate method of getting
* connections (such as caching). One method to fix this is to open
* connections at the start of flushBuffer() and close them at the
* end. I use a connection pool outside of JDBCAppender which is
* accessed in an override of this method.
* */
protected void execute(String sql) throws SQLException {
Connection con = null;
Statement stmt = null;
try {
con = getConnection();
stmt = con.createStatement();
stmt.executeUpdate(sql);
} catch (SQLException e) {
if (stmt != null)
stmt.close();
throw e;
}
stmt.close();
closeConnection(con);
//System.out.println("Execute: " + sql);
}
/**
* Override this to return the connection to a pool, or to clean up the
* resource.
*
* The default behavior holds a single connection open until the appender
* is closed (typically when garbage collected).
*/
protected void closeConnection(Connection con) {
}
/**
* Override this to link with your connection pooling system.
*
* By default this creates a single connection which is held open
* until the object is garbage collected.
*/
protected Connection getConnection() throws SQLException {
if (!DriverManager.getDrivers().hasMoreElements())
setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
if (connection == null) {
connection = DriverManager.getConnection(databaseURL, databaseUser,
databasePassword);
}
return connection;
}
/**
* Closes the appender, flushing the buffer first then closing the default
* connection if it is open.
*/
public void close()
{
flushBuffer();
try {
if (connection != null && !connection.isClosed())
connection.close();
} catch (SQLException e) {
errorHandler.error("Error closing connection", e, ErrorCode.GENERIC_FAILURE);
}
this.closed = true;
}
/**
* loops through the buffer of LoggingEvents, gets a
* sql string from getLogStatement() and sends it to execute().
* Errors are sent to the errorHandler.
*
* If a statement fails the LoggingEvent stays in the buffer!
*/
public void flushBuffer() {
//Do the actual logging
removes.ensureCapacity(buffer.size());
for (Iterator i = buffer.iterator(); i.hasNext();) {
try {
LoggingEvent logEvent = (LoggingEvent)i.next();
String sql = getLogStatement(logEvent);
execute(sql);
removes.add(logEvent);
}
catch (SQLException e) {
errorHandler.error("Failed to excute sql", e,
ErrorCode.FLUSH_FAILURE);
}
}
// remove from the buffer any events that were reported
buffer.removeAll(removes);
// clear the buffer of reported events
removes.clear();
}
/** closes the appender before disposal */
public void finalize() {
close();
}
/**
* JDBCAppender requires a layout.
* */
public boolean requiresLayout() {
return true;
}
/**
*
*/
public void setSql(String s) {
sqlStatement = s;
if (getLayout() == null) {
this.setLayout(new PatternLayout(s));
}
else {
((PatternLayout)getLayout()).setConversionPattern(s);
}
}
/**
* Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
*/
public String getSql() {
return sqlStatement;
}
public void setUser(String user) {
databaseUser = user;
}
public void setURL(String url) {
databaseURL = url;
}
public void setPassword(String password) {
databasePassword = password;
}
public void setBufferSize(int newBufferSize) {
bufferSize = newBufferSize;
buffer.ensureCapacity(bufferSize);
removes.ensureCapacity(bufferSize);
}
public String getUser() {
return databaseUser;
}
public String getURL() {
return databaseURL;
}
public String getPassword() {
return databasePassword;
}
public int getBufferSize() {
return bufferSize;
}
/**
* Ensures that the given driver class has been loaded for sql connection
* creation.
*/
public void setDriver(String driverClass) {
try {
Class.forName(driverClass);
} catch (Exception e) {
errorHandler.error("Failed to load driver", e,
ErrorCode.GENERIC_FAILURE);
}
}
}

View File

@@ -1,23 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<body>
The JDBCAppender provides for sending log events to a database.
</body>
</html>

View File

@@ -1,187 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.DynamicMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
import javax.management.MBeanRegistration;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.RuntimeOperationsException;
import org.apache.log4j.Logger;
import org.apache.log4j.Appender;
public abstract class AbstractDynamicMBean implements DynamicMBean,
MBeanRegistration {
String dClassName;
MBeanServer server;
private final Vector mbeanList = new Vector();
/**
* Get MBean name.
* @param appender appender, may not be null.
* @return name.
* @since 1.2.16
*/
static protected String getAppenderName(final Appender appender){
String name = appender.getName();
if (name == null || name.trim().length() == 0) {
// try to get some form of a name, because null is not allowed (exception), and empty string certainly isn't useful in JMX..
name = appender.toString();
}
return name;
}
/**
* Enables the to get the values of several attributes of the Dynamic MBean.
*/
public
AttributeList getAttributes(String[] attributeNames) {
// Check attributeNames is not null to avoid NullPointerException later on
if (attributeNames == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("attributeNames[] cannot be null"),
"Cannot invoke a getter of " + dClassName);
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, return an empty result list
if (attributeNames.length == 0)
return resultList;
// build the result attribute list
for (int i=0 ; i<attributeNames.length ; i++){
try {
Object value = getAttribute((String) attributeNames[i]);
resultList.add(new Attribute(attributeNames[i],value));
} catch (JMException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
return(resultList);
}
/**
* Sets the values of several attributes of the Dynamic MBean, and returns the
* list of attributes that have been set.
*/
public AttributeList setAttributes(AttributeList attributes) {
// Check attributes is not null to avoid NullPointerException later on
if (attributes == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("AttributeList attributes cannot be null"),
"Cannot invoke a setter of " + dClassName);
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, nothing more to do
if (attributes.isEmpty())
return resultList;
// for each attribute, try to set it and add to the result list if successfull
for (Iterator i = attributes.iterator(); i.hasNext();) {
Attribute attr = (Attribute) i.next();
try {
setAttribute(attr);
String name = attr.getName();
Object value = getAttribute(name);
resultList.add(new Attribute(name,value));
} catch(JMException e) {
e.printStackTrace();
} catch(RuntimeException e) {
e.printStackTrace();
}
}
return(resultList);
}
protected
abstract
Logger getLogger();
public
void postDeregister() {
getLogger().debug("postDeregister is called.");
}
public
void postRegister(java.lang.Boolean registrationDone) {
}
public
ObjectName preRegister(MBeanServer server, ObjectName name) {
getLogger().debug("preRegister called. Server="+server+ ", name="+name);
this.server = server;
return name;
}
/**
* Registers MBean instance in the attached server. Must <em>NOT</em>
* be called before registration of this instance.
*/
protected
void registerMBean(Object mbean, ObjectName objectName)
throws InstanceAlreadyExistsException, MBeanRegistrationException,
NotCompliantMBeanException {
server.registerMBean(mbean, objectName);
mbeanList.add(objectName);
}
/**
* Performs cleanup for deregistering this MBean. Default implementation
* unregisters MBean instances which are registered using
* {@link #registerMBean(Object mbean, ObjectName objectName)}.
*/
public
void preDeregister() {
getLogger().debug("preDeregister called.");
Enumeration iterator = mbeanList.elements();
while (iterator.hasMoreElements()) {
ObjectName name = (ObjectName) iterator.nextElement();
try {
server.unregisterMBean(name);
} catch (InstanceNotFoundException e) {
getLogger().warn("Missing MBean " + name.getCanonicalName());
} catch (MBeanRegistrationException e) {
getLogger().warn("Failed unregistering " + name.getCanonicalName());
}
}
}
}

View File

@@ -1,131 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import org.apache.log4j.Logger;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import java.lang.reflect.InvocationTargetException;
import java.io.InterruptedIOException;
/**
* Manages an instance of com.sun.jdmk.comm.HtmlAdapterServer which
* was provided for demonstration purposes in the
* Java Management Extensions Reference Implementation 1.2.1.
* This class is provided to maintain compatibility with earlier
* versions of log4j and use in new code is discouraged.
*
* @deprecated
*/
public class Agent {
/**
* Diagnostic logger.
* @deprecated
*/
static Logger log = Logger.getLogger(Agent.class);
/**
* Create new instance.
* @deprecated
*/
public Agent() {
}
/**
* Creates a new instance of com.sun.jdmk.comm.HtmlAdapterServer
* using reflection.
*
* @since 1.2.16
* @return new instance.
*/
private static Object createServer() {
Object newInstance = null;
try {
newInstance = Class.forName(
"com.sun.jdmk.comm.HtmlAdapterServer").newInstance();
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex.toString());
} catch (InstantiationException ex) {
throw new RuntimeException(ex.toString());
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex.toString());
}
return newInstance;
}
/**
* Invokes HtmlAdapterServer.start() using reflection.
*
* @since 1.2.16
* @param server instance of com.sun.jdmk.comm.HtmlAdapterServer.
*/
private static void startServer(final Object server) {
try {
server.getClass().getMethod("start", new Class[0]).
invoke(server, new Object[0]);
} catch(InvocationTargetException ex) {
Throwable cause = ex.getTargetException();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause != null) {
if (cause instanceof InterruptedException
|| cause instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
throw new RuntimeException(cause.toString());
} else {
throw new RuntimeException();
}
} catch(NoSuchMethodException ex) {
throw new RuntimeException(ex.toString());
} catch(IllegalAccessException ex) {
throw new RuntimeException(ex.toString());
}
}
/**
* Starts instance of HtmlAdapterServer.
* @deprecated
*/
public void start() {
MBeanServer server = MBeanServerFactory.createMBeanServer();
Object html = createServer();
try {
log.info("Registering HtmlAdaptorServer instance.");
server.registerMBean(html, new ObjectName("Adaptor:name=html,port=8082"));
log.info("Registering HierarchyDynamicMBean instance.");
HierarchyDynamicMBean hdm = new HierarchyDynamicMBean();
server.registerMBean(hdm, new ObjectName("log4j:hiearchy=default"));
} catch(JMException e) {
log.error("Problem while registering MBeans instances.", e);
return;
} catch(RuntimeException e) {
log.error("Problem while registering MBeans instances.", e);
return;
}
startServer(html);
}
}

View File

@@ -1,346 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import org.apache.log4j.Appender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.OptionHandler;
import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Vector;
import java.io.InterruptedIOException;
public class AppenderDynamicMBean extends AbstractDynamicMBean {
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
private Vector dAttributes = new Vector();
private String dClassName = this.getClass().getName();
private Hashtable dynamicProps = new Hashtable(5);
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[2];
private String dDescription =
"This MBean acts as a management facade for log4j appenders.";
// This category instance is for logging.
private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
// We wrap this appender instance.
private Appender appender;
public AppenderDynamicMBean(Appender appender) throws IntrospectionException {
this.appender = appender;
buildDynamicMBeanInfo();
}
private
void buildDynamicMBeanInfo() throws IntrospectionException {
Constructor[] constructors = this.getClass().getConstructors();
dConstructors[0] = new MBeanConstructorInfo(
"AppenderDynamicMBean(): Constructs a AppenderDynamicMBean instance",
constructors[0]);
BeanInfo bi = Introspector.getBeanInfo(appender.getClass());
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
int size = pd.length;
for(int i = 0; i < size; i++) {
String name = pd[i].getName();
Method readMethod = pd[i].getReadMethod();
Method writeMethod = pd[i].getWriteMethod();
if(readMethod != null) {
Class returnClass = readMethod.getReturnType();
if(isSupportedType(returnClass)) {
String returnClassName;
if(returnClass.isAssignableFrom(Priority.class)) {
returnClassName = "java.lang.String";
} else {
returnClassName = returnClass.getName();
}
dAttributes.add(new MBeanAttributeInfo(name,
returnClassName,
"Dynamic",
true,
writeMethod != null,
false));
dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
}
}
}
MBeanParameterInfo[] params = new MBeanParameterInfo[0];
dOperations[0] = new MBeanOperationInfo("activateOptions",
"activateOptions(): add an appender",
params,
"void",
MBeanOperationInfo.ACTION);
params = new MBeanParameterInfo[1];
params[0] = new MBeanParameterInfo("layout class", "java.lang.String",
"layout class");
dOperations[1] = new MBeanOperationInfo("setLayout",
"setLayout(): add a layout",
params,
"void",
MBeanOperationInfo.ACTION);
}
private
boolean isSupportedType(Class clazz) {
if(clazz.isPrimitive()) {
return true;
}
if(clazz == String.class) {
return true;
}
if(clazz.isAssignableFrom(Priority.class)) {
return true;
}
return false;
}
public
MBeanInfo getMBeanInfo() {
cat.debug("getMBeanInfo called.");
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
dAttributes.toArray(attribs);
return new MBeanInfo(dClassName,
dDescription,
attribs,
dConstructors,
dOperations,
new MBeanNotificationInfo[0]);
}
public
Object invoke(String operationName, Object params[], String signature[])
throws MBeanException,
ReflectionException {
if(operationName.equals("activateOptions") &&
appender instanceof OptionHandler) {
OptionHandler oh = (OptionHandler) appender;
oh.activateOptions();
return "Options activated.";
} else if (operationName.equals("setLayout")) {
Layout layout = (Layout) OptionConverter.instantiateByClassName((String)
params[0],
Layout.class,
null);
appender.setLayout(layout);
registerLayoutMBean(layout);
}
return null;
}
void registerLayoutMBean(Layout layout) {
if(layout == null)
return;
String name = getAppenderName(appender)+",layout="+layout.getClass().getName();
cat.debug("Adding LayoutMBean:"+name);
ObjectName objectName = null;
try {
LayoutDynamicMBean appenderMBean = new LayoutDynamicMBean(layout);
objectName = new ObjectName("log4j:appender="+name);
if (!server.isRegistered(objectName)) {
registerMBean(appenderMBean, objectName);
dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
"The " + name + " layout.", true, true, false));
}
} catch(JMException e) {
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
} catch(java.beans.IntrospectionException e) {
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
} catch(RuntimeException e) {
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
}
}
protected
Logger getLogger() {
return cat;
}
public
Object getAttribute(String attributeName) throws AttributeNotFoundException,
MBeanException,
ReflectionException {
// Check attributeName is not null to avoid NullPointerException later on
if (attributeName == null) {
throw new RuntimeOperationsException(new IllegalArgumentException(
"Attribute name cannot be null"),
"Cannot invoke a getter of " + dClassName + " with null attribute name");
}
cat.debug("getAttribute called with ["+attributeName+"].");
if(attributeName.startsWith("appender="+appender.getName()+",layout")) {
try {
return new ObjectName("log4j:"+attributeName );
} catch(MalformedObjectNameException e) {
cat.error("attributeName", e);
} catch(RuntimeException e) {
cat.error("attributeName", e);
}
}
MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
//cat.debug("----name="+attributeName+", b="+b);
if(mu != null && mu.readMethod != null) {
try {
return mu.readMethod.invoke(appender, null);
} catch(IllegalAccessException e) {
return null;
} catch(InvocationTargetException e) {
if (e.getTargetException() instanceof InterruptedException
|| e.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
return null;
} catch(RuntimeException e) {
return null;
}
}
// If attributeName has not been recognized throw an AttributeNotFoundException
throw(new AttributeNotFoundException("Cannot find " + attributeName +
" attribute in " + dClassName));
}
public
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
// Check attribute is not null to avoid NullPointerException later on
if (attribute == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute cannot be null"),
"Cannot invoke a setter of " + dClassName +
" with null attribute");
}
String name = attribute.getName();
Object value = attribute.getValue();
if (name == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"),
"Cannot invoke the setter of "+dClassName+
" with null attribute name");
}
MethodUnion mu = (MethodUnion) dynamicProps.get(name);
if(mu != null && mu.writeMethod != null) {
Object[] o = new Object[1];
Class[] params = mu.writeMethod.getParameterTypes();
if(params[0] == org.apache.log4j.Priority.class) {
value = OptionConverter.toLevel((String) value,
(Level) getAttribute(name));
}
o[0] = value;
try {
mu.writeMethod.invoke(appender, o);
} catch(InvocationTargetException e) {
if (e.getTargetException() instanceof InterruptedException
|| e.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
cat.error("FIXME", e);
} catch(IllegalAccessException e) {
cat.error("FIXME", e);
} catch(RuntimeException e) {
cat.error("FIXME", e);
}
} else if(name.endsWith(".layout")) {
} else {
throw(new AttributeNotFoundException("Attribute " + name +
" not found in " +
this.getClass().getName()));
}
}
public
ObjectName preRegister(MBeanServer server, ObjectName name) {
cat.debug("preRegister called. Server="+server+ ", name="+name);
this.server = server;
registerLayoutMBean(appender.getLayout());
return name;
}
}

View File

@@ -1,302 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import org.apache.log4j.Appender;
import org.apache.log4j.Category;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.HierarchyEventListener;
import org.apache.log4j.spi.LoggerRepository;
import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationFilter;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;
import java.lang.reflect.Constructor;
import java.util.Vector;
public class HierarchyDynamicMBean extends AbstractDynamicMBean
implements HierarchyEventListener,
NotificationBroadcaster {
static final String ADD_APPENDER = "addAppender.";
static final String THRESHOLD = "threshold";
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
private Vector vAttributes = new Vector();
private String dClassName = this.getClass().getName();
private String dDescription =
"This MBean acts as a management facade for org.apache.log4j.Hierarchy.";
private NotificationBroadcasterSupport nbs = new NotificationBroadcasterSupport();
private LoggerRepository hierarchy;
private static Logger log = Logger.getLogger(HierarchyDynamicMBean.class);
public HierarchyDynamicMBean() {
hierarchy = LogManager.getLoggerRepository();
buildDynamicMBeanInfo();
}
private
void buildDynamicMBeanInfo() {
Constructor[] constructors = this.getClass().getConstructors();
dConstructors[0] = new MBeanConstructorInfo(
"HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
constructors[0]);
vAttributes.add(new MBeanAttributeInfo(THRESHOLD,
"java.lang.String",
"The \"threshold\" state of the hiearchy.",
true,
true,
false));
MBeanParameterInfo[] params = new MBeanParameterInfo[1];
params[0] = new MBeanParameterInfo("name", "java.lang.String",
"Create a logger MBean" );
dOperations[0] = new MBeanOperationInfo("addLoggerMBean",
"addLoggerMBean(): add a loggerMBean",
params ,
"javax.management.ObjectName",
MBeanOperationInfo.ACTION);
}
public
ObjectName addLoggerMBean(String name) {
Logger cat = LogManager.exists(name);
if(cat != null) {
return addLoggerMBean(cat);
} else {
return null;
}
}
ObjectName addLoggerMBean(Logger logger) {
String name = logger.getName();
ObjectName objectName = null;
try {
LoggerDynamicMBean loggerMBean = new LoggerDynamicMBean(logger);
objectName = new ObjectName("log4j", "logger", name);
if (!server.isRegistered(objectName)) {
registerMBean(loggerMBean, objectName);
NotificationFilterSupport nfs = new NotificationFilterSupport();
nfs.enableType(ADD_APPENDER + logger.getName());
log.debug("---Adding logger [" + name + "] as listener.");
nbs.addNotificationListener(loggerMBean, nfs, null);
vAttributes.add(new MBeanAttributeInfo("logger=" + name, "javax.management.ObjectName",
"The " + name + " logger.", true, true, // this makes the object
// clickable
false));
}
} catch(JMException e) {
log.error("Could not add loggerMBean for ["+name+"].", e);
} catch(RuntimeException e) {
log.error("Could not add loggerMBean for ["+name+"].", e);
}
return objectName;
}
public
void addNotificationListener(NotificationListener listener,
NotificationFilter filter,
java.lang.Object handback) {
nbs.addNotificationListener(listener, filter, handback);
}
protected
Logger getLogger() {
return log;
}
public
MBeanInfo getMBeanInfo() {
//cat.debug("getMBeanInfo called.");
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[vAttributes.size()];
vAttributes.toArray(attribs);
return new MBeanInfo(dClassName,
dDescription,
attribs,
dConstructors,
dOperations,
new MBeanNotificationInfo[0]);
}
public
MBeanNotificationInfo[] getNotificationInfo(){
return nbs.getNotificationInfo();
}
public
Object invoke(String operationName,
Object params[],
String signature[]) throws MBeanException,
ReflectionException {
if (operationName == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Operation name cannot be null"),
"Cannot invoke a null operation in " + dClassName);
}
// Check for a recognized operation name and call the corresponding operation
if(operationName.equals("addLoggerMBean")) {
return addLoggerMBean((String)params[0]);
} else {
throw new ReflectionException(
new NoSuchMethodException(operationName),
"Cannot find the operation " + operationName + " in " + dClassName);
}
}
public
Object getAttribute(String attributeName) throws AttributeNotFoundException,
MBeanException,
ReflectionException {
// Check attributeName is not null to avoid NullPointerException later on
if (attributeName == null) {
throw new RuntimeOperationsException(new IllegalArgumentException(
"Attribute name cannot be null"),
"Cannot invoke a getter of " + dClassName + " with null attribute name");
}
log.debug("Called getAttribute with ["+attributeName+"].");
// Check for a recognized attributeName and call the corresponding getter
if (attributeName.equals(THRESHOLD)) {
return hierarchy.getThreshold();
} else if(attributeName.startsWith("logger")) {
int k = attributeName.indexOf("%3D");
String val = attributeName;
if(k > 0) {
val = attributeName.substring(0, k)+'='+ attributeName.substring(k+3);
}
try {
return new ObjectName("log4j:"+val);
} catch(JMException e) {
log.error("Could not create ObjectName" + val);
} catch(RuntimeException e) {
log.error("Could not create ObjectName" + val);
}
}
// If attributeName has not been recognized throw an AttributeNotFoundException
throw(new AttributeNotFoundException("Cannot find " + attributeName +
" attribute in " + dClassName));
}
public
void addAppenderEvent(Category logger, Appender appender) {
log.debug("addAppenderEvent called: logger="+logger.getName()+
", appender="+appender.getName());
Notification n = new Notification(ADD_APPENDER+logger.getName(), this, 0);
n.setUserData(appender);
log.debug("sending notification.");
nbs.sendNotification(n);
}
public
void removeAppenderEvent(Category cat, Appender appender) {
log.debug("removeAppenderCalled: logger="+cat.getName()+
", appender="+appender.getName());
}
public
void postRegister(java.lang.Boolean registrationDone) {
log.debug("postRegister is called.");
hierarchy.addHierarchyEventListener(this);
Logger root = hierarchy.getRootLogger();
addLoggerMBean(root);
}
public
void removeNotificationListener(NotificationListener listener)
throws ListenerNotFoundException {
nbs.removeNotificationListener(listener);
}
public
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
// Check attribute is not null to avoid NullPointerException later on
if (attribute == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute cannot be null"),
"Cannot invoke a setter of "+dClassName+" with null attribute");
}
String name = attribute.getName();
Object value = attribute.getValue();
if (name == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"),
"Cannot invoke the setter of "+dClassName+
" with null attribute name");
}
if(name.equals(THRESHOLD)) {
Level l = OptionConverter.toLevel((String) value,
hierarchy.getThreshold());
hierarchy.setThreshold(l);
}
}
}

View File

@@ -1,274 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import java.lang.reflect.Constructor;
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.OptionHandler;
import java.util.Vector;
import java.util.Hashtable;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanInfo;
import javax.management.Attribute;
import javax.management.MBeanException;
import javax.management.AttributeNotFoundException;
import javax.management.RuntimeOperationsException;
import javax.management.ReflectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import java.beans.Introspector;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.beans.IntrospectionException;
import java.io.InterruptedIOException;
public class LayoutDynamicMBean extends AbstractDynamicMBean {
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
private Vector dAttributes = new Vector();
private String dClassName = this.getClass().getName();
private Hashtable dynamicProps = new Hashtable(5);
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
private String dDescription =
"This MBean acts as a management facade for log4j layouts.";
// This category instance is for logging.
private static Logger cat = Logger.getLogger(LayoutDynamicMBean.class);
// We wrap this layout instance.
private Layout layout;
public LayoutDynamicMBean(Layout layout) throws IntrospectionException {
this.layout = layout;
buildDynamicMBeanInfo();
}
private
void buildDynamicMBeanInfo() throws IntrospectionException {
Constructor[] constructors = this.getClass().getConstructors();
dConstructors[0] = new MBeanConstructorInfo(
"LayoutDynamicMBean(): Constructs a LayoutDynamicMBean instance",
constructors[0]);
BeanInfo bi = Introspector.getBeanInfo(layout.getClass());
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
int size = pd.length;
for(int i = 0; i < size; i++) {
String name = pd[i].getName();
Method readMethod = pd[i].getReadMethod();
Method writeMethod = pd[i].getWriteMethod();
if(readMethod != null) {
Class returnClass = readMethod.getReturnType();
if(isSupportedType(returnClass)) {
String returnClassName;
if(returnClass.isAssignableFrom(Level.class)) {
returnClassName = "java.lang.String";
} else {
returnClassName = returnClass.getName();
}
dAttributes.add(new MBeanAttributeInfo(name,
returnClassName,
"Dynamic",
true,
writeMethod != null,
false));
dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
}
}
}
MBeanParameterInfo[] params = new MBeanParameterInfo[0];
dOperations[0] = new MBeanOperationInfo("activateOptions",
"activateOptions(): add an layout",
params,
"void",
MBeanOperationInfo.ACTION);
}
private
boolean isSupportedType(Class clazz) {
if(clazz.isPrimitive()) {
return true;
}
if(clazz == String.class) {
return true;
}
if(clazz.isAssignableFrom(Level.class)) {
return true;
}
return false;
}
public
MBeanInfo getMBeanInfo() {
cat.debug("getMBeanInfo called.");
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
dAttributes.toArray(attribs);
return new MBeanInfo(dClassName,
dDescription,
attribs,
dConstructors,
dOperations,
new MBeanNotificationInfo[0]);
}
public
Object invoke(String operationName, Object params[], String signature[])
throws MBeanException,
ReflectionException {
if(operationName.equals("activateOptions") &&
layout instanceof OptionHandler) {
OptionHandler oh = (OptionHandler) layout;
oh.activateOptions();
return "Options activated.";
}
return null;
}
protected
Logger getLogger() {
return cat;
}
public
Object getAttribute(String attributeName) throws AttributeNotFoundException,
MBeanException,
ReflectionException {
// Check attributeName is not null to avoid NullPointerException later on
if (attributeName == null) {
throw new RuntimeOperationsException(new IllegalArgumentException(
"Attribute name cannot be null"),
"Cannot invoke a getter of " + dClassName + " with null attribute name");
}
MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
cat.debug("----name="+attributeName+", mu="+mu);
if(mu != null && mu.readMethod != null) {
try {
return mu.readMethod.invoke(layout, null);
} catch(InvocationTargetException e) {
if (e.getTargetException() instanceof InterruptedException
|| e.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
return null;
} catch(IllegalAccessException e) {
return null;
} catch(RuntimeException e) {
return null;
}
}
// If attributeName has not been recognized throw an AttributeNotFoundException
throw(new AttributeNotFoundException("Cannot find " + attributeName +
" attribute in " + dClassName));
}
public
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
// Check attribute is not null to avoid NullPointerException later on
if (attribute == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute cannot be null"),
"Cannot invoke a setter of " + dClassName +
" with null attribute");
}
String name = attribute.getName();
Object value = attribute.getValue();
if (name == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"),
"Cannot invoke the setter of "+dClassName+
" with null attribute name");
}
MethodUnion mu = (MethodUnion) dynamicProps.get(name);
if(mu != null && mu.writeMethod != null) {
Object[] o = new Object[1];
Class[] params = mu.writeMethod.getParameterTypes();
if(params[0] == org.apache.log4j.Priority.class) {
value = OptionConverter.toLevel((String) value,
(Level) getAttribute(name));
}
o[0] = value;
try {
mu.writeMethod.invoke(layout, o);
} catch(InvocationTargetException e) {
if (e.getTargetException() instanceof InterruptedException
|| e.getTargetException() instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
cat.error("FIXME", e);
} catch(IllegalAccessException e) {
cat.error("FIXME", e);
} catch(RuntimeException e) {
cat.error("FIXME", e);
}
} else {
throw(new AttributeNotFoundException("Attribute " + name +
" not found in " +
this.getClass().getName()));
}
}
}

View File

@@ -1,282 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.OptionConverter;
import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;
import java.lang.reflect.Constructor;
import java.util.Enumeration;
import java.util.Vector;
public class LoggerDynamicMBean extends AbstractDynamicMBean
implements NotificationListener {
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
private Vector dAttributes = new Vector();
private String dClassName = this.getClass().getName();
private String dDescription =
"This MBean acts as a management facade for a org.apache.log4j.Logger instance.";
// This Logger instance is for logging.
private static Logger cat = Logger.getLogger(LoggerDynamicMBean.class);
// We wrap this Logger instance.
private Logger logger;
public LoggerDynamicMBean(Logger logger) {
this.logger = logger;
buildDynamicMBeanInfo();
}
public
void handleNotification(Notification notification, Object handback) {
cat.debug("Received notification: "+notification.getType());
registerAppenderMBean((Appender) notification.getUserData() );
}
private
void buildDynamicMBeanInfo() {
Constructor[] constructors = this.getClass().getConstructors();
dConstructors[0] = new MBeanConstructorInfo(
"HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
constructors[0]);
dAttributes.add(new MBeanAttributeInfo("name",
"java.lang.String",
"The name of this Logger.",
true,
false,
false));
dAttributes.add(new MBeanAttributeInfo("priority",
"java.lang.String",
"The priority of this logger.",
true,
true,
false));
MBeanParameterInfo[] params = new MBeanParameterInfo[2];
params[0] = new MBeanParameterInfo("class name", "java.lang.String",
"add an appender to this logger");
params[1] = new MBeanParameterInfo("appender name", "java.lang.String",
"name of the appender");
dOperations[0] = new MBeanOperationInfo("addAppender",
"addAppender(): add an appender",
params,
"void",
MBeanOperationInfo.ACTION);
}
protected
Logger getLogger() {
return logger;
}
public
MBeanInfo getMBeanInfo() {
//cat.debug("getMBeanInfo called.");
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
dAttributes.toArray(attribs);
MBeanInfo mb = new MBeanInfo(dClassName,
dDescription,
attribs,
dConstructors,
dOperations,
new MBeanNotificationInfo[0]);
//cat.debug("getMBeanInfo exit.");
return mb;
}
public
Object invoke(String operationName, Object params[], String signature[])
throws MBeanException,
ReflectionException {
if(operationName.equals("addAppender")) {
addAppender((String) params[0], (String) params[1]);
return "Hello world.";
}
return null;
}
public
Object getAttribute(String attributeName) throws AttributeNotFoundException,
MBeanException,
ReflectionException {
// Check attributeName is not null to avoid NullPointerException later on
if (attributeName == null) {
throw new RuntimeOperationsException(new IllegalArgumentException(
"Attribute name cannot be null"),
"Cannot invoke a getter of " + dClassName + " with null attribute name");
}
// Check for a recognized attributeName and call the corresponding getter
if (attributeName.equals("name")) {
return logger.getName();
} else if(attributeName.equals("priority")) {
Level l = logger.getLevel();
if(l == null) {
return null;
} else {
return l.toString();
}
} else if(attributeName.startsWith("appender=")) {
try {
return new ObjectName("log4j:"+attributeName );
} catch(MalformedObjectNameException e) {
cat.error("Could not create ObjectName" + attributeName);
} catch(RuntimeException e) {
cat.error("Could not create ObjectName" + attributeName);
}
}
// If attributeName has not been recognized throw an AttributeNotFoundException
throw(new AttributeNotFoundException("Cannot find " + attributeName +
" attribute in " + dClassName));
}
void addAppender(String appenderClass, String appenderName) {
cat.debug("addAppender called with "+appenderClass+", "+appenderName);
Appender appender = (Appender)
OptionConverter.instantiateByClassName(appenderClass,
org.apache.log4j.Appender.class,
null);
appender.setName(appenderName);
logger.addAppender(appender);
//appenderMBeanRegistration();
}
public
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
// Check attribute is not null to avoid NullPointerException later on
if (attribute == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute cannot be null"),
"Cannot invoke a setter of " + dClassName +
" with null attribute");
}
String name = attribute.getName();
Object value = attribute.getValue();
if (name == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"),
"Cannot invoke the setter of "+dClassName+
" with null attribute name");
}
if(name.equals("priority")) {
if (value instanceof String) {
String s = (String) value;
Level p = logger.getLevel();
if(s.equalsIgnoreCase("NULL")) {
p = null;
} else {
p = OptionConverter.toLevel(s, p);
}
logger.setLevel(p);
}
} else {
throw(new AttributeNotFoundException("Attribute " + name +
" not found in " +
this.getClass().getName()));
}
}
void appenderMBeanRegistration() {
Enumeration enumeration = logger.getAllAppenders();
while(enumeration.hasMoreElements()) {
Appender appender = (Appender) enumeration.nextElement();
registerAppenderMBean(appender);
}
}
void registerAppenderMBean(Appender appender) {
String name = getAppenderName(appender);
cat.debug("Adding AppenderMBean for appender named "+name);
ObjectName objectName = null;
try {
AppenderDynamicMBean appenderMBean = new AppenderDynamicMBean(appender);
objectName = new ObjectName("log4j", "appender", name);
if (!server.isRegistered(objectName)) {
registerMBean(appenderMBean, objectName);
dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
"The " + name + " appender.", true, true, false));
}
} catch(JMException e) {
cat.error("Could not add appenderMBean for ["+name+"].", e);
} catch(java.beans.IntrospectionException e) {
cat.error("Could not add appenderMBean for ["+name+"].", e);
} catch(RuntimeException e) {
cat.error("Could not add appenderMBean for ["+name+"].", e);
}
}
public
void postRegister(java.lang.Boolean registrationDone) {
appenderMBeanRegistration();
}
}

View File

@@ -1,32 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.jmx;
import java.lang.reflect.Method;
class MethodUnion {
Method readMethod;
Method writeMethod;
MethodUnion( Method readMethod, Method writeMethod) {
this.readMethod = readMethod;
this.writeMethod = writeMethod;
}
}

View File

@@ -1,24 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<body>
This package lets you manage log4j settings using JMX. It is
unfortunately not of production quality.
</body>
</html>

View File

@@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
/**
* <code>AppenderFinalizer</code> has a single method that will finalize
* resources associated with a <code>LogBrokerMonitor</code> in the event
* that the <code>LF5Appender</code> class is destroyed, and the class loader
* is garbage collected.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class AppenderFinalizer {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
protected LogBrokerMonitor _defaultMonitor = null;
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public AppenderFinalizer(LogBrokerMonitor defaultMonitor) {
_defaultMonitor = defaultMonitor;
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
/**
* @throws java.lang.Throwable
*/
protected void finalize() throws Throwable {
System.out.println("Disposing of the default LogBrokerMonitor instance");
_defaultMonitor.dispose();
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,113 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.Configurator;
import org.apache.log4j.spi.LoggerRepository;
import java.io.IOException;
import java.net.URL;
/**
* The <code>DefaultLF5Configurator</code> provides a default
* configuration for the <code>LF5Appender</code>.
*
* Note: The preferred method for configuring a <code>LF5Appender</code>
* is to use the <code>LF5Manager</code> class. This class ensures
* that configuration does not occur multiple times, and improves system
* performance. Reconfiguring the monitor multiple times can result in
* unexpected behavior.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class DefaultLF5Configurator implements Configurator {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
/**
* This class should never be instantiated! It implements the <code>
* Configurator</code>
* interface, but does not provide the same functionality as full
* configurator class.
*/
private DefaultLF5Configurator() {
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* This method configures the <code>LF5Appender</code> using a
* default configuration file. The default configuration file is
* <bold>defaultconfig.properties</bold>.
* @throws java.io.IOException
*/
public static void configure() throws IOException {
String resource =
"/org/apache/log4j/lf5/config/defaultconfig.properties";
URL configFileResource =
DefaultLF5Configurator.class.getResource(resource);
if (configFileResource != null) {
PropertyConfigurator.configure(configFileResource);
} else {
throw new IOException("Error: Unable to open the resource" +
resource);
}
}
/**
* This is a dummy method that will throw an
* <code>IllegalStateException</code> if used.
*/
public void doConfigure(URL configURL, LoggerRepository repository) {
throw new IllegalStateException("This class should NOT be" +
" instantiated!");
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,266 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import java.awt.Toolkit;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.LoggingEvent;
/**
* <code>LF5Appender</code> logs events to a swing based logging
* console. The swing console supports turning categories on and off,
* multiple detail level views, as well as full text searching and many
* other capabilties.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class LF5Appender extends AppenderSkeleton {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
protected LogBrokerMonitor _logMonitor;
protected static LogBrokerMonitor _defaultLogMonitor;
protected static AppenderFinalizer _finalizer;
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
/**
* Constructs a <code>LF5Appender</code> using the default instance of
* the <code>LogBrokerMonitor</code>. This constructor should <bold>always
* </bold> be preferred over the
* <code>LF5Appender(LogBrokerMonitor monitor)</code>
* constructor, unless you need to spawn additional log monitoring
* windows.
*/
public LF5Appender() {
this(getDefaultInstance());
}
/**
* Constructs a <code>LF5Appender<code> using an instance of
* a <code>LogBrokerMonitor<code> supplied by the user. This
* constructor should only be used when you need to spawn
* additional log monitoring windows.
*
* @param monitor An instance of a <code>LogBrokerMonitor<code>
* created by the user.
*/
public LF5Appender(LogBrokerMonitor monitor) {
if (monitor != null) {
_logMonitor = monitor;
}
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* Appends a <code>LoggingEvent</code> record to the
* <code>LF5Appender</code>.
* @param event The <code>LoggingEvent</code>
* to be appended.
*/
public void append(LoggingEvent event) {
// Retrieve the information from the log4j LoggingEvent.
String category = event.getLoggerName();
String logMessage = event.getRenderedMessage();
String nestedDiagnosticContext = event.getNDC();
String threadDescription = event.getThreadName();
String level = event.getLevel().toString();
long time = event.timeStamp;
LocationInfo locationInfo = event.getLocationInformation();
// Add the logging event information to a LogRecord
Log4JLogRecord record = new Log4JLogRecord();
record.setCategory(category);
record.setMessage(logMessage);
record.setLocation(locationInfo.fullInfo);
record.setMillis(time);
record.setThreadDescription(threadDescription);
if (nestedDiagnosticContext != null) {
record.setNDC(nestedDiagnosticContext);
} else {
record.setNDC("");
}
if (event.getThrowableInformation() != null) {
record.setThrownStackTrace(event.getThrowableInformation());
}
try {
record.setLevel(LogLevel.valueOf(level));
} catch (LogLevelFormatException e) {
// If the priority level doesn't match one of the predefined
// log levels, then set the level to warning.
record.setLevel(LogLevel.WARN);
}
if (_logMonitor != null) {
_logMonitor.addMessage(record);
}
}
/**
* This method is an empty implementation of the close() method inherited
* from the <code>org.apache.log4j.Appender</code> interface.
*/
public void close() {
}
/**
* Returns a value that indicates whether this appender requires a
* <code>Layout</code>. This method always returns false.
* No layout is required for the <code>LF5Appender</code>.
*/
public boolean requiresLayout() {
return false;
}
/**
* This method is used to set the property that controls whether
* the <code>LogBrokerMonitor</code> is hidden or closed when a user
* exits
* the monitor. By default, the <code>LogBrokerMonitor</code> will hide
* itself when the log window is exited, and the swing thread will
* continue to running in the background. If this property is
* set to true, the <code>LogBrokerMonitor</code> will call System.exit(0)
* and will shut down swing thread and the virtual machine.
*
* @param callSystemExitOnClose A boolean value indicating whether
* to call System.exit(0) when closing the log window.
*/
public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
_logMonitor.setCallSystemExitOnClose(callSystemExitOnClose);
}
/**
* The equals method compares two LF5Appenders and determines whether
* they are equal. Two <code>Appenders</code> will be considered equal
* if, and only if, they both contain references to the same <code>
* LogBrokerMonitor</code>.
*
* @param compareTo A boolean value indicating whether
* the two LF5Appenders are equal.
*/
public boolean equals(LF5Appender compareTo) {
// If both reference the same LogBrokerMonitor, they are equal.
return _logMonitor == compareTo.getLogBrokerMonitor();
}
public LogBrokerMonitor getLogBrokerMonitor() {
return _logMonitor;
}
public static void main(String[] args) {
new LF5Appender();
}
public void setMaxNumberOfRecords(int maxNumberOfRecords) {
_defaultLogMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
/**
* @return The default instance of the <code>LogBrokerMonitor</code>.
*/
protected static synchronized LogBrokerMonitor getDefaultInstance() {
if (_defaultLogMonitor == null) {
try {
_defaultLogMonitor =
new LogBrokerMonitor(LogLevel.getLog4JLevels());
_finalizer = new AppenderFinalizer(_defaultLogMonitor);
_defaultLogMonitor.setFrameSize(getDefaultMonitorWidth(),
getDefaultMonitorHeight());
_defaultLogMonitor.setFontSize(12);
_defaultLogMonitor.show();
} catch (SecurityException e) {
_defaultLogMonitor = null;
}
}
return _defaultLogMonitor;
}
/**
* @return the screen width from Toolkit.getScreenSize()
* if possible, otherwise returns 800
* @see java.awt.Toolkit
*/
protected static int getScreenWidth() {
try {
return Toolkit.getDefaultToolkit().getScreenSize().width;
} catch (Throwable t) {
return 800;
}
}
/**
* @return the screen height from Toolkit.getScreenSize()
* if possible, otherwise returns 600
* @see java.awt.Toolkit
*/
protected static int getScreenHeight() {
try {
return Toolkit.getDefaultToolkit().getScreenSize().height;
} catch (Throwable t) {
return 600;
}
}
protected static int getDefaultMonitorWidth() {
return (3 * getScreenWidth()) / 4;
}
protected static int getDefaultMonitorHeight() {
return (3 * getScreenHeight()) / 4;
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,116 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import org.apache.log4j.spi.ThrowableInformation;
/**
* A <code>Log4JLogRecord</code> encapsulates
* the details of your log4j <code>LoggingEvent</code> in a format usable
* by the <code>LogBrokerMonitor</code>.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class Log4JLogRecord extends LogRecord {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
/**
* Constructs an instance of a <code>Log4JLogRecord</code>.
*/
public Log4JLogRecord() {
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* Determines which <code>Priority</code> levels will
* be displayed in colored font when the <code>LogMonitorAppender</code>
* renders this log message. By default, messages will be colored
* red if they are of <code>Priority</code> ERROR or FATAL.
*
* @return true if the log level is ERROR or FATAL.
*/
public boolean isSevereLevel() {
boolean isSevere = false;
if (LogLevel.ERROR.equals(getLevel()) ||
LogLevel.FATAL.equals(getLevel())) {
isSevere = true;
}
return isSevere;
}
/**
* Set stack trace information associated with this Log4JLogRecord.
* When this method is called, the stack trace in a
* String-based format is made
* available via the getThrownStackTrace() method.
*
* @param throwableInfo An org.apache.log4j.spi.ThrowableInformation to
* associate with this Log4JLogRecord.
* @see #getThrownStackTrace()
*/
public void setThrownStackTrace(ThrowableInformation throwableInfo) {
String[] stackTraceArray = throwableInfo.getThrowableStrRep();
StringBuffer stackTrace = new StringBuffer();
String nextLine;
for (int i = 0; i < stackTraceArray.length; i++) {
nextLine = stackTraceArray[i] + "\n";
stackTrace.append(nextLine);
}
_thrownStackTrace = stackTrace.toString();
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,278 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import java.awt.Color;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* The LogLevel class defines a set of standard logging levels.
*
* The logging Level objects are ordered and are specified by ordered
* integers. Enabling logging at a given level also enables logging at all
* higher levels.
*
* @author Michael J. Sikorsky
* @author Robert Shaw
* @author Brent Sprecher
* @author Richard Hurst
* @author Brad Marlborough
*/
// Contributed by ThoughtWorks Inc.
public class LogLevel implements java.io.Serializable {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
// log4j log levels.
public final static LogLevel FATAL = new LogLevel("FATAL", 0);
public final static LogLevel ERROR = new LogLevel("ERROR", 1);
public final static LogLevel WARN = new LogLevel("WARN", 2);
public final static LogLevel INFO = new LogLevel("INFO", 3);
public final static LogLevel DEBUG = new LogLevel("DEBUG", 4);
// jdk1.4 log levels NOTE: also includes INFO
public final static LogLevel SEVERE = new LogLevel("SEVERE", 1);
public final static LogLevel WARNING = new LogLevel("WARNING", 2);
public final static LogLevel CONFIG = new LogLevel("CONFIG", 4);
public final static LogLevel FINE = new LogLevel("FINE", 5);
public final static LogLevel FINER = new LogLevel("FINER", 6);
public final static LogLevel FINEST = new LogLevel("FINEST", 7);
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
protected String _label;
protected int _precedence;
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static LogLevel[] _log4JLevels;
private static LogLevel[] _jdk14Levels;
private static LogLevel[] _allDefaultLevels;
private static Map _logLevelMap;
private static Map _logLevelColorMap;
private static Map _registeredLogLevelMap = new HashMap();
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
static {
_log4JLevels = new LogLevel[]{FATAL, ERROR, WARN, INFO, DEBUG};
_jdk14Levels = new LogLevel[]{SEVERE, WARNING, INFO,
CONFIG, FINE, FINER, FINEST};
_allDefaultLevels = new LogLevel[]{FATAL, ERROR, WARN, INFO, DEBUG,
SEVERE, WARNING, CONFIG, FINE, FINER, FINEST};
_logLevelMap = new HashMap();
for (int i = 0; i < _allDefaultLevels.length; i++) {
_logLevelMap.put(_allDefaultLevels[i].getLabel(), _allDefaultLevels[i]);
}
// prepopulate map with levels and text color of black
_logLevelColorMap = new HashMap();
for (int i = 0; i < _allDefaultLevels.length; i++) {
_logLevelColorMap.put(_allDefaultLevels[i], Color.black);
}
}
public LogLevel(String label, int precedence) {
_label = label;
_precedence = precedence;
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* Return the Label of the LogLevel.
*/
public String getLabel() {
return _label;
}
/**
* Returns true if the level supplied is encompassed by this level.
* For example, LogLevel.SEVERE encompasses no other LogLevels and
* LogLevel.FINE encompasses all other LogLevels. By definition,
* a LogLevel encompasses itself.
*/
public boolean encompasses(LogLevel level) {
if (level.getPrecedence() <= getPrecedence()) {
return true;
}
return false;
}
/**
* Convert a log level label into a LogLevel object.
*
* @param level The label of a level to be converted into a LogLevel.
* @return LogLevel The LogLevel with a label equal to level.
* @throws LogLevelFormatException Is thrown when the level can not be
* converted into a LogLevel.
*/
public static LogLevel valueOf(String level)
throws LogLevelFormatException {
LogLevel logLevel = null;
if (level != null) {
level = level.trim().toUpperCase();
logLevel = (LogLevel) _logLevelMap.get(level);
}
// Didn't match, Check for registered LogLevels
if (logLevel == null && _registeredLogLevelMap.size() > 0) {
logLevel = (LogLevel) _registeredLogLevelMap.get(level);
}
if (logLevel == null) {
StringBuffer buf = new StringBuffer();
buf.append("Error while trying to parse (" + level + ") into");
buf.append(" a LogLevel.");
throw new LogLevelFormatException(buf.toString());
}
return logLevel;
}
/**
* Registers a used defined LogLevel.
*
* @param logLevel The log level to be registered. Cannot be a default LogLevel
* @return LogLevel The replaced log level.
*/
public static LogLevel register(LogLevel logLevel) {
if (logLevel == null) return null;
// ensure that this is not a default log level
if (_logLevelMap.get(logLevel.getLabel()) == null) {
return (LogLevel) _registeredLogLevelMap.put(logLevel.getLabel(), logLevel);
}
return null;
}
public static void register(LogLevel[] logLevels) {
if (logLevels != null) {
for (int i = 0; i < logLevels.length; i++) {
register(logLevels[i]);
}
}
}
public static void register(List logLevels) {
if (logLevels != null) {
Iterator it = logLevels.iterator();
while (it.hasNext()) {
register((LogLevel) it.next());
}
}
}
public boolean equals(Object o) {
boolean equals = false;
if (o instanceof LogLevel) {
if (this.getPrecedence() ==
((LogLevel) o).getPrecedence()) {
equals = true;
}
}
return equals;
}
public int hashCode() {
return _label.hashCode();
}
public String toString() {
return _label;
}
// set a text color for a specific log level
public void setLogLevelColorMap(LogLevel level, Color color) {
// remove the old entry
_logLevelColorMap.remove(level);
// add the new color entry
if (color == null) {
color = Color.black;
}
_logLevelColorMap.put(level, color);
}
public static void resetLogLevelColorMap() {
// empty the map
_logLevelColorMap.clear();
// repopulate map and reset text color black
for (int i = 0; i < _allDefaultLevels.length; i++) {
_logLevelColorMap.put(_allDefaultLevels[i], Color.black);
}
}
/**
* @return A <code>List</code> of <code>LogLevel</code> objects that map
* to log4j <code>Priority</code> objects.
*/
public static List getLog4JLevels() {
return Arrays.asList(_log4JLevels);
}
public static List getJdk14Levels() {
return Arrays.asList(_jdk14Levels);
}
public static List getAllDefaultLevels() {
return Arrays.asList(_allDefaultLevels);
}
public static Map getLogLevelColorMap() {
return _logLevelColorMap;
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
protected int getPrecedence() {
return _precedence;
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,73 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
/**
* Thrown to indicate that the client has attempted to convert a string
* to one the LogLevel types, but the string does not have the appropriate
* format.
*
* @author Michael J. Sikorsky<
* @author Robert Shaw
*/
// Contributed by ThoughtWorks Inc.
public class LogLevelFormatException extends Exception {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public LogLevelFormatException(String message) {
super(message);
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,395 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* LogRecord. A LogRecord encapsulates the details of your desired log
* request.
*
* @author Michael J. Sikorsky
* @author Robert Shaw
*/
// Contributed by ThoughtWorks Inc.
public abstract class LogRecord implements java.io.Serializable {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
protected static long _seqCount = 0;
protected LogLevel _level;
protected String _message;
protected long _sequenceNumber;
protected long _millis;
protected String _category;
protected String _thread;
protected String _thrownStackTrace;
protected Throwable _thrown;
protected String _ndc;
protected String _location;
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public LogRecord() {
super();
_millis = System.currentTimeMillis();
_category = "Debug";
_message = "";
_level = LogLevel.INFO;
_sequenceNumber = getNextId();
_thread = Thread.currentThread().toString();
_ndc = "";
_location = "";
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* Get the level of this LogRecord.
*
* @return The LogLevel of this record.
* @see #setLevel(LogLevel)
* @see LogLevel
*/
public LogLevel getLevel() {
return (_level);
}
/**
* Set the level of this LogRecord.
*
* @param level The LogLevel for this record.
* @see #getLevel()
* @see LogLevel
*/
public void setLevel(LogLevel level) {
_level = level;
}
/**
* Abstract method. Must be overridden to indicate what log level
* to show in red.
*/
public abstract boolean isSevereLevel();
/**
* @return true if getThrown().toString() is a non-empty string.
*/
public boolean hasThrown() {
Throwable thrown = getThrown();
if (thrown == null) {
return false;
}
String thrownString = thrown.toString();
return thrownString != null && thrownString.trim().length() != 0;
}
/**
* @return true if isSevereLevel() or hasThrown() returns true.
*/
public boolean isFatal() {
return isSevereLevel() || hasThrown();
}
/**
* Get the category asscociated with this LogRecord. For a more detailed
* description of what a category is see setCategory().
*
* @return The category of this record.
* @see #setCategory(String)
*/
public String getCategory() {
return (_category);
}
/**
* Set the category associated with this LogRecord. A category represents
* a hierarchical dot (".") separated namespace for messages.
* The definition of a category is application specific, but a common convention
* is as follows:
*
* <p>
* When logging messages
* for a particluar class you can use its class name:
* com.thoughtworks.framework.servlet.ServletServiceBroker.<br><br>
* Futhermore, to log a message for a particular method in a class
* add the method name:
* com.thoughtworks.framework.servlet.ServletServiceBroker.init().
* </p>
*
* @param category The category for this record.
* @see #getCategory()
*/
public void setCategory(String category) {
_category = category;
}
/**
* Get the message asscociated with this LogRecord.
*
* @return The message of this record.
* @see #setMessage(String)
*/
public String getMessage() {
return (_message);
}
/**
* Set the message associated with this LogRecord.
*
* @param message The message for this record.
* @see #getMessage()
*/
public void setMessage(String message) {
_message = message;
}
/**
* Get the sequence number associated with this LogRecord. Sequence numbers
* are generally assigned when a LogRecord is constructed. Sequence numbers
* start at 0 and increase with each newly constructed LogRocord.
*
* @return The sequence number of this record.
* @see #setSequenceNumber(long)
*/
public long getSequenceNumber() {
return (_sequenceNumber);
}
/**
* Set the sequence number assocsiated with this LogRecord. A sequence number
* will automatically be assigned to evey newly constructed LogRecord, however,
* this method can override the value.
*
* @param number The sequence number.
* @see #getSequenceNumber()
*/
public void setSequenceNumber(long number) {
_sequenceNumber = number;
}
/**
* Get the event time of this record in milliseconds from 1970.
* When a LogRecord is constructed the event time is set but may be
* overridden by calling setMillis();
*
* @return The event time of this record in milliseconds from 1970.
* @see #setMillis(long)
*/
public long getMillis() {
return _millis;
}
/**
* Set the event time of this record. When a LogRecord is constructed
* the event time is set but may be overridden by calling this method.
*
* @param millis The time in milliseconds from 1970.
* @see #getMillis()
*/
public void setMillis(long millis) {
_millis = millis;
}
/**
* Get the thread description asscociated with this LogRecord. When a
* LogRecord is constructed, the thread description is set by calling:
* Thread.currentThread().toString(). You may supply a thread description
* of your own by calling the setThreadDescription(String) method.
*
* @return The thread description of this record.
* @see #setThreadDescription(String)
*/
public String getThreadDescription() {
return (_thread);
}
/**
* Set the thread description associated with this LogRecord. When a
* LogRecord is constructed, the thread description is set by calling:
* Thread.currentThread().toString(). You may supply a thread description
* of your own by calling this method.
*
* @param threadDescription The description of the thread for this record.
* @see #getThreadDescription()
*/
public void setThreadDescription(String threadDescription) {
_thread = threadDescription;
}
/**
* Get the stack trace in a String-based format for the associated Throwable
* of this LogRecord. The stack trace in a String-based format is set
* when the setThrown(Throwable) method is called.
*
* <p>
* Why do we need this method considering that we
* have the getThrown() and setThrown() methods?
* A Throwable object may not be serializable, however, a String representation
* of it is. Users of LogRecords should generally call this method over
* getThrown() for the reasons of serialization.
* </p>
*
* @return The Stack Trace for the asscoiated Throwable of this LogRecord.
* @see #setThrown(Throwable)
* @see #getThrown()
*/
public String getThrownStackTrace() {
return (_thrownStackTrace);
}
/**
* Set the ThrownStackTrace for the log record.
*
* @param trace A String to associate with this LogRecord
* @see #getThrownStackTrace()
*/
public void setThrownStackTrace(String trace) {
_thrownStackTrace = trace;
}
/**
* Get the Throwable associated with this LogRecord.
*
* @return The LogLevel of this record.
* @see #setThrown(Throwable)
* @see #getThrownStackTrace()
*/
public Throwable getThrown() {
return (_thrown);
}
/**
* Set the Throwable associated with this LogRecord. When this method
* is called, the stack trace in a String-based format is made
* available via the getThrownStackTrace() method.
*
* @param thrown A Throwable to associate with this LogRecord.
* @see #getThrown()
* @see #getThrownStackTrace()
*/
public void setThrown(Throwable thrown) {
if (thrown == null) {
return;
}
_thrown = thrown;
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
thrown.printStackTrace(out);
out.flush();
_thrownStackTrace = sw.toString();
try {
out.close();
sw.close();
} catch (IOException e) {
// Do nothing, this should not happen as it is StringWriter.
}
out = null;
sw = null;
}
/**
* Return a String representation of this LogRecord.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("LogRecord: [" + _level + ", " + _message + "]");
return (buf.toString());
}
/**
* Get the NDC (nested diagnostic context) for this record.
*
* @return The string representing the NDC.
*/
public String getNDC() {
return _ndc;
}
/**
* Set the NDC (nested diagnostic context) for this record.
*
* @param ndc A string representing the NDC.
*/
public void setNDC(String ndc) {
_ndc = ndc;
}
/**
* Get the location in code where this LogRecord originated.
*
* @return The string containing the location information.
*/
public String getLocation() {
return _location;
}
/**
* Set the location in code where this LogRecord originated.
*
* @param location A string containing location information.
*/
public void setLocation(String location) {
_location = location;
}
/**
* Resets that sequence number to 0.
*
*/
public static synchronized void resetSequenceNumber() {
_seqCount = 0;
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
protected static synchronized long getNextId() {
_seqCount++;
return _seqCount;
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,46 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
/**
* An interface for classes which filters LogRecords. Implementations
* represent a rule or condition which LogRecords may pass or fail.
* @see LogRecord
*
* @author Richard Wan
*/
// Contributed by ThoughtWorks Inc.
public interface LogRecordFilter {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* @return true if the specified LogRecord satisfies whatever condition
* implementing class tests for.
*/
public boolean passes(LogRecord record);
}

View File

@@ -1,74 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
/**
* An implementation of LogRecordFilter which always returns true.
*
* @author Richard Wan
*/
// Contributed by ThoughtWorks Inc.
public class PassingLogRecordFilter implements LogRecordFilter {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* @return true;
*/
public boolean passes(LogRecord record) {
return true;
}
/**
* Does nothing.
*/
public void reset() {
// do nothing
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces
//--------------------------------------------------------------------------
}

View File

@@ -1,81 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5;
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
/**
* Starts an instance of the LogFactor5 console for off-line viewing.
*
* @author Brad Marlborough
* @author Richard Hurst
*/
// Contributed by ThoughtWorks Inc.
public class StartLogFactor5 {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* NetworkClient - starts a an instance of the LogFactor5 console and configures
* the console settings.
*/
public final static void main(String[] args) {
LogBrokerMonitor monitor = new LogBrokerMonitor(
LogLevel.getLog4JLevels());
monitor.setFrameSize(LF5Appender.getDefaultMonitorWidth(),
LF5Appender.getDefaultMonitorHeight());
monitor.setFontSize(12);
monitor.show();
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces
//--------------------------------------------------------------------------
}

View File

@@ -1,114 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5.util;
import org.apache.log4j.lf5.LogLevel;
import org.apache.log4j.lf5.LogRecord;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* <p>A LogRecord to be used with the LogMonitorAdapter</p>
*
* @author Richard Hurst
*/
// Contributed by ThoughtWorks Inc.
public class AdapterLogRecord extends LogRecord {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static LogLevel severeLevel = null;
private static StringWriter sw = new StringWriter();
private static PrintWriter pw = new PrintWriter(sw);
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public AdapterLogRecord() {
super();
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public void setCategory(String category) {
super.setCategory(category);
super.setLocation(getLocationInfo(category));
}
public boolean isSevereLevel() {
if (severeLevel == null) return false;
return severeLevel.equals(getLevel());
}
public static void setSevereLevel(LogLevel level) {
severeLevel = level;
}
public static LogLevel getSevereLevel() {
return severeLevel;
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
protected String getLocationInfo(String category) {
String stackTrace = stackTraceToString(new Throwable());
String line = parseLine(stackTrace, category);
return line;
}
protected String stackTraceToString(Throwable t) {
String s = null;
synchronized (sw) {
t.printStackTrace(pw);
s = sw.toString();
sw.getBuffer().setLength(0);
}
return s;
}
protected String parseLine(String trace, String category) {
int index = trace.indexOf(category);
if (index == -1) return null;
trace = trace.substring(index);
trace = trace.substring(0, trace.indexOf(")") + 1);
return trace;
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces
//--------------------------------------------------------------------------
}

View File

@@ -1,243 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* Date format manager.
* Utility class to help manage consistent date formatting and parsing.
* It may be advantageous to have multiple DateFormatManagers per
* application. For example, one for handling the output (formatting) of
* dates, and another one for handling the input (parsing) of dates.
*
* @author Robert Shaw
* @author Michael J. Sikorsky
*/
// Contributed by ThoughtWorks Inc.
public class DateFormatManager {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private TimeZone _timeZone = null;
private Locale _locale = null;
private String _pattern = null;
private DateFormat _dateFormat = null;
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public DateFormatManager() {
super();
configure();
}
public DateFormatManager(TimeZone timeZone) {
super();
_timeZone = timeZone;
configure();
}
public DateFormatManager(Locale locale) {
super();
_locale = locale;
configure();
}
public DateFormatManager(String pattern) {
super();
_pattern = pattern;
configure();
}
public DateFormatManager(TimeZone timeZone, Locale locale) {
super();
_timeZone = timeZone;
_locale = locale;
configure();
}
public DateFormatManager(TimeZone timeZone, String pattern) {
super();
_timeZone = timeZone;
_pattern = pattern;
configure();
}
public DateFormatManager(Locale locale, String pattern) {
super();
_locale = locale;
_pattern = pattern;
configure();
}
public DateFormatManager(TimeZone timeZone, Locale locale, String pattern) {
super();
_timeZone = timeZone;
_locale = locale;
_pattern = pattern;
configure();
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public synchronized TimeZone getTimeZone() {
if (_timeZone == null) {
return TimeZone.getDefault();
} else {
return _timeZone;
}
}
public synchronized void setTimeZone(TimeZone timeZone) {
_timeZone = timeZone;
configure();
}
public synchronized Locale getLocale() {
if (_locale == null) {
return Locale.getDefault();
} else {
return _locale;
}
}
public synchronized void setLocale(Locale locale) {
_locale = locale;
configure();
}
public synchronized String getPattern() {
return _pattern;
}
/**
* Set the pattern. i.e. "EEEEE, MMMMM d, yyyy hh:mm aaa"
*/
public synchronized void setPattern(String pattern) {
_pattern = pattern;
configure();
}
/**
* This method has been deprecated in favour of getPattern().
* @deprecated Use getPattern().
*/
public synchronized String getOutputFormat() {
return _pattern;
}
/**
* This method has been deprecated in favour of setPattern().
* @deprecated Use setPattern().
*/
public synchronized void setOutputFormat(String pattern) {
_pattern = pattern;
configure();
}
public synchronized DateFormat getDateFormatInstance() {
return _dateFormat;
}
public synchronized void setDateFormatInstance(DateFormat dateFormat) {
_dateFormat = dateFormat;
// No reconfiguration necessary!
}
public String format(Date date) {
return getDateFormatInstance().format(date);
}
public String format(Date date, String pattern) {
DateFormat formatter = null;
formatter = getDateFormatInstance();
if (formatter instanceof SimpleDateFormat) {
formatter = (SimpleDateFormat) (formatter.clone());
((SimpleDateFormat) formatter).applyPattern(pattern);
}
return formatter.format(date);
}
/**
* @throws java.text.ParseException
*/
public Date parse(String date) throws ParseException {
return getDateFormatInstance().parse(date);
}
/**
* @throws java.text.ParseException
*/
public Date parse(String date, String pattern) throws ParseException {
DateFormat formatter = null;
formatter = getDateFormatInstance();
if (formatter instanceof SimpleDateFormat) {
formatter = (SimpleDateFormat) (formatter.clone());
((SimpleDateFormat) formatter).applyPattern(pattern);
}
return formatter.parse(date);
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
private synchronized void configure() {
_dateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.FULL,
DateFormat.FULL,
getLocale());
_dateFormat.setTimeZone(getTimeZone());
if (_pattern != null) {
((SimpleDateFormat) _dateFormat).applyPattern(_pattern);
}
}
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@@ -1,301 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.SwingUtilities;
import org.apache.log4j.lf5.Log4JLogRecord;
import org.apache.log4j.lf5.LogLevel;
import org.apache.log4j.lf5.LogLevelFormatException;
import org.apache.log4j.lf5.LogRecord;
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
import org.apache.log4j.lf5.viewer.LogFactor5ErrorDialog;
import org.apache.log4j.lf5.viewer.LogFactor5LoadingDialog;
/**
* Provides utility methods for input and output streams.
*
* @author Brad Marlborough
* @author Richard Hurst
*/
// Contributed by ThoughtWorks Inc.
public class LogFileParser implements Runnable {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
public static final String RECORD_DELIMITER = "[slf5s.start]";
public static final String ATTRIBUTE_DELIMITER = "[slf5s.";
public static final String DATE_DELIMITER = ATTRIBUTE_DELIMITER + "DATE]";
public static final String THREAD_DELIMITER = ATTRIBUTE_DELIMITER + "THREAD]";
public static final String CATEGORY_DELIMITER = ATTRIBUTE_DELIMITER + "CATEGORY]";
public static final String LOCATION_DELIMITER = ATTRIBUTE_DELIMITER + "LOCATION]";
public static final String MESSAGE_DELIMITER = ATTRIBUTE_DELIMITER + "MESSAGE]";
public static final String PRIORITY_DELIMITER = ATTRIBUTE_DELIMITER + "PRIORITY]";
public static final String NDC_DELIMITER = ATTRIBUTE_DELIMITER + "NDC]";
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static SimpleDateFormat _sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss,S");
private LogBrokerMonitor _monitor;
LogFactor5LoadingDialog _loadDialog;
private InputStream _in = null;
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public LogFileParser(File file) throws IOException,
FileNotFoundException {
this(new FileInputStream(file));
}
public LogFileParser(InputStream stream) throws IOException {
_in = stream;
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* Starts a new thread to parse the log file and create a LogRecord.
* See running().
* @param monitor LogBrokerMonitor
*/
public void parse(LogBrokerMonitor monitor) throws RuntimeException {
_monitor = monitor;
Thread t = new Thread(this);
t.start();
}
/**
* Parses the file and creates new log records and adds the record
* to the monitor.
*/
public void run() {
int index = 0;
int counter = 0;
LogRecord temp;
boolean isLogFile = false;
_loadDialog = new LogFactor5LoadingDialog(
_monitor.getBaseFrame(), "Loading file...");
try {
String logRecords = loadLogFile(_in);
while ((counter = logRecords.indexOf(RECORD_DELIMITER, index)) != -1) {
temp = createLogRecord(logRecords.substring(index, counter));
isLogFile = true;
if (temp != null) {
_monitor.addMessage(temp);
}
index = counter + RECORD_DELIMITER.length();
}
if (index < logRecords.length() && isLogFile) {
temp = createLogRecord(logRecords.substring(index));
if (temp != null) {
_monitor.addMessage(temp);
}
}
if (isLogFile == false) {
throw new RuntimeException("Invalid log file format");
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
destroyDialog();
}
});
} catch (RuntimeException e) {
destroyDialog();
displayError("Error - Invalid log file format.\nPlease see documentation"
+ " on how to load log files.");
} catch (IOException e) {
destroyDialog();
displayError("Error - Unable to load log file!");
}
_in = null;
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
protected void displayError(String message) {
LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
_monitor.getBaseFrame(), message);
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
private void destroyDialog() {
_loadDialog.hide();
_loadDialog.dispose();
}
/**
* Loads a log file from a web server into the LogFactor5 GUI.
*/
private String loadLogFile(InputStream stream) throws IOException {
BufferedInputStream br = new BufferedInputStream(stream);
int count = 0;
int size = br.available();
StringBuffer sb = null;
if (size > 0) {
sb = new StringBuffer(size);
} else {
sb = new StringBuffer(1024);
}
while ((count = br.read()) != -1) {
sb.append((char) count);
}
br.close();
br = null;
return sb.toString();
}
private String parseAttribute(String name, String record) {
int index = record.indexOf(name);
if (index == -1) {
return null;
}
return getAttribute(index, record);
}
private long parseDate(String record) {
try {
String s = parseAttribute(DATE_DELIMITER, record);
if (s == null) {
return 0;
}
Date d = _sdf.parse(s);
return d.getTime();
} catch (ParseException e) {
return 0;
}
}
private LogLevel parsePriority(String record) {
String temp = parseAttribute(PRIORITY_DELIMITER, record);
if (temp != null) {
try {
return LogLevel.valueOf(temp);
} catch (LogLevelFormatException e) {
return LogLevel.DEBUG;
}
}
return LogLevel.DEBUG;
}
private String parseThread(String record) {
return parseAttribute(THREAD_DELIMITER, record);
}
private String parseCategory(String record) {
return parseAttribute(CATEGORY_DELIMITER, record);
}
private String parseLocation(String record) {
return parseAttribute(LOCATION_DELIMITER, record);
}
private String parseMessage(String record) {
return parseAttribute(MESSAGE_DELIMITER, record);
}
private String parseNDC(String record) {
return parseAttribute(NDC_DELIMITER, record);
}
private String parseThrowable(String record) {
return getAttribute(record.length(), record);
}
private LogRecord createLogRecord(String record) {
if (record == null || record.trim().length() == 0) {
return null;
}
LogRecord lr = new Log4JLogRecord();
lr.setMillis(parseDate(record));
lr.setLevel(parsePriority(record));
lr.setCategory(parseCategory(record));
lr.setLocation(parseLocation(record));
lr.setThreadDescription(parseThread(record));
lr.setNDC(parseNDC(record));
lr.setMessage(parseMessage(record));
lr.setThrownStackTrace(parseThrowable(record));
return lr;
}
private String getAttribute(int index, String record) {
int start = record.lastIndexOf(ATTRIBUTE_DELIMITER, index - 1);
if (start == -1) {
return record.substring(0, index);
}
start = record.indexOf("]", start);
return record.substring(start + 1, index).trim();
}
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces
//--------------------------------------------------------------------------
}

View File

@@ -1,289 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5.util;
import java.awt.Toolkit;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.lf5.LogLevel;
import org.apache.log4j.lf5.LogRecord;
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
/**
* <p>LogMonitorAdapter facilitates the usage of the LogMonitor</p>
*
* @author Richard Hurst
*/
// Contributed by ThoughtWorks Inc.
public class LogMonitorAdapter {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
public static final int LOG4J_LOG_LEVELS = 0;
public static final int JDK14_LOG_LEVELS = 1;
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private LogBrokerMonitor _logMonitor;
private LogLevel _defaultLevel = null;
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
private LogMonitorAdapter(List userDefinedLevels) {
super();
// set the default level to be the first entry in the list
_defaultLevel = (LogLevel) userDefinedLevels.get(0);
_logMonitor = new LogBrokerMonitor(userDefinedLevels);
_logMonitor.setFrameSize(getDefaultMonitorWidth(),
getDefaultMonitorHeight());
_logMonitor.setFontSize(12);
_logMonitor.show();
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* <p>Creates an instance of LogMonitorAdapter using the
* log levels inticated by the parameter. Log4J and JDK1.4 both have default
* LogLevels which are set but these levels can be overriden.<p>
*
* @param loglevels An integer representing either Log4J or JDK1.4 logging levels
* @return LogMonitorAdapter
*/
public static LogMonitorAdapter newInstance(int loglevels) {
LogMonitorAdapter adapter;
if (loglevels == JDK14_LOG_LEVELS) {
adapter = newInstance(LogLevel.getJdk14Levels());
adapter.setDefaultLevel(LogLevel.FINEST);
adapter.setSevereLevel(LogLevel.SEVERE);
} else {
adapter = newInstance(LogLevel.getLog4JLevels());
adapter.setDefaultLevel(LogLevel.DEBUG);
adapter.setSevereLevel(LogLevel.FATAL);
}
return adapter;
}
/**
* <p>Creates an instance of LogMonitorAdapter using the specified LogLevels.
* The first LogLevel in the array is used as the default LogLevel unless
* changed using the setDefaultLevel method.<p>
*
* @param userDefined An array of user defined LogLevel objects.
* @return LogMonitorAdapter
*/
public static LogMonitorAdapter newInstance(LogLevel[] userDefined) {
if (userDefined == null) {
return null;
}
return newInstance(Arrays.asList(userDefined));
}
/**
* <p>Creates an instance of LogMonitorAdapter using the specified LogLevels.
* The first LogLevel in the List is used as the default LogLevel unless
* changed using the setDefaultLevel method.<p>
*
* @param userDefinedLevels A list of user defined LogLevel objects.
* @return LogMonitorAdapter
*/
public static LogMonitorAdapter newInstance(List userDefinedLevels) {
return new LogMonitorAdapter(userDefinedLevels);
}
/**
* <p>Adds a LogRecord to the LogMonitor.<p>
*
* @param record The LogRecord object to be logged in the logging monitor.
*/
public void addMessage(LogRecord record) {
_logMonitor.addMessage(record);
}
/**
* <p>Set the maximum number of records to be displayed in the monitor<p>
*
* @param maxNumberOfRecords
*/
public void setMaxNumberOfRecords(int maxNumberOfRecords) {
_logMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
}
/**
* <p>Set the default log level to be used when logging messages without
* specifying a LogLevel.<p>
*
* @param level
*/
public void setDefaultLevel(LogLevel level) {
_defaultLevel = level;
}
/**
* <p>Gets the default LogLevel for the Adapter.<p>
*
* @return LogLevel
*/
public LogLevel getDefaultLevel() {
return _defaultLevel;
}
/**
* <p>Sets the Severe LogLevel.</p>
*
* @param level
*/
public void setSevereLevel(LogLevel level) {
AdapterLogRecord.setSevereLevel(level);
}
/**
* <p>Gets the current Severe LogLevel <p>
*
* @return LogLevel
*/
public LogLevel getSevereLevel() {
return AdapterLogRecord.getSevereLevel();
}
/**
* <p>Log a complete message to the Monitor.<p>
*
* @param category The category to be used
* @param level The log level to apply to the message
* @param message The message
* @param t The throwable content of the message
* @param NDC The NDC really only applies to Log4J and the parameter can
* usually be ignored.
*/
public void log(String category, LogLevel level, String message,
Throwable t, String NDC) {
AdapterLogRecord record = new AdapterLogRecord();
record.setCategory(category);
record.setMessage(message);
record.setNDC(NDC);
record.setThrown(t);
if (level == null) {
record.setLevel(getDefaultLevel());
} else {
record.setLevel(level);
}
addMessage(record);
}
/**
* <p>Log a message to the Monitor and use the default LogLevel.<p>
*
* @param category The category to be used
* @param message The message
*/
public void log(String category, String message) {
log(category, null, message);
}
/**
* <p>Log a message to the Monitor.<p>
*
* @param category The category to be used
* @param level The log level to apply to the message
* @param message The message
* @param NDC
*/
public void log(String category, LogLevel level, String message, String NDC) {
log(category, level, message, null, NDC);
}
/**
* <p>Log a message to the Monitor.<p>
*
* @param category The category to be used
* @param level The log level to apply to the message
* @param message The message
* @param t The throwable content of the message
*/
public void log(String category, LogLevel level, String message,
Throwable t) {
log(category, level, message, t, null);
}
/**
* <p>Log a message to the Monitor.<p>
*
* @param category The category to be used
* @param level The log level to apply to the message
* @param message The message
*/
public void log(String category, LogLevel level, String message) {
log(category, level, message, null, null);
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
/**
* @return the screen width from Toolkit.getScreenSize()
* if possible, otherwise returns 800
* @see java.awt.Toolkit
*/
protected static int getScreenWidth() {
try {
return Toolkit.getDefaultToolkit().getScreenSize().width;
} catch (Throwable t) {
return 800;
}
}
/**
* @return the screen height from Toolkit.getScreenSize()
* if possible, otherwise returns 600
* @see java.awt.Toolkit
*/
protected static int getScreenHeight() {
try {
return Toolkit.getDefaultToolkit().getScreenSize().height;
} catch (Throwable t) {
return 600;
}
}
protected static int getDefaultMonitorWidth() {
return (3 * getScreenWidth()) / 4;
}
protected static int getDefaultMonitorHeight() {
return (3 * getScreenHeight()) / 4;
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces
//--------------------------------------------------------------------------
}

View File

@@ -1,156 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5.util;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
/**
* Resource encapsulates access to Resources via the Classloader.
*
* @author Michael J. Sikorsky
* @author Robert Shaw
*/
// Contributed by ThoughtWorks Inc.
public class Resource {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
protected String _name;
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
/**
* Default, no argument constructor.
*/
public Resource() {
super();
}
/**
* Construct a Resource given a name.
*
* @see #setName(String)
*/
public Resource(String name) {
_name = name;
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
/**
* Set the name of the resource.
* <p>
* A resource is some data (images, audio, text, etc) that can be accessed
* by class code in a way that is independent of the location of the code.
* </p>
* <p>
* The name of a resource is a "/"-separated path name that identifies
* the resource.
* </p>
*
* @see #getName()
*/
public void setName(String name) {
_name = name;
}
/**
* Get the name of the resource. Set setName() for a description of
* a resource.
*
* @see #setName
*/
public String getName() {
return (_name);
}
/**
* Get the InputStream for this Resource. Uses the classloader
* from this Resource.
*
* @see #getInputStreamReader
* @see ResourceUtils
*/
public InputStream getInputStream() {
InputStream in = ResourceUtils.getResourceAsStream(this, this);
return (in);
}
/**
* Get the InputStreamReader for this Resource. Uses the classloader from
* this Resource.
*
* @see #getInputStream
* @see ResourceUtils
*/
public InputStreamReader getInputStreamReader() {
InputStream in = ResourceUtils.getResourceAsStream(this, this);
if (in == null) {
return null;
}
InputStreamReader reader = new InputStreamReader(in);
return reader;
}
/**
* Get the URL of the Resource. Uses the classloader from this Resource.
*
* @see ResourceUtils
*/
public URL getURL() {
return (ResourceUtils.getResourceAsURL(this, this));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

Some files were not shown because too many files have changed in this diff Show More